Home日記コラム書評HintsLinks自己紹介
 

Tips: BIRT

Tips: BIRT

Java Tips に書いていたのだが、 どうも量が壮大【日本語がヘン】になりそうなので、こちらに分離した。

BIRT の chart を使ってグラフを書く

install

BIRT の download のところから、 Latest Builds をダウンロードする。 Release Build、Milestone Build、Stable Build があるのだが、 どれを使えばいいのかよく分からない。 チャレンジャーでないのなら、 Release Build か Stable Build なのだが、 今回は Release Build (1.0.1) というのを使った。

ダウンロード候補の中から、 birt-charts-1_0_1.zip をダウンロードして展開する。 内容は Eclipse をインストールしたところに上書きするいつもの形式なので、 コピーすればインストールは完了。

なお、doc の eclipse/plugins/org.eclipse.birt.doc_1.0.1 の下に doc.zip というファイルが入っている。 これを展開すると API のドキュメントとかあるので、 展開して、 chart/api/index.html を見えるようにしておくといい。

サンプルプログラムの実行

次のようなプログラムを作って、 Eclipse 3.1 に読み込んで実行してみた。 なお、最初の方にある、

package com.phinloda.mytest;

この行は、 皆さんの環境に合わせて修正する必要があると思う。 あるいは、そういうパッケージを作ってしまう手もあるが。

/**
 * BIRT を使ってグラフを表示するテスト。
 * see BIRT chart FAQ
 */
package com.phinloda.mytest;

import java.util.ArrayList;

import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.factory.Generator;
import org.eclipse.birt.chart.log.impl.DefaultLoggerImpl;
import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.attribute.Anchor;
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.IntersectionType;
import org.eclipse.birt.chart.model.attribute.LineAttributes;
import org.eclipse.birt.chart.model.attribute.LineStyle;
import org.eclipse.birt.chart.model.attribute.TickStyle;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.AxisImpl;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
import org.eclipse.birt.chart.model.data.NumberDataSet;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.TextDataSet;
import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl;
import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl;
import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;
import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;
import org.eclipse.birt.chart.util.PluginSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
 * @author mai see BIRT chart FAQ http://www.eclipse.org/birt/faq/Charts_FAQ.doc
 *         36, 37
 */
public class ChartViewerTest implements PaintListener {

    private IDeviceRenderer renderer = null;

    private Chart myChart = null;

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
     */
    public void paintControl(PaintEvent event) {
        renderer.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, event.gc);
        Composite composite = (Composite) event.getSource();
        Rectangle rectangle = composite.getClientArea();
        Bounds bounds = BoundsImpl.create(rectangle.x, rectangle.y,
                rectangle.width, rectangle.height);
        bounds.scale(72d / renderer.getDisplayServer().getDpiResolution());

        Generator generator = Generator.instance();

        try {
            generator.render(renderer, generator.build(renderer
                    .getDisplayServer(), myChart, null, bounds, null));
        } catch (ChartException e) {
            e.printStackTrace();
        }

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        ChartViewerTest viewer = new ChartViewerTest();
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 1;
        Display display = Display.getDefault();
        Shell shell = new Shell(display);
        shell.setSize(640, 480);

        shell.setLayout(gridLayout);
        shell.setText(viewer.getClass().getName() + "[device="
                + viewer.renderer.getClass().getName() + "]");

        GridData gridData = new GridData(GridData.FILL_BOTH);
        Canvas cCenter = new Canvas(shell, SWT.NONE);
        cCenter.setLayoutData(gridData);
        cCenter.addPaintListener(viewer);

        shell.open();

        while (shell.isDisposed() == false) {
            if (display.readAndDispatch() == false) {
                display.sleep();
            }
        }

        display.dispose();
    }

    /**
     * constructor
     * 
     */
    ChartViewerTest() {
        System.setProperty("STANDALONE", "true");

        final PluginSettings pluginSettings = PluginSettings.instance();

        try {
            renderer = pluginSettings.getDevice("dv.SWT");
        } catch (ChartException e) {
            e.printStackTrace();
            DefaultLoggerImpl.instance().log(e);
        }

        myChart = createMyChart();
    }

    public static Chart createMyChart() {
        // 軸ありのグラフ(チャート)を作る
        ChartWithAxes chartWithAxes = ChartWithAxesImpl.create();

        // グラフの題名を指定する
        // この方法は Additional information の 1 に出ている
        chartWithAxes.getTitle().getLabel().getCaption()
                .setValue("最近のアクセス状況");

        // 凡例表示の設定。
        Legend legend = chartWithAxes.getLegend();

        // 凡例を囲む枠線の設定
        LineAttributes legendLineAttributes = legend.getOutline();
        // 点線に指定する
        legendLineAttributes.setStyle(LineStyle.DOTTED_LITERAL);
        // 枠線を表示する
        legendLineAttributes.setVisible(true);

        // 凡例の説明表示に使われるフォントサイズ
        legend.getText().getFont().setSize(16);

        // Insets を指定している。
        // Top=10, Left=5, Bottom=0, Right=0
        legend.getInsets().set(10, 5, 0, 0);

        // 凡例表示の位置。NORTH_LITERAL は上詰めで表示する。
        // SOUTH_LITERAL を指定すると、下詰めで表示する。
        legend.setAnchor(Anchor.NORTH_LITERAL);

        // 軸に関する設定を行う

        // x軸
        // getPrimaryBaseAxis()[0] は、x軸に対応する
        Axis xAxis = chartWithAxes.getPrimaryBaseAxes()[0];

        // 軸タイプを指定する。x軸は文字列に対応するように設定
        xAxis.setType(AxisType.TEXT_LITERAL);

        // ヒゲを下に出す
        xAxis.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL);

        // x軸とy軸の交点がどこになるか指定する
        xAxis.getOrigin().setType(IntersectionType.VALUE_LITERAL);
        xAxis.getTitle().setVisible(false);

        // y軸
        // x軸と対応させた y軸
        Axis yAxis = (AxisImpl) chartWithAxes.getPrimaryOrthogonalAxis(xAxis);
        yAxis.getTitle().getCaption().setValue("アクセス数");
        yAxis.getTitle().setVisible(true);

        // ヒゲを左に出す
        yAxis.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL);

        // x 軸に対応する DataSet を作る
        ArrayList categoryList = new ArrayList();
        categoryList.add("11/1");
        categoryList.add("11/2");
        categoryList.add("11/3");
        categoryList.add("11/4");
        categoryList.add("11/5");
        categoryList.add("11/6");
        categoryList.add("11/7");
        categoryList.add("11/8");
        categoryList.add("11/9");
        categoryList.add("11/10");

        TextDataSet categoryValues = TextDataSetImpl.create(categoryList);

        // y軸に対応する DataSet を作る
        ArrayList valueList = new ArrayList();
        valueList.add(new Double(180.0));
        valueList.add(new Double(197.0));
        valueList.add(new Double(167.0));
        valueList.add(new Double(240.0));
        valueList.add(new Double(235.0));
        valueList.add(new Double(225.0));
        valueList.add(new Double(424.0));
        valueList.add(new Double(242.0));
        valueList.add(new Double(414.0));
        valueList.add(new Double(207.0));

        NumberDataSet OrthogonalValues = NumberDataSetImpl.create(valueList);

        // x軸に対応する Series を作る
        Series categorySeries = SeriesImpl.create();
        categorySeries.setDataSet(categoryValues);

        // y軸に対応する Series を作る
        Series lineSeries = LineSeriesImpl.create();
        lineSeries.setDataSet(OrthogonalValues);

        // 折れ線の識別子。これは凡例に表示される文字列となる。
        lineSeries.setSeriesIdentifier("裏表");

        // WRAP THE BASE SERIES IN THE X-AXIS SERIES
        SeriesDefinition sdX = SeriesDefinitionImpl.create();
        sdX.getSeriesPalette().update(0); // SET THE COLORS IN THE PALETTE
        xAxis.getSeriesDefinitions().add(sdX);
        sdX.getSeries().add(categorySeries);

        SeriesDefinition sdY = SeriesDefinitionImpl.create();
        sdY.getSeriesPalette().update(1);
        yAxis.getSeriesDefinitions().add(sdY);

        sdY.getSeries().add(lineSeries);

        return chartWithAxes;

    }
}

このコードを Eclipse にそのままコピーすると、 build path の関係で、大量のエラーが出る。 Project > Properties > Java Build Path をメニューから選択し、 Libraries タブをクリックして、 Add External JARs を実行する。 ダウンロードしたファイル中にある、 全ての jar ファイルを追加する。 (全部必要ではないのかもしれないが、どれが必要なのかわからんので。)

この状態で birt.chart 系のエラーは全部消えて、 次に目立つのが swt 系のエラーになっているはず。 これは、swt.jar を Build path に追加すれば消える。

この状態でBoundsImpl.create の所がエラーになっている。 The type org.eclipse.emf.ecore.impl.EObjectImpl cannot be resolved. ということで、 コンパイルには EMF が必要ということがわかる。 EMF のサイトからダウンロードするのだが、 これまたどれが適切なのか分からない。 一貫性のない選択だが、 今回は SDK 2.2.0M3 をダウンロードして使うことにした。 ごちゃ混ぜだけど、いいのだろうか。 とりあえず、 org.eclipse.emf.ecore_2.2.0.jar を追加。 今度は、 org.eclipse.emf.common.notify.impl.BasicNotifierImpl cannot be resolved. というのが出た。 org.eclipse.emf.common_2.2.0.jar も追加。 これでエラーはなくなった。 ところが実行すると、こんな感じになる。

警告: No plugins in BIRT_HOME: /d:/java/birt-charts-1_0_1/eclipse/plugins/org
 .eclipse.birt.core_1.0.1/, make sure this directory is correct!
Exception in thread "main" java.lang.UnsatisfiedLinkError: no swt-win32-3212
 in java.library.path
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at org.eclipse.swt.internal.Library.loadLibrary(Library.java:123)
    at org.eclipse.swt.internal.win32.OS.<clinit>(OS.java:18)
    at org.eclipse.swt.widgets.Display.<clinit>(Display.java:125)
    at org.eclipse.birt.chart.device.swt.SwtDisplayServer.<init>(SwtDisplayServer.java:80)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at org.eclipse.birt.chart.util.PluginSettings.newInstance(PluginSettings.java:591)
    at org.eclipse.birt.chart.util.PluginSettings.getDisplayServer(PluginSettings.java:431)
    at org.eclipse.birt.chart.device.swt.SwtRendererImpl.<init>(SwtRendererImpl.java:106)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at org.eclipse.birt.chart.util.PluginSettings.newInstance(PluginSettings.java:591)
    at org.eclipse.birt.chart.util.PluginSettings.getDevice(PluginSettings.java:370)
    at com.phinloda.mytest.ChartViewerTest.<init>(ChartViewerTest.java:125)
    at com.phinloda.mytest.ChartViewerTest.main(ChartViewerTest.java:88)

をーこれが有名なアレか…。 SWT FAQ には、

Q: Why do I get the error "java.lang.UnsatisfiedLinkError: no swt-win32-2034 in java.library.path."?

と出ている、まさにその通りの問題が残っているのだ。 Run ダイアログの Arguments に、

-Djava.library.path=D:/java/swt-3.2M3-win32-win32-x86

として実行。 これでこのエラーは解消して、次のようなグラフが表示されるはずだ。

birt chart sample

プログラムの解説

というか、概略に近いが。 まず、一番最後のメソッド、 createMyChart() が一番謎だと思うので、ここを解説。

        // 軸ありのグラフ(チャート)を作る
        ChartWithAxes chartWithAxes = ChartWithAxesImpl.create();

BIRT の Chart を使う場合、 まず、このように HogeHogeImpl.create() みたいなメソッドを呼び出してオブジェクトを生成してもらう。 ここでは、軸ありのグラフ(チャート)のオブジェクトを作っている。

ChartWithAxes クラスとは何か。 これは Chart クラスから派生している。 getter だけ紹介すると、こんな感じ。

Chart
+getBlock() : Block
+getDescription() : Text
+getDimension() : ChartDimension
+getExtendedProperties() : org.eclipse.emf.common.util.EList
+getGridColumnCount() : int
+getLegend() : Legend
+getPlot() : Plot
+getSampleData() : SampleData
+getScript() : String
+getSeriesForLegend() : SeriesDefinition[]
+getSeriesThickness() : double
+getSubType() : String
+getTitle() : TitleBlock
+getType() : String
+getUnits() : String
+getVersion() : String

Note

ちょっと表が見苦しいけど、 forrest の設定が未完成です。 そのうちもう少しマシにできると思われます。 クラス図だと思ってください。

org.eclipse.emf.common.util.EList というクラスが、この後も出てくるのだが、 これは java.util.List から派生したクラスで、 move というメソッドが追加されているだけ、というもの。

EList <<interface>>
+ move(int newPosition, int oldPosition) : Object
+ move(int newPosition, Object object) : void

move メソッドは、 移動前の位置を指定するものと、 移動したい Object を直接指定するものの、2通りが用意されている。 こういう汎用的なメソッドは java.util に置いてあってもいいと思うが、 まあそれはそうとして、話を元に戻す。

軸を持つグラフを表示したい場合には、 Chart クラスから派生したクラスの ChartWithAxes を使う。 このクラスには、 次のような getter が追加されている。

ChartWithAxes
+ getAxes() : org.eclipse.emf.common.util.EList
+ getBaseAxes() : Axis[]
+ getFloorFill() : Fill
+ getOrientation() : Orientation
+ getOrthogonalAxes(Axis axBase, boolean bIncludePrimary) : Axis[]
+ getPrimaryBaseAxes() : Axis[]
+ getPrimaryOrthogonalAxis(Axis axBase) : Axis
+ getSeries(int iBaseOrOrthogonal) Series[]
+ getUnitSpacing() : double
+ getWallFill() : Fill

軸を持つグラフを設定するときに、 軸の設定は重要なので、 Chart で指定できる要素だけで済むことはまずないと思われる。 つまり、ChartWithAxes クラスの操作が実際に必要になるので、 オブジェクトを受け取るときに、 Chart ではなく ChartWithAxes で受け取っているのだ。 なお、軸を持つグラフというのは、 折れ線グラフや棒グラフのことである。 では軸を持たないグラフとは何ぞやというと、 円グラフみたいな。

Chart は、 いくつかの領域を組み合わせた構造になっている。 グラフを描画する領域は Plot が受け持つのだが、 このソースでは全部デフォルトで済ませているので出てこない。 例えばグラフを描画する領域の背景色を指定したければ、 こんなことをすればいい。

        Plot plot = chartWithAxes.getPlot();
        ClientArea clientArea = plot.getClientArea();
        clientArea.setBackground(
                ColorDefinitionImpl.create(255, 255, 200));

グラフにタイトルを表示したい場合に使う領域は、 TitleBlock である。 これは Chart.getTitle() で get できる。

Note

個人的には getTitleBlock() という名前にして欲しいものだ。 まあいいけど。 EMF のネーミングが影響しているのかもしれない?

TitleBlock の中に Label があって、Caption があって… という構造になっていて、 確かによくできているのだが、 結構面倒。 ということで、実際こういう書き方をした。

        // グラフの題名を指定する
        // この方法は Additional information の 1 に出ている
        chartWithAxes.getTitle().getLabel().getCaption().setValue("最近のアクセス状況");

コメントに書いてあるように、 これは chart FAQ の、 Additional information の 1 の書き方を真似したものである。

次に凡例を指定している。 Legend というのが、凡例を表示するエリアに対応する。

Note

Web 翻訳とかに通すと legend block というのが「伝説のブロック」と訳されて驚きたわわだ。
        // 凡例表示の設定。
        Legend legend = chartWithAxes.getLegend();

        // 凡例を囲む枠線の設定
        LineAttributes legendLineAttributes = legend.getOutline();
        // 点線に指定する
        legendLineAttributes.setStyle(LineStyle.DOTTED_LITERAL);
        // 枠線を表示する
        legendLineAttributes.setVisible(true);

        // 凡例の説明表示に使われるフォントサイズ
        legend.getText().getFont().setSize(16);

        // Insets を指定している。
        // Top=10, Left=5, Bottom=0, Right=0
        legend.getInsets().set(10, 5, 0, 0);

        // 凡例表示の位置。NORTH_LITERAL は上詰めで表示する。
        // SOUTH_LITERAL を指定すると、下詰めで表示する。
        legend.setAnchor(Anchor.NORTH_LITERAL);

Inset というインターフェースは、 長方形領域の四隅を double の値で表現するもので、 上、左、下、右、の4つの位置に対応した Top, Left, Bottom, Right、の4つの属性を持つ。 これらを setter / getter でコントロールする。

Inset には、 各属性の値をセットしたか、何も指定していないか、 という状態も保持する機能もある。 例えば一度も Top が set されていなければ、 isSetTop() メソッドが false を返すはず。

次に、軸の設定。 ChartWithAxes 系のグラフの軸に関する設定は、 Axis クラスを使って行う。

        // x軸
        // getPrimaryBaseAxis()[0] は、x軸に対応する
        Axis xAxis = chartWithAxes.getPrimaryBaseAxes()[0];

        // 軸タイプを指定する。x軸は文字列に対応するように設定
        xAxis.setType(AxisType.TEXT_LITERAL);

        // ヒゲを下に出す
        xAxis.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL);

        // x軸とy軸の交点がどこになるか指定する
        xAxis.getOrigin().setType(IntersectionType.VALUE_LITERAL);
        xAxis.getTitle().setVisible(false);

getPrimaryBaseAxes() に関しては、 例の FAQ に詳しく書いてあるので省略するが、 要するに最初の1つの軸はこれで生成するらしい。

今回は横軸は文字を指定するので、 TEXT_LITERAL を指定している。 TEXT と TEXT_LITERAL の違いなのだが、 型が違うというか、 とりあえず横軸に文字を表示したければ TEXT_LITERAL にしておけばよいのではなかろうか。

tickStyle というのは、 軸の目盛りのところに出ているヒゲのようなアレ。 BELOW_LITERAL というのは、 軸から下に向かってヒゲを出すことを指定している。

Axis.getOrigin() で AxisOrigin オブジェクトを受け取って、 その内容を設定している。 この AxisOrigin クラスは座標原点を表現するもので、 Type と Value の 2つの属性を持っている。 ここでは、Type として、 IntersectionType.VALUE_LITERAL を指定している。

次に、y軸の設定を行う。 y座標は、x軸に対する直交座標となるので、 getPrimaryOrthogonalAxis メソッドを使って、 xAxi に対応付けたオブジェクトを受け取っている。

        // y軸
        // x軸と対応させた y軸
        Axis yAxis = (AxisImpl) chartWithAxes.getPrimaryOrthogonalAxis(xAxis);
        yAxis.getTitle().getCaption().setValue("アクセス数");
        yAxis.getTitle().setVisible(true);

        // ヒゲを左に出す
        yAxis.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL);

setTickStyle は、ヒゲを左に出す指定。

続いて、 x座標の値を DataSet として指定する。 今回は、文字列を対応付ける。

        // x 軸に対応する DataSet を作る
        ArrayList categoryList = new ArrayList();
        categoryList.add("11/1");
        categoryList.add("11/2");
        categoryList.add("11/3");
        categoryList.add("11/4");
        categoryList.add("11/5");
        categoryList.add("11/6");
        categoryList.add("11/7");
        categoryList.add("11/8");
        categoryList.add("11/9");
        categoryList.add("11/10");

        TextDataSet categoryValues = TextDataSetImpl.create(categoryList);

続いて、 これらの DataSet に対して、 値がどうなのかということを指定する。 これは y 軸の値になる。

        // y軸に対応する DataSet を作る
        ArrayList valueList = new ArrayList();
        valueList.add(new Double(180.0));
        valueList.add(new Double(197.0));
        valueList.add(new Double(167.0));
        valueList.add(new Double(240.0));
        valueList.add(new Double(235.0));
        valueList.add(new Double(225.0));
        valueList.add(new Double(424.0));
        valueList.add(new Double(242.0));
        valueList.add(new Double(414.0));
        valueList.add(new Double(207.0));

        NumberDataSet OrthogonalValues = NumberDataSetImpl.create(valueList);

x軸に対応する Series を作る。

        // x軸に対応する Series を作る
        Series categorySeries = SeriesImpl.create();
        categorySeries.setDataSet(categoryValues);

y軸も同様だが、 y軸には identifier を指定している。 ここで指定した String が、凡例のところに表示される。

        // y軸に対応する Series を作る
        Series lineSeries = LineSeriesImpl.create();
        lineSeries.setDataSet(OrthogonalValues);

        // 折れ線の識別子。これは凡例に表示される文字列となる。
        lineSeries.setSeriesIdentifier("裏表");

次にここがよく分からないのだが、 SeriesDefinition を作って、 軸にセットする。

        // WRAP THE BASE SERIES IN THE X-AXIS SERIES
        SeriesDefinition sdX = SeriesDefinitionImpl.create();
        sdX.getSeriesPalette().update(0); // SET THE COLORS IN THE PALETTE
        xAxis.getSeriesDefinitions().add(sdX);
        sdX.getSeries().add(categorySeries);

これはもしかして、

        // WRAP THE BASE SERIES IN THE X-AXIS SERIES
        SeriesDefinition sdX = SeriesDefinitionImpl.create();
        sdX.getSeriesPalette().update(0); // SET THE COLORS IN THE PALETTE
        sdX.getSeries().add(categorySeries);
        xAxis.getSeriesDefinitions().add(sdX);

と書いてはいけないのだろうか、 とか思うのだが、 FAQ のサンプルがそうなっているので、 とりあえずコードは元の順序のままにしておいた。 こんなのが順番変えたら動かないなんてことはあり得ないと思うが、 念のため。

Note

実際、順番を変えてもちゃんと動く。

一応考えておくと、 Series というのが「列」ということで、 数値なら数列に対応するのだが、 今回は文字列が入った ArrayList を使って横軸を作っているから、 横軸は、ArrayList の要素が並んだ列、という感じになる。

getSeriesPalette() というのがよく分からないのだが、 標準的な色の組み合わせがあらかじめ指定されていて、 0番目のグループの組み合わせの色に初期化している、ということらしい。

(UNDER CONSTRUCTION)