JavaFX で棒グラフ (BarChart) と折れ線グラフ (LineChart) を合わせて表示したい場合、StackPane を用いてそれぞれを重ねて表示することで簡単に実現できます。Jewelsea (John Smith) 氏が GitHub Gist でサンプルを公開していますので、その実行例を紹介します [1]。
動作を確認した環境は次の通りです。
- OS: Fedora 23 (x86_64)
- Java: Java SE 1.8.0_72 (jdk1.8.0_72-1.8.0_72-fcs.x86_64)
- IDE: NetBeans IDE 8.1
パレート図(もどき)への応用
StackPane を用いたチャートの重ね合わせを応用して、BarChart の y 軸が 左側、LineChart の y 軸が右側にあるパレート図を描画するサンプルを紹介します。ただし、QC七つ道具のパレート図で定義されている累積比率の折れ線と、プロットの仕方が異なっていることをご了承ください [2]。
とある会社で品証部門に在籍していたことがあり、そこには日本の品質管理の手法を大切にする気風がありました。何かの時に R で作成したパレート図を自慢気に披露したところ、これはパレート図ではない、と指摘されて赤面したことがあるのです。それが、ここで紹介するパレート図と同じ書き方でしたので、自戒をこめて(もどき)と入れています。個人的には、定義から逸れているからダメだという議論より、このチャートから何を読み取るべきかが大切だとは思うのですが、間違いを間違いだと認めなければなりません。
リスト:Sample_Pareto.java
package sample_pareto;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Sample_Pareto extends Application {
Boolean first = true;
BarChart<String, Number> barchart;
LineChart<String, Number> linechart;
// X data
String category1 = "A";
String category2 = "B";
String category3 = "C";
String category4 = "D";
String category5 = "E";
String category6 = "Others";
// Y data
ObservableList<XYChart.Data> data1 = FXCollections.observableArrayList(
new XYChart.Data(category1, 34),
new XYChart.Data(category2, 19),
new XYChart.Data(category3, 12),
new XYChart.Data(category4, 9),
new XYChart.Data(category5, 6),
new XYChart.Data(category6, 10)
);
// Y2 data
ObservableList<XYChart.Data> data2 = FXCollections.observableArrayList(
new XYChart.Data(category1, 37.8),
new XYChart.Data(category2, 58.9),
new XYChart.Data(category3, 72.2),
new XYChart.Data(category4, 82.2),
new XYChart.Data(category5, 88.9),
new XYChart.Data(category6, 100.0)
);
// chart title
String gTitle = "パレート図のサンプル ";
String gXTitle = "カテゴリ";
String gYTitle = "件 数";
String gY2Title = "累積比率 (%)";
// geometry
double sizeX = 600;
double sizeY = 500;
double offsetX = 60;
@Override
public void start(Stage stage) {
// X axis
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel(gXTitle);
// barchart
barchart = createBarChart(xAxis, data1);
barchart.setTitle(""); // ダミー
barchart.getStylesheets().addAll(getClass().getResource("BaseChart.css").toExternalForm());
// linechart
linechart = createLineChart(xAxis, data2);
linechart.setTitle(gTitle);
// set chart width
updateChartWidth();
// stackpane for overlay
StackPane pane = new StackPane();
pane.getChildren().addAll(barchart, linechart);
pane.setAlignment(Pos.BOTTOM_LEFT);
Scene scene = new Scene(pane, sizeX, sizeY);
scene.widthProperty().addListener(
(ObservableValue<? extends Number> observableValue, Number oldSceneWidth, Number newSceneWidth) -> {
if (!first) {
sizeX = (double) newSceneWidth;
updateChartWidth();
} else {
first = false;
}
}
);
scene.getStylesheets().add(getClass().getResource("ParetoChart.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
BarChart<String, Number> createBarChart(CategoryAxis xAxis, ObservableList<XYChart.Data> data) {
NumberAxis yAxis = createYaxis(0, 90, 10, 5);
yAxis.setLabel(gYTitle);
BarChart<String, Number> chart = new BarChart<>(xAxis, yAxis);
chart.setLegendVisible(false);
XYChart.Series series = new XYChart.Series(data);
series.setName("カテゴリ");
chart.getData().add(series);
return chart;
}
LineChart<String, Number> createLineChart(CategoryAxis xAxis, ObservableList<XYChart.Data> data) {
NumberAxis y2Axis = createYaxis(0, 100, 10, 2);
y2Axis.setSide(Side.RIGHT);
y2Axis.setLabel(gY2Title);
LineChart<String, Number> chart = new LineChart<>(xAxis, y2Axis);
chart.setLegendVisible(false);
chart.setHorizontalGridLinesVisible(false);
chart.setVerticalGridLinesVisible(false);
XYChart.Series series = new XYChart.Series(data);
series.setName("累積");
chart.getData().add(series);
return chart;
}
NumberAxis createYaxis(double min, double max, int major, int minor) {
final NumberAxis axis = new NumberAxis(min, max, major);
axis.setMinorTickCount(minor);
axis.setPrefWidth(offsetX);
return axis;
}
void updateChartWidth() {
barchart.setLayoutX(0);
barchart.setTranslateX(0);
barchart.setMaxWidth(sizeX - offsetX);
linechart.setLayoutX(0);
linechart.setTranslateX(offsetX);
linechart.setMaxWidth(sizeX - offsetX);
}
public static void main(String[] args) {
launch(args);
}
}
リスト:ParetoChart.css
.chart {
-fx-padding: 10px;
}
.chart-content {
-fx-padding: 10px;
}
.chart-title {
-fx-font-size: 16pt;
}
.chart-plot-background {
-fx-background-color: transparent;
}
.axis-label {
-fx-font-size: 14pt;
}
.axis {
AXIS_COLOR: #888;
-fx-tick-label-font: 12pt system;
-fx-tick-label-fill: derive(-fx-text-background-color, 30%);
}
.chart-bar {
-fx-border-color: rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4) transparent rgba(0, 0, 0, 0.4);
}
.series0.chart-bar {
-fx-background-color: lightskyblue;
}
.default-color0.chart-series-line {
-fx-stroke: #f44;
}
.default-color0.chart-line-symbol {
-fx-background-color: #f44, #f88;
-fx-background-radius: 6px;
-fx-padding: 6px;
}
リスト:BaseChart.css
.chart-plot-background {
-fx-background-color: white;
}
実行例
参考サイト
- Uses JavaFX to draw layers of XYCharts.
- (株)日科技研:パレート図とは(QC七つ道具)|製品案内
0 件のコメント:
コメントを投稿