|
|
JFreeChart を使ったグラフ作成 時系列グラフ(TimeSeriesChart) |
H.Kamifuji . |
時系列グラフの作成に関して確認します。時系列グラフは日時の経過に伴って変化する値をグラフにしたものです。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 に、アップされています。JDK-23 + jfreechart-1.0.19 で、上位互換について、見直しを行っていきます。 |
|
時系列グラフの基本的な作成方法を確認します。 まずChartFactoryクラスの「createTimeSeriesChart」メソッドを使って時系列グラフを扱うJFreeChartクラスのオブジェクトを作成します。 createTimeSeriesChart public static JFreeChart createTimeSeriesChart(java.lang.String title, java.lang.String timeAxisLabel, java.lang.String valueAxisLabel, XYDataset dataset, boolean legend, boolean tooltips, boolean urls)Creates and returns a time series chart. A time series chart is an XYPlot with a DateAxis for the x-axis and a NumberAxis for the y-axis. The default renderer is an XYLineAndShapeRenderer. A convenient dataset to use with this chart is a TimeSeriesCollection. Parameters: title - the chart title (null permitted). timeAxisLabel - a label for the time axis (null permitted). valueAxisLabel - a label for the value axis (null permitted). dataset - the dataset for the chart (null permitted). legend - a flag specifying whether or not a legend is required. tooltips - configure chart to generate tool tips? urls - configure chart to generate URLs? Returns: A time series chart. 1番目の引数にグラフのタイトルを文字列で指定します。 2番目の引数には時間軸のラベルを文字列で指定します。3番目の引数には値が配置される軸のラベルを文字列で指定します。 4番目の引数にはグラフのデータをXYDatasetインターフェースを実装したクラスのオブジェクトで指定します。今回はTimeSeriesCollectionクラスを使います。詳細は次のページで確認します。 5番目の引数には凡例を表示するかどうかを「true」か「false」で指定します。 6番目の引数にはツールチップを作成するかどうかを「true」か「false」で指定します。 7番目の引数にはURLを作成するかどうかを「true」か「false」で指定します。 実際の使い方は次のようになります。 TimeSeriesCollection data = new TimeSeriesCollection(); JFreeChart chart = ChartFactory.createTimeSeriesChart("PV推移", "月", "PV", data, true, false, false);実際のデータの追加方法は次のページで確認します。 では簡単なサンプルを作成して試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 時系列グラフの作成(createTimeSeriesChartメソッド) */ import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartFactory; import org.jfree.data.time.TimeSeriesCollection; import javax.swing.JFrame; import java.awt.BorderLayout; import org.jfree.chart.ChartPanel; public class Test1_1 extends JFrame{ public static void main(String[] args) { Test1_1 frame = new Test1_1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 500, 500); frame.setTitle("グラフサンプル"); frame.setVisible(true); } Test1_1(){ TimeSeriesCollection data = new TimeSeriesCollection(); JFreeChart chart = ChartFactory.createTimeSeriesChart("PV推移", "月", "PV", data, true, false, false); ChartPanel cpanel = new ChartPanel(chart); getContentPane().add(cpanel, BorderLayout.CENTER); } }上記をコンパイルした後で実行すると次のように表示されます。 |
時系列グラフのデータでは系列を作成し個々のデータを系列に登録していきます。そして系列毎にデータを追加していきます。最後に全ての系列を系列コレクションに追加します。 まずは系列コレクションを表すTimeSeriesCollectionクラスのオブジェクトを作成します。 TimeSeriesCollectionクラスのクラス図は次のようになっています。 java.lang.Object | +- org.jfree.data.general.AbstractDataset | +- org.jfree.data.general.AbstractSeriesDataset | +- org.jfree.data.xy.AbstractXYDataset | +- org.jfree.data.xy.AbstractIntervalXYDataset | +- org.jfree.data.time.TimeSeriesCollection public class TimeSeriesCollection extends AbstractIntervalXYDataset implements XYDataset, IntervalXYDataset, DomainInfo, java.io.Serializableコンストラクタは4つ用意されています。デフォルトのコンストラクタは次のようになっています。 TimeSeriesCollection public TimeSeriesCollection()Constructs an empty dataset, tied to the default timezone. 次のようにオブジェクトを作成します。 TimeSeriesCollection data = new TimeSeriesCollection(); 系列の登録系列はTimeSeriesクラスを使います。TimeSeriesクラスは若干複雑なので詳細な使い方については「TimeSeriesクラス」で解説していますので参照して下さい。TimeSeriesクラスのコンストラクタは3つ用意されています。系列名と系列の時間単位を指定するコンストラクタについて見てみます。 TimeSeries public TimeSeries(java.lang.Comparable name, java.lang.Class timePeriodClass)Creates a new (empty) time series with the specified name and class of RegularTimePeriod. Parameters: name - the series name (null not permitted). timePeriodClass - the type of time period (null not permitted). 1番目の引数には系列の名前を指定します。2番目の引数には系列の時間単位を表すクラスを指定します。ここで時間単位とは時、分、日、月などです。時系列グラフは時間の推移に伴う値の変化を表すグラフであり、グラフの時間軸の単位を指定することになります。指定するには「RegularTimePeriod」クラスのサブクラスのいずれかとなりますが、ここでは月を表す「org.jfree.data.time.Month」クラスを使います。 TimeSeriesクラスのオブジェクト作成したらTimeSeriesCollectionクラスで用意されている「addSeries」メソッドを使って系列を追加していきます。 addSeries public void addSeries(TimeSeries series)Adds a series to the collection and sends a DatasetChangeEvent to all registered listeners. Parameters: series - the series (null not permitted). 引数には系列を表す「TimeSeries」クラスをのオブジェクトを指定します。 実際には次のように記述します。 TimeSeriesCollection data = new TimeSeriesCollection(); TimeSeries series = new TimeSeries("Aサイト"); data.addSeries(series);これで系列が作成できました。最後に系列にデータを追加していきます。 データの登録系列にデータを登録するにはTimeSeriesクラスで用意されている「add」メソッドを使います。add public void add(RegularTimePeriod period, java.lang.Number value)Adds a new data item to the series and sends a SeriesChangeEvent to all registered listeners. Parameters: period - the time period (null not permitted). value - the value (null permitted). 1番目の引数には日時を表すTimeSeriesクラスのコンストラクタの2番目の引数で指定した「RegularTimePeriod」クラスのサブクラスのオブジェクトを指定します。今回は「org.jfree.data.time.Month」クラスのオブジェクトを指定します。2番目の引数には値を指定します。 今回は次のようなデータを元にグラフを作成してみます。
実際には次のように記述します。 TimeSeriesCollection data = new TimeSeriesCollection(); TimeSeries series = new TimeSeries("Aサイト", Month.class); series.add(new Month(7, 2007), 120); series.add(new Month(8, 2007), 140); series.add(new Month(9, 2007), 150); series.add(new Month(10, 2007), 190); series.add(new Month(11, 2007), 230); series.add(new Month(12, 2007), 280);今回は系列数が1つで、時系列の単位が月のものとなります。 では簡単なサンプルを作成して試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 時系列グラフのデータ(TimeSeriesCollectionクラス) */ import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartFactory; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.Month; import javax.swing.JFrame; import java.awt.BorderLayout; import org.jfree.chart.ChartPanel; public class Test2_1 extends JFrame{ public static void main(String[] args) { Test2_1 frame = new Test2_1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 500, 500); frame.setTitle("グラフサンプル"); frame.setVisible(true); } Test2_1(){ TimeSeriesCollection data = new TimeSeriesCollection(); TimeSeries series = new TimeSeries("Aサイト", Month.class); series.add(new Month(7, 2007), 120); series.add(new Month(8, 2007), 140); series.add(new Month(9, 2007), 150); series.add(new Month(10, 2007), 190); series.add(new Month(11, 2007), 230); series.add(new Month(12, 2007), 280); data.addSeries(series); JFreeChart chart = ChartFactory.createTimeSeriesChart("PV推移", "月", "PV", data, true, false, false); ChartPanel cpanel = new ChartPanel(chart); getContentPane().add(cpanel, BorderLayout.CENTER); } }上記をコンパイルした後で実行すると次のように表示されます。 コンパイル時に、下記の警告が発生します。 [xxxxxxxx@dddddddddd TimeSeriesChart]$ javac Test2_1.java 注意:Test2_1.javaは非推奨のAPIを使用またはオーバーライドしています。 注意:詳細は、-Xlint:deprecationオプションを指定して再コンパイルしてください。 [xxxxxxxx@dddddddddd TimeSeriesChart]$ [xxxxxxxx@dddddddddd TimeSeriesChart]$ javac -Xlint:deprecation Test2_1.java Test2_1.java:27: 警告: [deprecation] TimeSeriesのTimeSeries(Comparable,Class)は非推奨になりました TimeSeries series = new TimeSeries("Aサイト", Month.class); ^ 警告1個 [xxxxxxxx@dddddddddd TimeSeriesChart]$ |
時系列グラフの場合は複数の系列のデータを扱うことが可能です。 ここでは例として次のようなデータを元にグラフを作成します。
時系列グラフの場合には系列毎にTimeSeriesクラスのオブジェクトを作成しTimeSeriesCollectionクラスのオブジェクトに追加します。 TimeSeriesCollection data = new TimeSeriesCollection(); TimeSeries series1 = new TimeSeries("Aサイト", Month.class); TimeSeries series2 = new TimeSeries("Bサイト", Month.class); TimeSeries series3 = new TimeSeries("Cサイト", Month.class); data.addSeries(series1); data.addSeries(series2); data.addSeries(series3);そして各系列毎にデータをTimeSeriesクラスのオブジェクトに追加していきます。 実際には次のように記述します。 TimeSeriesCollection data = new TimeSeriesCollection(); Month[] month = new Month[6]; month[0] = new Month(7, 2007); month[1] = new Month(8, 2007); month[2] = new Month(9, 2007); month[3] = new Month(10, 2007); month[4] = new Month(11, 2007); month[5] = new Month(12, 2007); TimeSeries series1 = new TimeSeries("Aサイト", Month.class); series1.add(month[0], 120); series1.add(month[1], 140); series1.add(month[2], 150); series1.add(month[3], 190); series1.add(month[4], 230); series1.add(month[5], 280); TimeSeries series2 = new TimeSeries("Bサイト", Month.class); series2.add(month[0], 400); series2.add(month[1], 380); series2.add(month[2], 410); series2.add(month[3], 200); series2.add(month[4], 150); series2.add(month[5], 80); TimeSeries series3 = new TimeSeries("Cサイト", Month.class); series3.add(month[0], 150); series3.add(month[1], 170); series3.add(month[2], 160); series3.add(month[3], 180); series3.add(month[4], 150); series3.add(month[5], 170); data.addSeries(series1); data.addSeries(series2); data.addSeries(series3);今回は系列数が3つで、時系列の単位が月のものとなります。 では簡単なサンプルを作成して試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 複数の系列のデータ */ import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartFactory; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.Month; import javax.swing.JFrame; import java.awt.BorderLayout; import org.jfree.chart.ChartPanel; public class Test3_1 extends JFrame{ public static void main(String[] args) { Test3_1 frame = new Test3_1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 500, 500); frame.setTitle("グラフサンプル"); frame.setVisible(true); } Test3_1(){ JFreeChart chart = ChartFactory.createTimeSeriesChart("PV推移", "月", "PV", createData(), true, false, false); ChartPanel cpanel = new ChartPanel(chart); getContentPane().add(cpanel, BorderLayout.CENTER); } private TimeSeriesCollection createData(){ TimeSeriesCollection data = new TimeSeriesCollection(); Month[] month = new Month[6]; for (int i = 0 ; i < 6 ; i++){ month[i] = new Month(i + 7, 2007); } int graphdata[][] = {{120, 140, 150, 190, 230, 280}, /* Aサイト */ {400, 380, 410, 200, 150, 80}, /* Bサイト */ {150, 170, 160, 180, 150, 170}}; /* Cサイト */ TimeSeries[] series = new TimeSeries[3]; series[0] = new TimeSeries("Aサイト", Month.class); series[1] = new TimeSeries("Bサイト", Month.class); series[2] = new TimeSeries("Cサイト", Month.class); for (int i = 0 ; i < 3 ; i++){ for (int j = 0 ; j < 6 ; j++){ series[i].add(month[j], graphdata[i][j]); } data.addSeries(series[i]); } return data; } }上記をコンパイルした後で実行すると次のように表示されます。 |
グラフの描画領域を取得し、描画領域に対する設定を行っていきます。ファクトリメソッドを使ってJFreeChartクラスのオブジェクトを作成した場合は、JFreeChartクラスで用意されている「getPlot」メソッドを使ってPlotクラスのオブジェクトを取得します。 getPlot public Plot getPlot()Returns the plot for the chart. The plot is a class responsible for coordinating the visual representation of the data, including the axes (if any). Returns: The plot. 時系列グラフの場合には、取得したPlotクラスのオブジェクトを、PlotクラスのサブクラスであるXYPlotクラスにキャストして取得して使います。例えば次のように記述します。 JFreeChart chart = ChartFactory.createTimeSeriesChart(...); /* 引数は省略 */ XYPlot plot = (XYPlot)chart.getPlot();ではXYPlotクラスについて確認します。 XYPlotクラスXYPlotクラスのクラス図は次のようになっています。java.lang.Object | +-- org.jfree.chart.plot.Plot | +-- org.jfree.chart.plot.XYPlot public class XYPlot extends Plot implements ValueAxisPlot, Zoomable, RendererChangeListener, java.lang.Cloneable, org.jfree.util.PublicCloneable, java.io.Serializable用意されているコンストラクタは次の2つです。
今回はコンストラクタでオブジェクトを直接生成するのではなく、JFreeChartクラスの「getPlot」メソッドでオブジェクトを取得します。 取得したXYPlotクラスのオブジェクトは時系列グラフの描画領域を表すオブジェクトです。XYPlotクラスで定義されているメソッドや、親クラスのPlotクラスで用意されているメソッドを使用して描画領域に対する設定を行うことが可能です。 では簡単なサンプルを作成して試してみます。 サンプルプログラム下記のサンプルを実行してみよう。/** * 時系列グラフの描画領域(XYPlotクラス) */ import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartFactory; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.Month; import javax.swing.JFrame; import java.awt.BorderLayout; import org.jfree.chart.ChartPanel; import org.jfree.chart.plot.XYPlot; import java.awt.Color; public class Test4_1 extends JFrame{ public static void main(String[] args) { Test4_1 frame = new Test4_1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 500, 500); frame.setTitle("グラフサンプル"); frame.setVisible(true); } Test4_1(){ JFreeChart chart = ChartFactory.createTimeSeriesChart("PV推移", "月", "PV", createData(), true, false, false); XYPlot plot = (XYPlot)chart.getPlot(); plot.setBackgroundPaint(Color.ORANGE); ChartPanel cpanel = new ChartPanel(chart); getContentPane().add(cpanel, BorderLayout.CENTER); } private TimeSeriesCollection createData(){ TimeSeriesCollection data = new TimeSeriesCollection(); Month[] month = new Month[6]; for (int i = 0 ; i < 6 ; i++){ month[i] = new Month(i + 7, 2007); } int graphdata[][] = {{120, 140, 150, 190, 230, 280}, /* Aサイト */ {400, 380, 410, 200, 150, 80}, /* Bサイト */ {150, 170, 160, 180, 150, 170}}; /* Cサイト */ TimeSeries[] series = new TimeSeries[3]; series[0] = new TimeSeries("Aサイト", Month.class); series[1] = new TimeSeries("Bサイト", Month.class); series[2] = new TimeSeries("Cサイト", Month.class); for (int i = 0 ; i < 3 ; i++){ for (int j = 0 ; j < 6 ; j++){ series[i].add(month[j], graphdata[i][j]); } data.addSeries(series[i]); } return data; } }上記をコンパイルした後で実行すると次のように表示されます。 今回は例として描画領域の背景色をオレンジに変更しました。また上記のオレンジの箇所がグラフの描画領域となります。 |
|