生物屋さんのためのゼロからのプログラミング

―忘れないための覚書 (たま~に更新)―

JFreeChartを使って、2種類のグラフ (散布図と折れ線グラフ) を重ねて表示する。

ここでは、データをグラフに表示し、その中で極大値と極小値を表示するプログラムを書く。
ただし、コードを簡潔にするために解析用のデータはRandomで作成し、極大値と極小値の代わりに“5の倍数”と“8の倍数”の点をマークするプログラムを書いた。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Plot extends JFrame implements ActionListener {

	Random rand = new Random();
	int no = 30;

	//解析例用のデータを入れる配列
	int data [] = new int [no];

	//解析用データの作成
	public void makeData (int [] data) {
		System.out.println("解析用のデータ:");
		for (int i = 0; i < data.length; i++) {
			data [i] = rand.nextInt(100) + 1;
			System.out.print(data [i] + " ");
		}
		System.out.println();
	}

	//Fig作成メソッド
	public void MakeFig (int no) {
		JFrame frame = new JFrame("ShowData");
		frame.setBounds(200, 200, 400, 400);
		frame.setVisible(true);

		XYSeriesCollection plot = new XYSeriesCollection ();

                //5の倍数の値をプロット
		XYSeries plot5Series = new XYSeries("Multiple of 5");
		for (int i = 1; i < no ; i++) {
			if (i* 5 >= no) break;
			plot5Series.add(i*5, data[i*5]);
		}

        //8の倍数の値をプロット   
		XYSeries plot8Series = new XYSeries("Multiple of 8");
		for (int i = 1; i < no ; i++) {
			if (i* 8 >= no) break;
			plot8Series.add(i*8, data[i*8]);
		}

		plot.addSeries(plot5Series);
		plot.addSeries(plot8Series);

		JFreeChart chart = ChartFactory.createScatterPlot(
					"Data",  //タイトル
					"Frame",  //x軸のラベル
					"Value",  //y軸のラベル
					plot,     //表示するデータ
					PlotOrientation.VERTICAL,  //値が表す軸がy軸
					true,  //凡例の表示
					false, //ツールチップを作成するか
					false); //URLを作成するか

		XYSeriesCollection rowData = new XYSeriesCollection ();
		XYSeries rowSeries = new XYSeries("Trace");  //折れ線グラフの作成
		for (int i = 0; i < no; i++) {
			rowSeries.add(i, data[i]);
		}
		rowData.addSeries(rowSeries);
		XYPlot linePlot = chart.getXYPlot();
		linePlot.setBackgroundPaint(Color.white); //グラフの背景を白に
		linePlot.setDataset(1, rowData);     
		linePlot.mapDatasetToRangeAxis(1, 0);

		 XYLineAndShapeRenderer render = new XYLineAndShapeRenderer();
	     linePlot.setRenderer(1, render);
	     render.setSeriesPaint(0, ChartColor.BLACK);
	     linePlot.setDatasetRenderingOrder(DatasetRenderingOrder.REVERSE);
	     ChartPanel pane = new ChartPanel(chart);
	      frame.add(pane);
	}

	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();

		if (cmd.equals("button")) {
			makeData(data);
			MakeFig(no);
		}
 	}

	Plot (String title) {
		setTitle(title);
		setSize(180, 80);
		setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

		JButton button = new JButton("Show");
		button.addActionListener (this);
		button.setActionCommand("button");

		JPanel pane = new JPanel();
		pane.add(button);
		getContentPane().add(pane, BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		Plot frame = new Plot("Plot");
		frame.setVisible(true);
	}
}

このプログラムの実行結果例を下記に示す。
f:id:Aki-Miya:20150205084630p:plain

今回のプログラミングではグラフの作成にJFreeChartを使用しているため、本ソースコードを使うにはJFreeChart(JFreeChart)のインストールが必要となる。詳細な利用方法等は他のサイト(JFreeChartを使ったグラフ作成)を参照されたし。


時系列の折れ線グラフの特定のマーカー(極大値や極小値など)のみを標識するために、ここでは時系列折れ線グラフに散布図を重ねることにした。
実際のFig作成メソッドは下記の通り。

	//Fig作成メソッド
	public void MakeFig (int no) {
		JFrame frame = new JFrame("ShowData");
		frame.setBounds(200, 200, 400, 400);
		frame.setVisible(true);

		XYSeriesCollection plot = new XYSeriesCollection ();

		XYSeries plot5Series = new XYSeries("Multiple of 5");
		for (int i = 1; i < no ; i++) {
			if (i* 5 >= no) break;
			plot5Series.add(i*5, data[i*5]);
		}

		XYSeries plot8Series = new XYSeries("Multiple of 8");
		for (int i = 1; i < no ; i++) {
			if (i* 8 >= no) break;
			plot8Series.add(i*8, data[i*8]);
		}

		plot.addSeries(plot5Series);
		plot.addSeries(plot8Series);

		JFreeChart chart = ChartFactory.createScatterPlot(
					"Data",  //タイトル
					"Frame",  //x軸のラベル
					"Value",  //y軸のラベル
					plot,     //表示するデータ
					PlotOrientation.VERTICAL,  //値が表す軸がy軸
					true,  //凡例の表示
					false, //ツールチップを作成するか
					false); //URLを作成するか

		XYSeriesCollection rowData = new XYSeriesCollection ();
		XYSeries rowSeries = new XYSeries("Trace");
		for (int i = 0; i < no; i++) {
			rowSeries.add(i, data[i]);
		}
		rowData.addSeries(rowSeries);
		XYPlot linePlot = chart.getXYPlot();
		linePlot.setBackgroundPaint(Color.white);
		linePlot.setDataset(1, rowData);
		linePlot.mapDatasetToRangeAxis(1, 0);

		 XYLineAndShapeRenderer render = new XYLineAndShapeRenderer();
	     linePlot.setRenderer(1, render);
	     render.setSeriesPaint(0, ChartColor.BLACK);
	     linePlot.setDatasetRenderingOrder(DatasetRenderingOrder.REVERSE);
	     ChartPanel pane = new ChartPanel(chart);
	      frame.add(pane);
	}

本来は元データの時系列折れ線グラフの上に散布図を重ねたかったのだが、知識不足のため散布図を作成後に折れ線グラフを重ねた(おそらく、Scatter plotのrendererの取得に失敗したため)。

JFreeChart chart = ChartFactory.createScatterPlot

この部分で、ScatterPlotを作成している。ここのScattePlotをXYLineChartに変えると時系列折れ線グラフが作成できる。


グラフの線やマーカーを変える場合は、

        render.setShapesVisible(true); //マーカーの表示
        render.setDrawOutlines(true); //マーカーの外枠の表示
        render.setUseFillPaint(true); //マーカーの内を塗りつぶす
        render.setFillPaint(Color.GREEN); //マーカーを塗りつぶす色の指定
        render.setSeriesStroke(0, new BasicStroke(3.0f)); //線を太くする
        render.setSeriesOutlineStroke(0, new BasicStroke(5.0f)); //マーカーの線を太くする。
        render.setSeriesShape(0, new Ellipse2D.Double 
                                (-5.0, -5.0, 10.0, 10.0)); //マーカーの形を指定

などの方法がある。


今回用いた、5の倍数や8の倍数の値の代わりに、極大値、極小値の値を導入することでデータ内の極大値、極小値の位置を可視化できる。

ここまでの方法で、エクセルファイルからデータを読み込み、Peakの検出およびFig作成、解析結果のエクセルファイルへの書き出しが出来るはず。