2015-06-28

【まとめ】Google Chromebooks の今

Chromebook(クロームブック)は、Google が開発しているオペレーティングシステム Google Chrome OS を搭載しているノートパソコンのシリーズです。2011 年 5 月に、Google がサムスン電子との共同開発で 1 号機を発表、同 6 月より市販されています。日本では、法人ユーザーと教育関係機関向けに先行販売されていましたが、個人向けに 2014 年 11 月 11 日より発売されています。

個人向けに販売されて半年以上経っていますが、現状はどのようになっているかをまとめました。

まずは、古い記事ですが、Chromebook に実際に使い込んだ経験を元に書かれている記事です。執筆業に携る人の視点でまとめられています。

以下の記事も、半年程度実際に使った経験をベースとした記事です。これも編集部員やライター氏の視点でまとめられています。

以下の記事も、どちらかと言えば編集部員やライター氏の視点で、肯定的な表う論をしていますが、Chromebook に満足するには、自身が Chrome 化していなければ、と最後に結論付けています。

以下の記事も、ライター氏の視点ですが、製品の宣伝も兼ねているのか、写真やビデオの映像が豊富です。

こちらは、一般的なユーザーに近い視点で書かれています。Chromebook の長所/短所がわかりやすくまとめられています。

Amazon.jp の Chromebook ストアをみてみましょう。

Chromebook の特徴が簡潔に 6 つにまとめられており、購入できる Chromebook が並んでいます。CPU は Intel Celeron/Atom を搭載したものが大半ですが、Intel 系の CPU が必須というわけではなく、Samsung 製はもちろんのこと一部の HP の製品でも ARM 系の Samsung Exynos を搭載しているものもあります。個人的には ARM を搭載している機種に興味津々ですが、バッテリーの持ちで Intel の CPU に較べて圧倒的に優位でもない限り、CPU にこだわる必要は無いのかもしれません。


2015-06-26

JavaFX: チャートのカスタマイズ (1)

JavaFX のチャートを使いこなせるようになりたいと、いくつかチャートのサンプルを紹介してきました。前回は ScatterChart を利用した散布図のサンプルを紹介しましたが、やはり、点と線をチャートでは自由に扱いたいと感じました。データ点(シンボル)と線を別々に扱いたければ、LineChart で、データ点については点と点を結ぶ線を透明にすれば良いのですが、なんだかとても無駄な気がします。

X と Y 座標でデータ表現する ScatterChart などのクラスは、抽象クラス XYChart を継承しています。JavaFX のチャートをカスタマイズしたければ、XYChart を継承して好きなようにチャートを作れば良いのですが、いきなりは敷居が高いです。そこで、線も点(シンボル)も扱える LineChart を継承したクラスで、部分的に機能をカスタマイズしてみます。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2
  • commons-math3-3.5

今回は、回帰計算をするために、Apache Commons Math ライブラリを使用しています

さて、まず LineChart を継承するクラス MyChart1 です。ここでは、最初のデータ群 (series) をデータ点(シンボル)のみ、二番目以降のデータ群はシンボルなしで直線で結ぶだけ、という仕様にしました。

MyChart1 では、メソッド layoutPlotChildren をオーバーライドしています。参考サイト [1] にある LineChart のメソッド layoutPlotChildren のコードに手を加えました。なお、JavaFX Demos and Samples の CandleStickChart にある layoutPlotChildren メソッドを参考にしています。

リスト:MyChart1.java 
package mychartsample;

import java.util.Iterator;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;

/**
 * MyChart1
 *
 * @author bitwalk
 * @param <X>
 * @param <Y>
 */
public class MyChart1<X, Y> extends LineChart<X, Y> {

    // -------------- CONSTRUCTORS ----------------------------------------------
    /**
     * Construct a new MyChart with the given axis.
     *
     * @param xAxis The x axis to use
     * @param yAxis The y axis to use
     */
    public MyChart1(Axis<X> xAxis, Axis<Y> yAxis) {
        super(xAxis, yAxis);
    }

    // -------------- METHODS ------------------------------------------------------------------------------------------
    /**
     *
     */
    @Override
    protected void layoutPlotChildren() {
        for (int seriesIndex = 0; seriesIndex < getData().size(); seriesIndex++) {
            Series<X, Y> series = getData().get(seriesIndex);
            Iterator<Data<X, Y>> iter = getDisplayedDataIterator(series);
            boolean isFirst = true;

            if (series.getNode() instanceof Path) {
                Path seriesLine = (Path) series.getNode();
                seriesLine.getElements().clear();

                while (iter.hasNext()) {
                    Data<X, Y> item = iter.next();
                    double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
                    double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));

                    if (seriesIndex == 0) {
                        // 最初のデータ群はシンボルのみ
                        Node symbol = item.getNode();
                        if (symbol != null) {
                            final double w = symbol.prefWidth(-1);
                            final double h = symbol.prefHeight(-1);
                            symbol.resizeRelocate(x - (w / 2), y - (h / 2), w, h);
                        }
                    } else {
                        // 最初のデータ群でない場合は線のみ
                        if (isFirst) {
                            isFirst = false;
                            seriesLine.getElements().add(new MoveTo(x, y));
                        } else {
                            seriesLine.getElements().add(new LineTo(x, y));
                        }
                    }
                }
            }
        }
    }
}

MyChart1 を使ってチャートを表示するサンプル MyChart1Sample.java では、[2] で紹介したサンプルをベースにして、同じデータ点に、Commons Math ライブラリで計算した回帰直線と三次の重回帰式を加えてみました。

リスト:MyChart1Sample.java 
package mychartsample;

import java.util.ArrayList;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.commons.math3.stat.regression.SimpleRegression;

/**
 * MyChart1Sample - for sample of MyChart1, customized LineChart
 *
 * @author bitwalk
 */
public class MyChart1Sample extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("MyChart Sample");

        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("X軸ラベル(時間)");
        yAxis.setLabel("Y軸ラベル(数値)");

        final MyChart1<Number, Number> myChart = new MyChart1<>(xAxis, yAxis);
        myChart.setTitle("最小二乗法のサンプル");

        myChart.setAnimated(false);
        myChart.setCreateSymbols(true);

        myChart.setData(getChartData());

        Scene scene = new Scene(myChart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("MyChart1.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }

    /**
     * getChartData
     *
     * @return ObservableList<XYChart.Series<String, Double>>
     */
    private ObservableList<XYChart.Series<Number, Number>> getChartData() {
        Series<Number, Number> series1 = new Series<>();
        Series<Number, Number> series2 = new Series<>();
        Series<Number, Number> series3 = new Series<>();

        // raw data
        ArrayList<PairData> dataArr = new ArrayList<>();
        dataArr.add(setPair(1d, 3d));
        dataArr.add(setPair(2d, 7d));
        dataArr.add(setPair(3d, 14d));
        dataArr.add(setPair(4d, 10d));
        dataArr.add(setPair(5d, 17d));

        // data range used for line/curve
        ArrayList<Double> xRange = new ArrayList<>();
        xRange.add(0.5);
        xRange.add(5.5);

        // for simple regression
        SimpleRegression regression = new SimpleRegression();

        // for multiple regression
        OLSMultipleLinearRegression mulreg = new OLSMultipleLinearRegression();
        double[] y_mulreg = new double[dataArr.size()];
        double[][] x_mulreg = new double[dataArr.size()][];

        // raw data setting and regression
        series1.setName("観測データ");
        for (int i = 0; i < dataArr.size(); i++) {
            double x = dataArr.get(i).X;
            double y = dataArr.get(i).Y;
            series1.getData().add(new XYChart.Data(x, y));

            // simple regression
            regression.addData(x, y);

            // muliple regression for cubic
            y_mulreg[i] = y;
            x_mulreg[i] = new double[]{x, x * x, x * x * x};
        }

        // regression
        series2.setName("単回帰(直線)");
        xRange.stream().forEach((xr) -> {
            series2.getData().add(new XYChart.Data(xr, regression.predict(xr)));
        });

        // multiple requression
        series3.setName("重回帰(三次式)");
        mulreg.newSampleData(y_mulreg, x_mulreg);
        double[] beta = mulreg.estimateRegressionParameters();

        double x0 = xRange.get(0);
        while (x0 <= xRange.get(1)) {
            series3.getData().add(new XYChart.Data(x0, getPolynomialValue(beta, x0)));
            x0 = x0 + 0.01;
        }

        // set series data to collection
        ObservableList<XYChart.Series<Number, Number>> seriesList = FXCollections.observableArrayList();
        seriesList.addAll(series1, series2, series3);

        return seriesList;
    }

    /**
     * getPolynomialValue
     *
     * @param coef coefficient
     * @param x x value
     * @return calculated polynomial
     */
    private double getPolynomialValue(double[] coef, double x) {
        double y = 0d;
        for (int i = 0; i < coef.length; i++) {
            y = y + coef[i] * Math.pow(x, i);
        }
        return y;
    }

    /**
     * setPair - set pair of data to the PairData structure
     *
     * @param x
     * @param y
     * @return PairData
     */
    private PairData setPair(double x, double y) {
        PairData data = new PairData();
        data.X = x;
        data.Y = y;

        return data;
    }

    /**
     * PairData - structure for handling (x, y) data
     */
    private class PairData {

        double X;
        double Y;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

CSS は、チャートの主要部分は今まで紹介したサンプルで使用した CSS をベースとしていますが、シンボルとラインの修飾については、今回の仕様に合うように書き直しています。

リスト:MyChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}

.chart-vertical-grid-lines {
    -fx-stroke: #c1e0fd;
}
.chart-horizontal-grid-lines {
    -fx-stroke: #c1e0fd;
}

.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-series-line {
    -fx-stroke-width: 1px;
    -fx-effect: null;
}

.default-color0.chart-series-line { -fx-stroke: transparent; }
.default-color1.chart-series-line { -fx-stroke: blue; }

.default-color0.chart-line-symbol { 
    -fx-background-color: red;
    -fx-background-radius: 0;
    -fx-background-insets: 0;
    -fx-shape: "M2,0 L5,4 L8,0 L10,0 L10,2 L6,5 L10,8 L10,10 L8,10 L5,6 L2,
        10 L0,10 L0,8 L4,5 L0,2 L0,0 Z";
}

.default-color1.chart-line-symbol { 
    -fx-background-color: transparent, transparent; 
}

.default-color1.chart-legend-item-symbol{
    -fx-background-color: blue;
    -fx-background-radius: 0;
    -fx-background-insets: 0;
    -fx-shape: "M0,5 L0,7 L12,7 L12,5 Z";
    -fx-scale-shape: false;
}

実行例を以下に示します。

今回はほんの僅かですが、すこしずつカスタマイズできる範囲を広げて行く予定です。

参考サイト

  1. openjfx/8/master/rt: 88d3bef80ffc modules/controls/src/main/java/javafx/scene/chart/LineChart.java
  2. bitWalk's: JavaFX: LineChart を使いこなそう (3)
  3. JavaFX CSS Reference Guide
  4. Using JavaFX Charts: Styling Charts with CSS | JavaFX 2 Tutorials and Documentation

2015-06-21

JavaFX: ScatterChart を使いこなそう

JavaFX のチャートを使いこなせるようになりたいと、いくつかチャートのサンプルを紹介してきました。今回は ScatterChart を利用した散布図のサンプルを紹介します。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2

今回は [3] を参考にして、マウスのポインタをデータ上に持っていけば Tooltip でデータ点の座標を表示できるようにしました。

リスト:ScatterChartSample.java 
package scatterchartsample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Tooltip;
import javafx.stage.Stage;

public class ScatterChartSample extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Scatter Chart Sample");

        //defining the axes
        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("X軸ラベル(数値)");
        yAxis.setLabel("Y軸ラベル(数値)");

        //creating the chart
        final ScatterChart scatterChart = new ScatterChart(xAxis, yAxis);
        ObservableList<XYChart.Series<Double, Double>> scatterData = getScatterData();
        scatterChart.setData(scatterData);
        scatterChart.setTitle("散布図のサンプル");

        Scene scene = new Scene(scatterChart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("ScatterChart.css").toExternalForm());

        stage.setScene(scene);
        stage.show();

        scatterData.stream().forEach((series) -> {
            series.getData().stream().forEach((point) -> {
                Tooltip.install(point.getNode(),
                        new Tooltip(String.format("(%3.2f, %3.2f)", point.getXValue(), point.getYValue())));
            });
        });
    }

    /**
     *
     * @return ObservableList<XYChart.Series<Double, Double>>
     */
    private ObservableList<XYChart.Series<Double, Double>> getScatterData() {
        Series<Double, Double> series1 = new Series<>();
        Series<Double, Double> series2 = new Series<>();

        series1.setName("系列1");
        series2.setName("系列2");

        for (int i = 0; i < 50; i++) {
            series1.getData().add(new XYChart.Data(Math.random() * 2 - 1.4, Math.random() - .7));
            series2.getData().add(new XYChart.Data(Math.random() * 2 - .6, Math.random() - .3));
        }

        ObservableList<XYChart.Series<Double, Double>> seriesList = FXCollections.observableArrayList();
        seriesList.addAll(series1, series2);

        return seriesList;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

CSS は、今回も折れ線グラフに使ったものをベースにしています。

リスト:ScatterChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}


.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-symbol { /* solid circle */
    -fx-background-radius: 3px;
    -fx-padding: 3px;
}

.default-color0.chart-symbol {
    -fx-background-color: black, forestgreen;
}

.default-color1.chart-symbol {
    -fx-background-color: tomato;
    -fx-background-radius: 0;
    -fx-background-insets: 0;
    -fx-shape: "M2,0 L5,4 L8,0 L10,0 L10,2 L6,5 L10,8 L10,10 L8,10 L5,6 L2,
        10 L0,10 L0,8 L4,5 L0,2 L0,0 Z";
}

実行例を以下に示します。

散布図は自分にとって最も基本的なグラフです。データを表現する際にまず、XY グラフ(散布図)を作ってみて、それからデータを結ぶとか補間するなど、データに視覚的な意味付けをしていきます。ですので、ScatterChart を出発点として、線やら何やら加えていけるととても嬉しいのですが、JavaFX のチャートはそのような仕様にはなっていません。しかし、基本的なチャートが利用できるわけですから、これらのクラスを拡張して自分の好きなチャートを作れるようにすれば良いのです。

さて、言うは易く行うは難し…、習得に時間が掛りそうではあります。

参考サイト

  1. JavaFX CSS Reference Guide
  2. Using JavaFX Charts: Styling Charts with CSS | JavaFX 2 Tutorials and Documentation
  3. Tooltips for datapoints in a scatter chart in javafx 2.2 - Stack Overflow

2015-06-15

JavaFX: PieChart を使いこなそう

JavaFX のチャートを使いこなせるようになりたいと、LineChart, BarChart のサンプルを紹介してきました。今回は PieChart を利用した円グラフ(パイチャート)のサンプルを紹介します。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2

リスト:PieChartSample.java 
package piechartsample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.stage.Stage;

public class PieChartSample extends Application {

    @Override
    public void start(Stage stage) {
        // http://www.kudamononavi.com/graph/trade/
        ObservableList<PieChart.Data> piechartData
                = FXCollections.observableArrayList(
                        new PieChart.Data("温州みかん", 47200),
                        new PieChart.Data("りんご", 39700),
                        new PieChart.Data("かき", 22600),
                        new PieChart.Data("くり", 21700),
                        new PieChart.Data("ぶどう", 18600));

        final PieChart piechart = new PieChart(piechartData);
        piechart.setTitle("果物生産ランキング(作付面積)");
        piechart.setLegendSide(Side.RIGHT);
        
        Scene scene = new Scene(piechart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("PieChart.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

CSS は、今回も折れ線グラフに使ったものをベースにしています。

リスト:PieChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}

.chart-pie {
    -fx-border-color: rgba(0, 0, 0, 0.2);
    -fx-background-radius: 0;
    -fx-background-insets: 0;
}

.chart-pie-label {
    -fx-font-size: 12pt;
}

.default-color0.chart-pie { -fx-background-color: orange; }
.default-color1.chart-pie { -fx-background-color: lawngreen; }
.default-color2.chart-pie { -fx-background-color: lightpink; }
.default-color3.chart-pie { -fx-background-color: khaki; }
.default-color4.chart-pie { -fx-background-color: skyblue; }

.chart-pie-label-line {
}

.chart-pie-label {
} 

.chart-legend {
    -fx-font-size: 9pt;
    -fx-background-color:  transparent;
}

実行例を以下に示します。

棒グラフの場合と同じ理由で、円グラフでも作成するときには配色に悩みます。さらに、Excel などでは文字の大きさと円グラフの領域を最大にするのに苦労します。その苦労は JavaFX でも同じです。なにか良い方法がないかと思うのですが、時間を掛けて検討するほど円グラフの使用頻度が高くないので、いつも間に合わせの対応で済ませてしまっています。

参考サイト

  1. JavaFX CSS Reference Guide
  2. Using JavaFX Charts: Styling Charts with CSS | JavaFX 2 Tutorials and Documentation
  3. chartとgraphの違い | 違いがわかると英語がわかる

2015-06-14

JavaFX: BarChart を使いこなそう

JavaFX のチャートを使いこなせるようになりたいと、今まで三回にわたって LineChart のサンプルを紹介しました。今回は BarChart を利用した棒グラフのサンプルを紹介します。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2

リスト:BarChartSample.java 
package barchartsample;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

public class BarChartSample extends Application {

    final static String fy2010 = "2010";
    final static String fy2011 = "2011";
    final static String fy2012 = "2012";
    final static String fy2013 = "2013";
    final static String fy2014 = "2014";

    @Override
    public void start(Stage stage) {
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        final BarChart<String, Number> barchart = new BarChart<>(xAxis, yAxis);

        barchart.setTitle("棒グラフのサンプル");
        xAxis.setLabel("会計年度");
        yAxis.setLabel("販売金額(百万円)");

        XYChart.Series series1 = new XYChart.Series();
        series1.setName("製品A");
        series1.getData().add(new XYChart.Data(fy2010, 11));
        series1.getData().add(new XYChart.Data(fy2011, 15));
        series1.getData().add(new XYChart.Data(fy2012, 21));
        series1.getData().add(new XYChart.Data(fy2013, 38));
        series1.getData().add(new XYChart.Data(fy2014, 62));

        XYChart.Series series2 = new XYChart.Series();
        series2.setName("製品B");
        series2.getData().add(new XYChart.Data(fy2010, 38));
        series2.getData().add(new XYChart.Data(fy2011, 35));
        series2.getData().add(new XYChart.Data(fy2012, 36));
        series2.getData().add(new XYChart.Data(fy2013, 41));
        series2.getData().add(new XYChart.Data(fy2014, 42));

        XYChart.Series series3 = new XYChart.Series();
        series3.setName("製品C");
        series3.getData().add(new XYChart.Data(fy2010, 15));
        series3.getData().add(new XYChart.Data(fy2011, 28));
        series3.getData().add(new XYChart.Data(fy2012, 38));
        series3.getData().add(new XYChart.Data(fy2013, 42));
        series3.getData().add(new XYChart.Data(fy2014, 34));

        Scene scene = new Scene(barchart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("BarChart.css").toExternalForm());

        barchart.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

CSS は、折れ線グラフに使ったものをベースにしています。

リスト:BarChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-bar {
    -fx-border-color: rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.2) transparent rgba(0, 0, 0, 0.2);
}

.series0.chart-bar {
    -fx-background-color: lightskyblue;
}

.series1.chart-bar {
    -fx-background-color: khaki;
}

.series2.chart-bar {
    -fx-background-color: lightpink;
}

.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.default-color0.chart-legend-item-symbol {
    -fx-border-color: rgba(0, 0, 0, 0.2);        
}

.default-color1.chart-legend-item-symbol {
    -fx-border-color: rgba(0, 0, 0, 0.2);        
}

.default-color2.chart-legend-item-symbol {
    -fx-border-color: rgba(0, 0, 0, 0.2);        
}

実行例を以下に示します。

棒グラフを作成するときにいつも頭を悩ますのがバーの配色です。三原色に近い色を使ってしまうと、ペイントする領域が多いのでバーが目立ち過ぎて、却って棒グラフの特徴が判りにくくなってしまいます。かと言って淡い配色を使うと、バーの輪郭を処理しないとメリハリが無いグラフになってしまいます。その点、JavaFX のチャートでは容易に輪郭を表現できそうです。

なお、 BarChart クラスを StackedBarChart へ変更すると、下記のような積み上げの棒グラフを作成できます。

参考サイト

  1. JavaFX CSS Reference Guide
  2. Using JavaFX Charts: Styling Charts with CSS | JavaFX 2 Tutorials and Documentation

2015-06-11

JavaFX: LineChart を使いこなそう (3)

JavaFX では LineChart で折れ線グラフ、ScatterChart で散布図を作成することができます。それでは、データのポイントと直線や曲線が混在するグラフを作成するにはどうすれば良いでしょうか?

この場合、LineChart でデータとデータの間の線の色を透明にしてデータ点を表現します。

今回は、最小二乗法のサンプルグラフを紹介します。と言っても、回帰計算の処理はサンプルには含まれておらず、計算結果のみをプロットしています。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64 Fedora 23 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 jdk1.8.0_77-1.8.0_77-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2 NetBeans IDE 8.1

※ コンパイル時の警告が出ないようにソースコードを修正、整理しました。(2016-3-26)

リスト:LineChartSample2.java 
package linechartsample2;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

public class LineChartSample2 extends Application {

    @Override
    public void start(Stage stage) {
        NumberAxis xAxis = new NumberAxis();
        NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("X軸ラベル(時間)");
        yAxis.setLabel("Y軸ラベル(数値)");

        LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
        lineChart.setTitle("最小二乗法のサンプル");
        lineChart.setAnimated(false);
        lineChart.setCreateSymbols(true);

        XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
        series1.setName("データ");
        series1.getData().add(new XYChart.Data<>(1, 3));
        series1.getData().add(new XYChart.Data<>(2, 7));
        series1.getData().add(new XYChart.Data<>(3, 14));
        series1.getData().add(new XYChart.Data<>(4, 10));
        series1.getData().add(new XYChart.Data<>(5, 17));
        lineChart.getData().add(series1);

        XYChart.Series<Number, Number> series2 = new XYChart.Series<>();
        series2.setName("回帰直線");
        series2.getData().add(new XYChart.Data<>(0, 0.9));
        series2.getData().add(new XYChart.Data<>(6, 19.5));
        lineChart.getData().add(series2);

        Scene scene = new Scene(lineChart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("XYChart.css").toExternalForm());
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

CSS は以下のようになります。凡例において、回帰直線の青い直線を表現するのに手こずってしまいました。

リスト:XYChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}


.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-series-line {
    -fx-stroke-width: 1px;
    -fx-effect: null;
}

.default-color0.chart-series-line { -fx-stroke: transparent; }
.default-color1.chart-series-line { -fx-stroke: blue; }

.default-color0.chart-line-symbol { 
    -fx-background-color: red;
    -fx-background-radius: 0;
    -fx-background-insets: 0;
    -fx-shape: "M2,0 L5,4 L8,0 L10,0 L10,2 L6,5 L10,8 L10,10 L8,10 L5,6 L2,
        10 L0,10 L0,8 L4,5 L0,2 L0,0 Z";
}

.default-color1.chart-line-symbol { 
    -fx-background-color: transparent, transparent; 
}

.default-color1.chart-legend-item-symbol{
    -fx-background-color: blue;
    -fx-background-radius: 0;
    -fx-background-insets: 0;
    -fx-shape: "M0,5 L0,7 L12,7 L12,5 Z";
    -fx-scale-shape: false;
}

実行例を以下に示します。

次回は、他の種類のチャートを紹介する予定です。

参考サイト

  1. bitWalk's: トレンドチャートのサンプル

2015-06-07

JavaFX: LineChart を使いこなそう (2)

JavaFX のチャートを使いこなせるようになりたいと、前回 LineChart のベースサンプルを示しました。今回はそのサンプルを自分が好きなように CSS で修飾してみました。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2

Java のソースを若干の修正を加え、32 行で CSS を読み込んでいます。

リスト:LineChartSample.java 
package linechartsample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart Sample");

        //defining the axes
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("X軸ラベル(年)");
        yAxis.setLabel("Y軸ラベル(数値)");

        //creating the chart
        final LineChart lineChart = new LineChart(xAxis, yAxis);
        lineChart.setData(getChartData());
        lineChart.setTitle("折れ線グラフのサンプル");
        
        Scene scene = new Scene(lineChart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("LineChart.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }

    /**
     *
     * @return ObservableList<XYChart.Series<String, Double>>
     */
    private ObservableList<XYChart.Series<String, Double>> getChartData() {
        double y1 = 0.1;
        double y2 = -0.1;

        Series<String, Double> series1 = new Series<>();
        Series<String, Double> series2 = new Series<>();

        series1.setName("系列1");
        series2.setName("系列2");

        for (int i = 2011; i < 2021; i++) {
            series1.getData().add(new XYChart.Data(Integer.toString(i), y1));
            y1 = y1 + Math.random() - .5;

            series2.getData().add(new XYChart.Data(Integer.toString(i), y2));
            y2 = y2 + Math.random() - .5;
        }

        ObservableList<XYChart.Series<String, Double>> seriesList = FXCollections.observableArrayList();
        seriesList.addAll(series1, series2);

        return seriesList;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

CSS は参考資料 [1][2] を参考にして作成しました。

リスト:LineChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}


.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-series-line {
    -fx-stroke-width: 2px;
    -fx-effect: null;
}

.default-color0.chart-series-line { -fx-stroke: red; }
.default-color1.chart-series-line { -fx-stroke: blue; }

.default-color0.chart-line-symbol {
    -fx-background-color: red, #f88;
    -fx-background-radius: 6px;
    -fx-padding: 6px;
}
.default-color1.chart-line-symbol {
    -fx-background-color: blue, #88f;
    -fx-background-radius: 0;
    -fx-padding: 6px;
}

実行例を以下に示します。

プレゼンテーションに使用するグラフは、離れた人から見ても識別できるように、ややオーバー気味にフォントの大きさや、シンボル、ラインの色を選ぶようにしています。しかし、絶対的基準というものはありませんので、ご参考程度に。

CSS でチャートの要素の修飾を指定する方法は理解できますが、いまひとつしっくりきません。慣れが必要だと思われます。自分が慣れるためにいろいろなサンプルを紹介していきたいと思います。

参考サイト

  1. JavaFX CSS Reference Guide
  2. Using JavaFX Charts: Styling Charts with CSS | JavaFX 2 Tutorials and Documentation

2015-06-06

JavaFX: LineChart を使いこなそう (1)

JavaFX ではさまざまなチャートを利用できますが、私は思い存分に、というレベルまで細かい所を使いこなせていません。そこで簡単ないくつかのサンプルをベースにして少しずつ加工してみようと思います。まずは LineChart のベースサンプルを紹介します。参考サイト[1] を参考にしました。

動作環境は次の通りです。

  • OS: Fedora 22 x86_64
  • jdk1.8.0_45-1.8.0_45-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.0.2
リスト:LineChartSample.java 
package linechartsample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart Sample");

        //defining the axes
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();

        //creating the chart
        final LineChart lineChart = new LineChart(xAxis, yAxis);

        lineChart.setData(getChartData());
        lineChart.setTitle("折れ線グラフのサンプル");

        Scene scene = new Scene(lineChart, 600, 400);
        stage.setScene(scene);
        stage.show();
    }

    /**
     *
     * @return ObservableList<XYChart.Series<String, Double>>
     */
    private ObservableList<XYChart.Series<String, Double>> getChartData() {
        double y1 = 0.1;
        double y2 = -0.1;

        Series<String, Double> series1 = new Series<>();
        Series<String, Double> series2 = new Series<>();

        series1.setName("系列1");
        series2.setName("系列2");

        for (int i = 2011; i < 2021; i++) {
            series1.getData().add(new XYChart.Data(Integer.toString(i), y1));
            y1 = y1 + Math.random() - .5;

            series2.getData().add(new XYChart.Data(Integer.toString(i), y2));
            y2 = y2 + Math.random() - .5;
        }

        ObservableList<XYChart.Series<String, Double>> seriesList = FXCollections.observableArrayList();
        seriesList.addAll(series1, series2);

        return seriesList;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

実行例を以下に示します。

このチャートのままでは、プレゼン資料や論文に使えません。次回は、このサンプルをベースにして好きなように修飾してみようと思います。

参考サイト

  1. LineChart from ObservableList<XYChart.Series<String, Double>> : LineChart « JavaFX « Java