35 散点图
本章介绍散点图,它是一个二维坐标图,将数据呈现为一组点。
每个点由X和Y值定义。与其他二维坐标图一样,您可以创建一个或多个数据系列。 图35-1展示了一个包含三个数据系列的散点图。
创建散点图
要创建散点图,需要定义至少一个数据系列,设置水平和垂直轴,通过实例化ScatterChart
类来创建图表,并将数据分配给图表。示例35-1演示了如何创建一个包含两个数据系列的简单散点图。
示例35-1 包含两个数据系列的散点图
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("散点图示例"); 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("年龄(岁)"); yAxis.setLabel("累计回报"); sc.setTitle("投资概览"); XYChart.Series series1 = new XYChart.Series(); series1.setName("股票"); 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("共同基金"); 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); } }
在这个例子中,ScatterChart
对象使用两个Number
轴来展示年份和回报金额的数值数据。数据的范围和刻度单位在NumberAxis
类的构造函数中定义。
编译和运行这个应用程序的结果如图35-2所示。
管理图表数据
示例35-1创建了一个散点图,其数据被编码到应用程序中,无法从用户界面更改。在应用程序中使用UI控件来管理图表呈现的数据集,例如添加和删除一系列数据。
查看示例35-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("散点图示例"); 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("年龄(岁)"); yAxis.setLabel("累计回报"); sc.setTitle("投资概览"); XYChart.Series series1 = new XYChart.Series(); series1.setName("选项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("添加系列"); final Button remove = new Button("删除系列"); 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所示,为“添加系列”按钮定义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("选项 " + (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所示,为“删除系列”按钮定义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中的输出。它捕捉了将五个系列添加到“选项1”系列的时刻。
用于表示一系列数据的符号被编码到ScatterChart
类的实现中。 示例35-5显示了散点图符号的默认样式。
示例35-5 设置散点图符号的样式
.default-color5.chart-symbol { /* 空心圆 */ -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);
当您将此代码片段添加到投资概览应用程序中,然后编译并运行它,散点图将被阴影突出显示,如图35-4所示。
请注意,投影的视觉效果应用于图表的所有元素,包括轴、刻度线和刻度标签。
更改图表符号
散点图中的每个数据系列都由modena.css
中定义的符号表示,这是JavaFX应用程序的默认样式表。但是,您可以通过实现自己的样式表来更改图表符号。
创建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路径来创建符号形状,并为符号设置描边颜色。
使用Scene
类的getStylesheets()
方法将样式表应用于应用程序,如示例35-8所示。
编译并运行此应用程序将产生修改后的面积图的外观,如图35-5所示。
您可以从使用CSS样式的JavaFX应用程序和使用CSS样式的UI控件中了解更多关于在JavaFX应用程序中使用CSS样式的信息。
相关API文档