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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | .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 ); } .series 0 .chart-bar { -fx- background-color : lightskyblue; } .default-color 0 .chart-series-line { -fx-stroke: #f44 ; } .default-color 0 .chart-line-symbol { -fx- background-color : #f44 , #f88 ; -fx-background-radius: 6px ; -fx- padding : 6px ; } |
リスト:BaseChart.css
1 2 3 | .chart-plot-background { -fx- background-color : white ; } |
0 件のコメント:
コメントを投稿