JFreeChart
JFreeChartは、Javaでグラフを生成・表示するためのライブラリ。
簡単なサンプルを書いてみる。
■準備
jfreechartとjcommonのjarファイルをダウンロードし、クラスパスを設定する。
せっかくなので、freehepとbatikのライブラリも利用する。
■ソースコード
次のようなコードを書いてみる。
CSVファイルで折れ線グラフのXYデータを読み込み、JPG、SVG、WMFを出力する。
package test; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.filechooser.FileFilter; import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.svggen.SVGGraphics2D; import org.apache.batik.svggen.SVGGraphics2DIOException; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.Element; public class JChartTest { private JFrame frame; private ChartPanel chartPanel; private JFileChooser chooser; private FileFilter csv,wmf,svg,jpg; private static final String REG="\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"|([^,]+)|,|"; public JChartTest(){ frame=new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("JChartTest"); frame.setSize(640, 480); initComponents(); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); } private void initComponents(){ chooser=new JFileChooser(); csv=new TmpFileFilter("csv"); svg=new TmpFileFilter("svg"); wmf=new TmpFileFilter("wmf"); jpg=new TmpFileFilter("jpg"); frame.getContentPane().setLayout(new BorderLayout()); frame.setJMenuBar(createJMenuBar()); } private JMenuBar createJMenuBar(){ JMenuBar ret=new JMenuBar(); JMenu file=new JMenu("File"); file.setMnemonic('F'); ret.add(file); JMenuItem open=new JMenuItem("Open"); file.add(open); open.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { chooser.resetChoosableFileFilters(); chooser.setFileFilter(csv); int ret = chooser.showDialog(null, "Open"); if (ret != JFileChooser.APPROVE_OPTION){return;} File file=chooser.getSelectedFile(); try{ double[][] val=parseCsv(file,true); initChart(val,file.getName()); }catch(IOException ie){ ie.printStackTrace(); }catch(NumberFormatException ne){ ne.printStackTrace(); } } }); JMenuItem save=new JMenuItem("Save"); file.add(save); save.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { if(chartPanel==null)return; chooser.resetChoosableFileFilters(); chooser.setFileFilter(svg); chooser.setFileFilter(wmf); chooser.setFileFilter(jpg); int ret = chooser.showDialog(null, "Save"); if (ret != JFileChooser.APPROVE_OPTION){return;} File file=chooser.getSelectedFile(); if(wmf.accept(file)){ Rectangle r=chartPanel.getBounds(); try{ org.freehep.graphics2d.VectorGraphics vg =new org.freehep.graphicsio.emf.EMFGraphics2D( file,new Dimension((int)r.getWidth(),(int)r.getHeight())); vg.startExport(); chartPanel.paintComponent(vg); vg.endExport(); }catch(FileNotFoundException fe){} }else if(svg.accept(file)){ Rectangle r=chartPanel.getBounds(); DOMImplementation domImpl=GenericDOMImplementation.getDOMImplementation(); Document document=domImpl.createDocument(null, "svg", null); SVGGraphics2D svg2d=new SVGGraphics2D(document); svg2d.setBackground(new Color(255,255,255,0)); svg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); chartPanel.paintComponent(svg2d); Element sv=svg2d.getRoot(); sv.setAttribute("xml:space", "preserve"); sv.setAttribute("width", Integer.toString((int)r.getWidth())); sv.setAttribute("height", Integer.toString((int)r.getHeight())); sv.setAttribute("viewBox", Integer.toString((int)r.getX())+" "+ Integer.toString((int)r.getY())+" "+ Integer.toString((int)r.getWidth())+" "+ Integer.toString((int)r.getHeight()) ); try { OutputStream os = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(os); Writer out = new OutputStreamWriter(bos, "UTF-8"); svg2d.stream(sv,out); } catch (UnsupportedEncodingException ue){ ue.printStackTrace(); } catch (SVGGraphics2DIOException se){ se.printStackTrace(); } catch (IOException ioe){ ioe.printStackTrace(); } }else if(jpg.accept(file)){ Rectangle r=chartPanel.getBounds(); BufferedImage buf=new BufferedImage((int)r.getWidth(),(int)r.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d=(Graphics2D)buf.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); chartPanel.paintComponent(g2d); try{ ImageIO.write(buf, "jpg",file); }catch(IOException ie){} } } }); return ret; } public double[][] parseCsv(File f,boolean isExistTitleRow) throws IOException{ BufferedReader reader; reader = new BufferedReader(new FileReader(f)); String[][] str=parse(reader,isExistTitleRow); reader.close(); double[][] val=new double[str.length][str[0].length]; for(int i=0;i<val.length;i++){ for(int j=0;j<val[i].length;j++){ val[i][j]=Double.parseDouble(str[i][j]); } } return val; } private String[][] parse(BufferedReader reader,boolean title) throws IOException{ ArrayList<String[]> list=new ArrayList<String[]>(); Pattern pattern = Pattern.compile(REG); String line; if(title)line=reader.readLine(); while((line=reader.readLine())!=null){ String[] sp=split(pattern,line); list.add(sp); } if(list.size()==0)return new String[0][0]; return list.toArray(new String[list.size()][]); } private String[] split(Pattern pattern,String line){ Matcher matcher=pattern.matcher(line); List<String> list=new ArrayList<String>(); int index=0; int com=0; while(index<line.length()){ if(matcher.find(index+com)){ String s=matcher.group(); index=matcher.end(); list.add(s); com=1; } } return list.toArray(new String[list.size()]); } private void initChart(double[][] val,String name){ XYSeriesCollection dataset=new XYSeriesCollection(); for(int i=1;i<val[0].length;i++){ XYSeries series=new XYSeries("col_"+Integer.toString(i)); for(int j=0;j<val.length;j++){ series.add(val[j][0], val[j][i]); } dataset.addSeries(series); } JFreeChart chart=ChartFactory.createXYLineChart( name,"x","y",dataset,PlotOrientation.VERTICAL,true,false,false); if(chartPanel!=null)frame.getContentPane().remove(chartPanel); chartPanel=new ChartPanel(chart); frame.getContentPane().add(chartPanel,BorderLayout.CENTER); chartPanel.updateUI(); } private class TmpFileFilter extends FileFilter{ String ext; TmpFileFilter(String _ext){ ext=_ext.toLowerCase(); } @Override public boolean accept(File f) { String name=f.getName().toLowerCase(); int id=name.lastIndexOf("."); if(id==-1||id==name.length()-1){ return false; }else{ String ex=name.substring(id+1, name.length()); return ex.equals(ext); } } @Override public String getDescription() { return "*."+ext; } } public static void main(String[] args){ JChartTest ct=new JChartTest(); ct.frame.setVisible(true); } }
■結果
とりあえず、グラフを表示し、JPG、SVG、WMFを出力できた。