35 散布図
この章では、一連のポイントとしてデータを表示する2軸チャートである、散布図について説明します。
各ポイントはX値およびY値によって定義されます。他の2軸チャートの場合と同様、データの系列を1つ以上作成できます。図35-1に、データの系列が3つある散布図を示します。
散布図の作成
散布図を作成するには、データの系列を少なくとも1つ定義し、横軸と縦軸を設定し、ScatterChart
クラスをインスタンス化してチャートを作成し、データをチャートに割り当てます。図35-1は、データの系列を2つ使用して簡単な散布図を作成する方法を示しています。
例35-1 データの系列を2つ使用した散布図
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.ScatterChart; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class ScatterChartSample extends Application { @Override public void start(Stage stage) { stage.setTitle("Scatter Chart Sample"); final NumberAxis xAxis = new NumberAxis(0, 10, 1); final NumberAxis yAxis = new NumberAxis(-100, 500, 100); final ScatterChart<Number,Number> sc = new ScatterChart<>(xAxis,yAxis); xAxis.setLabel("Age (years)"); yAxis.setLabel("Returns to date"); sc.setTitle("Investment Overview"); XYChart.Series series1 = new XYChart.Series(); series1.setName("Equities"); series1.getData().add(new XYChart.Data(4.2, 193.2)); series1.getData().add(new XYChart.Data(2.8, 33.6)); series1.getData().add(new XYChart.Data(6.2, 24.8)); series1.getData().add(new XYChart.Data(1, 14)); series1.getData().add(new XYChart.Data(1.2, 26.4)); series1.getData().add(new XYChart.Data(4.4, 114.4)); series1.getData().add(new XYChart.Data(8.5, 323)); series1.getData().add(new XYChart.Data(6.9, 289.8)); series1.getData().add(new XYChart.Data(9.9, 287.1)); series1.getData().add(new XYChart.Data(0.9, -9)); series1.getData().add(new XYChart.Data(3.2, 150.8)); series1.getData().add(new XYChart.Data(4.8, 20.8)); series1.getData().add(new XYChart.Data(7.3, -42.3)); series1.getData().add(new XYChart.Data(1.8, 81.4)); series1.getData().add(new XYChart.Data(7.3, 110.3)); series1.getData().add(new XYChart.Data(2.7, 41.2)); XYChart.Series series2 = new XYChart.Series(); series2.setName("Mutual funds"); series2.getData().add(new XYChart.Data(5.2, 229.2)); series2.getData().add(new XYChart.Data(2.4, 37.6)); series2.getData().add(new XYChart.Data(3.2, 49.8)); series2.getData().add(new XYChart.Data(1.8, 134)); series2.getData().add(new XYChart.Data(3.2, 236.2)); series2.getData().add(new XYChart.Data(7.4, 114.1)); series2.getData().add(new XYChart.Data(3.5, 323)); series2.getData().add(new XYChart.Data(9.3, 29.9)); series2.getData().add(new XYChart.Data(8.1, 287.4)); sc.getData().addAll(series1, series2); Scene scene = new Scene(sc, 500, 400); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
この例では、年度と収益額の数値データを表すために2つのNumber
軸を使用してScatterChart
オブジェクトを作成しています。データの範囲とティック単位は、NumberAxis
クラスのコンストラクタ内で定義されています。
このアプリケーションをコンパイルして実行した結果を図35-2に示します。
グラフ・データの管理
例35-1では、データがアプリケーションにコーディングされていてユーザー・インタフェースから変更できない散布図を作成しています。データの系列の追加や削除など、チャートによって表される一連のデータを管理するには、アプリケーションでUIコントロールを使用します。
例35-2に示すコードについて考えてみましょう。これにより、一連のデータを変更するための「Add Series」および「Remove Series」の2つのボタンが作成されます。
例35-2 ボタンを使用したグラフ・データの管理
import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.ScatterChart; import javafx.scene.chart.XYChart; import javafx.scene.control.Button; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class ScatterChartSample extends Application { @Override public void start(Stage stage) { stage.setTitle("Scatter Chart Sample"); final NumberAxis xAxis = new NumberAxis(0, 10, 1); final NumberAxis yAxis = new NumberAxis(-100, 500, 100); final ScatterChart<Number,Number> sc = new ScatterChart<>(xAxis,yAxis); xAxis.setLabel("Age (years)"); yAxis.setLabel("Returns to date"); sc.setTitle("Investment Overview"); XYChart.Series series1 = new XYChart.Series(); series1.setName("Option 1"); series1.getData().add(new XYChart.Data(4.2, 193.2)); series1.getData().add(new XYChart.Data(2.8, 33.6)); series1.getData().add(new XYChart.Data(6.2, 24.8)); series1.getData().add(new XYChart.Data(1, 14)); series1.getData().add(new XYChart.Data(1.2, 26.4)); series1.getData().add(new XYChart.Data(4.4, 114.4)); series1.getData().add(new XYChart.Data(8.5, 323)); series1.getData().add(new XYChart.Data(6.9, 289.8)); series1.getData().add(new XYChart.Data(9.9, 287.1)); series1.getData().add(new XYChart.Data(0.9, -9)); series1.getData().add(new XYChart.Data(3.2, 150.8)); series1.getData().add(new XYChart.Data(4.8, 20.8)); series1.getData().add(new XYChart.Data(7.3, -42.3)); series1.getData().add(new XYChart.Data(1.8, 81.4)); series1.getData().add(new XYChart.Data(7.3, 110.3)); series1.getData().add(new XYChart.Data(2.7, 41.2)); sc.setPrefSize(500, 400); sc.getData().addAll(series1); Scene scene = new Scene(new Group()); final VBox vbox = new VBox(); final HBox hbox = new HBox(); final Button add = new Button("Add Series"); final Button remove = new Button("Remove Series"); hbox.setSpacing(10); hbox.getChildren().addAll(add, remove); vbox.getChildren().addAll(sc, hbox); hbox.setPadding(new Insets(10, 10, 10, 50)); ((Group)scene.getRoot()).getChildren().add(vbox); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
例35-1では散布図をシーンに直接追加していますが、例35-2ではVBox
およびHBox
レイアウト・コンテナを使用してアプリケーション・シーン内にコンポーネントを配置しています。
例35-3に示すように、「Add Series」ボタンのsetOnAction
メソッドを定義します。これにより、ランダムに計算された値をXYChart.Series
オブジェクトに移入することにより、新しいデータの系列が作成されます。新しい各系列は、add(series)
メソッドを使用してグラフに割り当てられています。
例35-3 データの系列の追加
add.setOnAction((ActionEvent e) -> { if (sc.getData() == null) { sc.setData(FXCollections.<XYChart.Series<Number, Number>>observableArrayList()); } ScatterChart.Series<Number, Number> series = new ScatterChart.Series<>(); series.setName("Option " + (sc.getData().size() + 1)); for (int i = 0; i < 100; i++) { series.getData().add( new ScatterChart.Data<>(Math.random() * 100, Math.random() * 500)); } sc.getData().add(series); });
グラフからデータの系列を削除するには、例35-4に示すように、「Remove Series」ボタンのsetOnAction
メソッドを定義します。散布図でコールされたremove(int)
メソッドにより、ランダムに生成された索引を使用してデータの系列が削除されます。
例35-4 データの系列の削除
remove.setOnAction((ActionEvent e) -> { if (!sc.getData().isEmpty()) sc.getData().remove((int)( Math.random()*(sc.getData().size()-1))); });
例35-3および例35-4を例35-2のアプリケーションに追加すると、図35-3に示す出力が表示されます。これは、「Option 1」系列に5つの系列を追加した瞬間を捉えています。
データの系列を示すために使用される記号は、ScatterChart
クラスの実装にコーディングされています。例35-5に、散布図記号の1つのデフォルトのスタイルを示します。
例35-5 ScatterChart記号のスタイル設定
.default-color5.chart-symbol { /* hollow circle */ -fx-background-color: #860061, white; -fx-background-insets: 0, 2; -fx-background-radius: 5px; -fx-padding: 5px; }
.default-color5.chart-symbol
プロパティに代替値を設定することにより、この記号のスタイルを変更できます。詳細は、「CSSによるチャートのスタイル設定」を参照してください。
チャートへの効果の追加
javafx.scene.chart
内で使用可能なチャート・クラスはすべて、Node
クラスの拡張です。したがって、すべてのタイプのグラフに対して視覚効果または変換を適用できます。例35-6のコード・フラグメントを確認してください。ここでは、ドロップ・シャドウ効果を作成して散布図に適用しています。
例35-6 ドロップ・シャドウの作成および適用
final DropShadow shadow = new DropShadow(); shadow.setOffsetX(2); shadow.setColor(Color.GREY); sc.setEffect(shadow);
このコード・フラグメントを「Investment Overview」アプリケーションに追加し、コンパイルして実行すると、図35-4に示すように、散布図がシャドウによって強調表示されます。
ドロップ・シャドウの視覚効果はグラフのすべての要素(軸、ティック・マークおよびティック・ラベルを含む)に適用されていることに注意してください。
チャート記号の変更
散布図の各データ系列は、JavaFXアプリケーションのデフォルトのスタイル・シートであるmodena.css
に定義されている記号によって表されます。ただし、独自のスタイル・シートを実装することによってチャート記号は変更できます。
Chart.css
ファイルを作成し、AreaChartSample
アプリケーションのメイン・クラスと同じディレクトリに保存します。例35-7に示す行をChart.css
ファイルに追加します。
例35-7 CSSによる新しいチャート記号の作成
.chart-symbol{ -fx-stroke: #a9e200; -fx-shape: "M0,4 L2,4 L4,8 L7,0 L9,0 L4,11 Z"; }
このコード・フラグメントでは、-fx-shape
パラメータにSVGパスを定義することによって記号の形状を作成し、記号の描画色を設定しています。
アプリケーションにスタイル・シートを適用するには、図35-8に示すように、Scene
クラスのgetStylesheets()
メソッドを使用します。
このアプリケーションをコンパイルして実行すると、図35-5に示すように、変更された面グラフの外観が生成されます。
JavaFXアプリケーションでのCSSスタイルの使用の詳細は、「CSSによるチャートのスタイル設定」および「CSSによるUIコントロールのスタイル設定」を参照してください。
関連APIドキュメント