JavaFX の BarChart を試してみた

このところ JavaFX の学習をさぼっていたので(マイペースともいう)標準装備された Chart をいじってみることにした。

今回も ITPro の「JavaFX 2で始めるGUI開発 第10回 組み込みブラウザとチャート」を参考にさせてもらいました。

実はこちらの記事では Scene Builder を使っているサンプルはなかったので Scene Builder を使って創りはじめました。

スタイルの設定も簡単にできるんだろうなと甘い考えを持っていました。

結果をいうと恥ずかしながら撃沈です。(>_<。)

Scene Builder を使えばスタイルの設定が簡単にできるだろうと思っていたが使い方が解らなかった!

ネット上にサンプルがあるだろうと随分ググったけど見つけられなかった。

結局、Scene Builder 使って簡単にというのは幻となってしまった。

結局、ほとんど ITPro のサンプルまんまになってしまった。

選択した Chart が BarChart だということくらいしかないな・・・

せめて Chart 用のデータを創ってるクラスが Java 8 ならではの機能を利用しているから許してね!

そう言うことで Chart について知りたい方は ITPro の記事を読んでくださいね。

流れ的には X 軸、Y 軸を設定して、それを引数にとった Chart を作る。

BarChart<String, Number> ramdomNumberBarChart = new BarChart<>(xAxis, yAxis);

そして作った Chart にデータを読み込ませるって感じです。

肝心なところはデータを読み込ませるところですね。

このプログラムでは

XYChart.Series<String, Number> ramdomGaussian = new XYChart.Series<>();

IntStream.rangeClosed(0, 9).forEach(i -> {
            ramdomGaussian.getData().add(new XYChart.Data<>(String.valueOf(i), ramdomGaussianGenerator.counter.getOrDefault(i, 0L)));
        });

ramdomNumberBarChart.getData().add(ramdomGaussian);

としてます。

ガウス分布乱数の 0 から 9 のそれぞれの個数を BarChart にセットしました。

おっと、このプログラムの概要を説明するのを忘れてましたね。

大まかにザックリ説明するとガウス分布乱数を作り、それをもとに 0 から 9 の整数だけを 100 万個作る。

そして、それをそれぞれいくつあるかカウントして Map<Integer, Long> で保持する。

つくったガウス分布乱数 Map<Integer, Long> を 0 から 9 の BarChart として表示させる。

右肩下がりの BarChart が表示されればおそらく間違ってはないだろう。

それではツッコミどころはあるけどプログラムのソースを載せます。それはいろいろ試していたと言うことで笑ってください。

package jp.yucchi.randomnumber4gaussiandistribution;

import java.security.SecureRandom;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author Yucchi
 */
public class RamdomGaussianGenerator {

    Random random = new SecureRandom();

    Map counter = Stream.generate(random::nextGaussian)
            .mapToDouble(e -> e)
            .filter(e -> (e >= 0.0 && e < 1.0))
            .mapToInt(e -> (int) (e * 10))
            .limit(1_000_000)
            .boxed()
            .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
}
package jp.yucchi.randomnumber4gaussiandistribution;

import java.util.stream.IntStream;
import javafx.application.Application;
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.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 *
 * @author Yucchi
 */
public class RandomNumber4GaussianDistribution extends Application {

    @Override
    public void start(Stage primaryStage) {

        RamdomGaussianGenerator ramdomGaussianGenerator = new RamdomGaussianGenerator();

        StackPane root = new StackPane();

        CategoryAxis xAxis = new CategoryAxis();
        xAxis.setLabel("RandomNumber");
        NumberAxis yAxis = new NumberAxis();
        yAxis.setLabel("Count");

        BarChart ramdomNumberBarChart = new BarChart<>(xAxis, yAxis);
        ramdomNumberBarChart.setTitle("Gaussian RandomNumber");
        root.getChildren().add(ramdomNumberBarChart);
        XYChart.Series ramdomGaussian = new XYChart.Series<>();
        ramdomGaussian.setName("Gaussian distribution");

        IntStream.rangeClosed(0, 9).forEach(i -> {
            ramdomGaussian.getData().add(new XYChart.Data<>(String.valueOf(i), ramdomGaussianGenerator.counter.getOrDefault(i, 0L)));
        });

        ramdomNumberBarChart.getData().add(ramdomGaussian);

        Scene scene = new Scene(root, 800, 500);
        scene.getStylesheets().add(this.getClass().getResource("chart.css").toExternalForm());
        Image myIcon = new Image(this.getClass().getResource("cludia_icon.png").toString());
        primaryStage.getIcons().add(myIcon);
        primaryStage.setTitle("RandomNumber4GaussianDistribution");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

.chart {
     -fx-background-image: url("icon.gif");
}

.chart-legend {
   -fx-background-color:  transparent;
}
 
.chart-legend-item-symbol{
   -fx-background-radius: 0;
}
 
.chart-legend-item{
    -fx-text-fill: #191970;
}

.chart-title {
  -fx-text-fill: #4682b4;
  -fx-font-size: 1.6em;
}
 
.axis-label {
  -fx-text-fill: #4682b4;
}

.chart-bar {
    -fx-bar-fill: #C2EEFF;
}

/*.data0.chart-bar {
    -fx-background-color: #ff7fbf;
}
.data1.chart-bar {
    -fx-background-color: #ff7fff;
}
.data2.chart-bar {
    -fx-background-color: #bf7fff;
}
.data3.chart-bar {
    -fx-background-color: #7f7fff;
}
.data4.chart-bar {
    -fx-background-color: #7fbfff;
}
.data5.chart-bar {
    -fx-background-color: #7fffff;
}
.data6.chart-bar {
    -fx-background-color: #7fffbf;
}
.data7.chart-bar {
    -fx-background-color: #bfff7f;
}
.data8.chart-bar {
    -fx-background-color: #bfff7f;
}
.data9.chart-bar {
    -fx-background-color: #ffff7f;
}*/

 

実行結果は次のようになります。

1

 

スタイルシートを使わない素の状態は次のようになります。

2

 

どちらにしろ右肩下がりの BarChart が表示されました。

めでたし!めでたし! (^_^)

後は、Scene Builder からスタイルの設定を簡単にする方法があればそれも試してみたい。

結局、CSS ファイルをコード側から読み込ませては意味ないし、Java 8 がリリースされたら JavaFX でプログラム組む人も増えるだろうからそのうち GOOD な情報を入手できるだろう。

いずれにしろ、JavaFX はスタイルシート使えるからプログラムの見栄えもガラッと変わってしまう。

デザインセンスのある人が使えば強力な武器となることは間違いない!

残念ながら私はデザインセンスは標準装備されてもないしオプション設定もないので泣きたくなります。

今回、Chart 関連の CSS の設定についてググってみても日本語ではあまり情報がなかった。

参考までに

JavaFX CSS Reference Guide

サンプルは無いし、英語なので泣きたくなります。(>_<。)

外国語での情報も少なかった。

これもそのうち情報が増えてくるのをゆっくりと待つとしよう。

マイペースでお気楽に楽しんでが私のモットーなので今日はここまでできた自分を褒めてあげよう!

Hatena タグ:

Java 8 での算術オーバーフロー

Java 8 では算術オーバーフローを検出可能となるよっておはなしです。

Math クラスに算術オーバーフローを検出できるメソッドが追加されました。

ちょっとしたサンプルプログラムをのせておきます。


package jp.yucchi.exact;

/**
 *
 * @author Yucchi
 */
public class Exact {

    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE + 1);
        System.out.println(Integer.MIN_VALUE - 1);
        try {
            System.out.println(Math.addExact(Integer.MAX_VALUE, 1));
        } catch (ArithmeticException ae) {
            // G'catch! :p
            ae.printStackTrace();
        }
        try {
            System.out.println(Math.subtractExact(Integer.MIN_VALUE, 1));
        } catch (ArithmeticException ae) {
            // G'catch! :p
            ae.printStackTrace();
        }  
    }
}

実行結果は次の通りになります。

-2147483648
2147483647
java.lang.ArithmeticException: integer overflow
at java.lang.Math.addExact(Math.java:790)
at jp.yucchi.exact.Exact.main(Exact.java:14)
java.lang.ArithmeticException: integer overflow
at java.lang.Math.subtractExact(Math.java:829)
at jp.yucchi.exact.Exact.main(Exact.java:20)

この他にも Java 8 で追加された便利なものがありますので興味のある方は API ドキュメントに目を通してみるといいですよ!

Hatena タグ: