33 面积图
本章介绍面积图,这是另一种二轴图表类型。
与折线图类似,它将数据呈现为一系列由直线连接的点。然而,轴和线之间的区域会被填充颜色。每个数据系列都会使用不同的颜色进行填充。图33-1显示了一个具有两个数据系列的面积图。
创建面积图
要在应用程序中创建一个简单的面积图,至少需要定义两个轴,通过实例化AreaChart
类创建AreaChart
对象,使用XYChart.Series
类创建一个或多个数据系列,并将数据分配给图表。
在实例化AreaChart
类时,可以在构造函数中指定一个包含数据系列的可观察列表,或者通过在AreaChart
对象上调用getData
和addAll
方法稍后添加系列。
示例33-1创建了一个面积图来说明温度监测数据。该示例使用了四月和五月两个时间段收集的两个数据系列。
示例33-1 创建面积图
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.AreaChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class AreaChartSample extends Application { @Override public void start(Stage stage) { stage.setTitle("面积图示例"); final NumberAxis xAxis = new NumberAxis(1, 31, 1); final NumberAxis yAxis = new NumberAxis(); final AreaChart<Number,Number> ac = new AreaChart<>(xAxis,yAxis); ac.setTitle("温度监测(摄氏度)"); XYChart.Series seriesApril= new XYChart.Series(); seriesApril.setName("四月"); seriesApril.getData().add(new XYChart.Data(1, 4)); seriesApril.getData().add(new XYChart.Data(3, 10)); seriesApril.getData().add(new XYChart.Data(6, 15)); seriesApril.getData().add(new XYChart.Data(9, 8)); seriesApril.getData().add(new XYChart.Data(12, 5)); seriesApril.getData().add(new XYChart.Data(15, 18)); seriesApril.getData().add(new XYChart.Data(18, 15)); seriesApril.getData().add(new XYChart.Data(21, 13)); seriesApril.getData().add(new XYChart.Data(24, 19)); seriesApril.getData().add(new XYChart.Data(27, 21)); seriesApril.getData().add(new XYChart.Data(30, 21)); XYChart.Series seriesMay = new XYChart.Series(); seriesMay.setName("五月"); seriesMay.getData().add(new XYChart.Data(1, 20)); seriesMay.getData().add(new XYChart.Data(3, 15)); seriesMay.getData().add(new XYChart.Data(6, 13)); seriesMay.getData().add(new XYChart.Data(9, 12)); seriesMay.getData().add(new XYChart.Data(12, 14)); seriesMay.getData().add(new XYChart.Data(15, 18)); seriesMay.getData().add(new XYChart.Data(18, 25)); seriesMay.getData().add(new XYChart.Data(21, 25)); seriesMay.getData().add(new XYChart.Data(24, 23)); seriesMay.getData().add(new XYChart.Data(27, 26)); seriesMay.getData().add(new XYChart.Data(31, 26)); Scene scene = new Scene(ac,800,600); ac.getData().addAll(seriesApril, seriesMay); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
这个例子创建了两个NumberAxis
对象,用于在水平和垂直轴上呈现数值数据。水平轴(X)上的值从XYChart.Data
对象的第一个参数中获取,而第二个参数提供垂直轴(Y)的数据。
使用getData
和addAll
方法将数据系列分配给图表。因为最后添加的seriesMay
数据,所以对应的绿色区域覆盖了显示四月数据的黄色区域。
编译和运行应用程序的结果如图33-2所示。
创建堆叠面积图
您可以使用StackedAreaChart
类来表示面积图中的数据。该类构建的区域是堆叠的,因此每个系列相邻但不重叠。 示例33-2实现了这个任务。
示例33-2 创建堆叠面积图
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.StackedAreaChart; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class StackedAreaChartSample extends Application { final NumberAxis xAxis = new NumberAxis(1, 31, 1); final NumberAxis yAxis = new NumberAxis(); final StackedAreaChart<Number, Number> sac = new StackedAreaChart<>(xAxis, yAxis); @Override public void start(Stage stage) { stage.setTitle("面积图示例"); sac.setTitle("温度监测(摄氏度)"); XYChart.Series<Number, Number> seriesApril = new XYChart.Series<>(); seriesApril.setName("四月"); seriesApril.getData().add(new XYChart.Data(1, 4)); seriesApril.getData().add(new XYChart.Data(3, 10)); seriesApril.getData().add(new XYChart.Data(6, 15)); seriesApril.getData().add(new XYChart.Data(9, 8)); seriesApril.getData().add(new XYChart.Data(12, 5)); seriesApril.getData().add(new XYChart.Data(15, 18)); seriesApril.getData().add(new XYChart.Data(18, 15)); seriesApril.getData().add(new XYChart.Data(21, 13)); seriesApril.getData().add(new XYChart.Data(24, 19)); seriesApril.getData().add(new XYChart.Data(27, 21)); seriesApril.getData().add(new XYChart.Data(30, 21)); XYChart.Series<Number, Number> seriesMay = new XYChart.Series<>(); seriesMay.setName("五月"); seriesMay.getData().add(new XYChart.Data(1, 20)); seriesMay.getData().add(new XYChart.Data(3, 15)); seriesMay.getData().add(new XYChart.Data(6, 13)); seriesMay.getData().add(new XYChart.Data(9, 12)); seriesMay.getData().add(new XYChart.Data(12, 14)); seriesMay.getData().add(new XYChart.Data(15, 18)); seriesMay.getData().add(new XYChart.Data(18, 25)); seriesMay.getData().add(new XYChart.Data(21, 25)); seriesMay.getData().add(new XYChart.Data(24, 23)); seriesMay.getData().add(new XYChart.Data(27, 26)); seriesMay.getData().add(new XYChart.Data(31, 26)); Scene scene = new Scene(sac, 800, 600); sac.getData().addAll(seriesApril, seriesMay); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
当您编译和运行此应用程序时,它会创建如图33-3所示的图表。
将图33-3中显示的数据与图33-2中的相同数据进行比较。堆叠面积图中的区域显示了沿水平轴的任意点上垂直轴上的累积值。例如,堆叠面积图中5月15日垂直轴上显示的值为36,这不对应于当天的实际温度。该值表示4月15日和5月15日的温度的累积结果。
在开发JavaFX应用程序中的面积图时,请记住垂直轴上的数据根据面积图的类型(AreaChart
或StackedAreaChart
)进行解释。选择最适合应用程序任务的数据表示形式。
设置轴和刻度属性
温度监控应用程序的输出在图33-2和图33-3中以默认的双精度格式呈现轴上的数值,而不是以用户友好的方式呈现。例如,月份应该是整数,范围在1到31之间,而不是浮点数。
JavaFX SDK API提供了几种方法来调整图表轴上呈现的值的外观。 图33-4显示了图表轴的主要元素,包括刻度线和刻度标签,用于指示范围的数值。
您可以使用NumberAxis
类的构造函数或相应的方法来指定数值范围中的最小值和最大值,如示例33-3所示。
示例33-3 指定水平轴的数据范围
//使用NumberAxis构造函数 final NumberAxis xAxis = new NumberAxis(1, 31, 1); //使用相应的方法 xAxis.setLowerBound(1); xAxis.setUpperBound(31); xAxis.setTickUnit(1);
当使用NumberAxis
类的三个参数构造函数时,请记住第一个参数定义范围中的最小值,第二个参数是范围中的最大值,第三个参数定义刻度单位,即轴上两个刻度线之间的值。
此外,如果您想禁止在水平轴上显示次刻度线,则将minorTickCount
属性设置为0,如示例33-4所示。
此属性定义每个主刻度线之间要显示的次刻度线的数量。通过将其值设置为0,您可以禁用水平轴上的次刻度线。
当您将来自示例33-3和示例33-4的代码行添加到温度监控应用程序中时,水平轴将如图33-5所示发生变化。
如果您的应用程序不需要显示刻度标签,请使用setTickLabelsVisible
方法并将值设置为false
。同样,如果您不希望刻度标记可见,请使用setTickMarkVisible
方法并将值设置为false
。
使用示例33-5中显示的代码行来调整垂直轴的值范围。
您还可以调整刻度标记,使次要刻度标记和主要刻度标记具有相等的长度。使用示例33-6中显示的tickLength
和minorTickLength
属性。
添加负值
由于温度监控应用程序中的垂直轴是使用NumberAxis
类创建的,因此可以为面积图数据指定负值。
按照示例 33-7中所示创建另一个数据系列。
示例 33-7 添加一系列带有负值的数据
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.AreaChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class AreaChartSample extends Application { @Override public void start(Stage stage) { stage.setTitle("面积图示例"); final NumberAxis xAxis = new NumberAxis(1, 31, 1); xAxis.setMinorTickCount(0); final NumberAxis yAxis = new NumberAxis(-5, 27, 5); yAxis.setMinorTickLength(yAxis.getTickLength()); yAxis.setForceZeroInRange(false); final AreaChart<Number,Number> ac = new AreaChart<Number,Number>(xAxis,yAxis); ac.setTitle("温度监测(摄氏度)"); XYChart.Series seriesApril= new XYChart.Series(); seriesApril.setName("四月"); seriesApril.getData().add(new XYChart.Data(0, 4)); seriesApril.getData().add(new XYChart.Data(3, 10)); seriesApril.getData().add(new XYChart.Data(6, 15)); seriesApril.getData().add(new XYChart.Data(9, 8)); seriesApril.getData().add(new XYChart.Data(12, 5)); seriesApril.getData().add(new XYChart.Data(15, 18)); seriesApril.getData().add(new XYChart.Data(18, 15)); seriesApril.getData().add(new XYChart.Data(21, 13)); seriesApril.getData().add(new XYChart.Data(24, 19)); seriesApril.getData().add(new XYChart.Data(27, 21)); seriesApril.getData().add(new XYChart.Data(30, 21)); XYChart.Series seriesMay = new XYChart.Series(); seriesMay.setName("五月"); seriesMay.getData().add(new XYChart.Data(0, 20)); seriesMay.getData().add(new XYChart.Data(3, 15)); seriesMay.getData().add(new XYChart.Data(6, 13)); seriesMay.getData().add(new XYChart.Data(9, 12)); seriesMay.getData().add(new XYChart.Data(12, 14)); seriesMay.getData().add(new XYChart.Data(15, 18)); seriesMay.getData().add(new XYChart.Data(18, 25)); seriesMay.getData().add(new XYChart.Data(21, 25)); seriesMay.getData().add(new XYChart.Data(24, 23)); seriesMay.getData().add(new XYChart.Data(27, 26)); seriesMay.getData().add(new XYChart.Data(31, 26)); XYChart.Series seriesMarch = new XYChart.Series(); seriesMarch.setName("三月"); seriesMarch.getData().add(new XYChart.Data(0, -2)); seriesMarch.getData().add(new XYChart.Data(3, -4)); seriesMarch.getData().add(new XYChart.Data(6, 0)); seriesMarch.getData().add(new XYChart.Data(9, 5)); seriesMarch.getData().add(new XYChart.Data(12, -4)); seriesMarch.getData().add(new XYChart.Data(15, 6)); seriesMarch.getData().add(new XYChart.Data(18, 8)); seriesMarch.getData().add(new XYChart.Data(21, 14)); seriesMarch.getData().add(new XYChart.Data(24, 4)); seriesMarch.getData().add(new XYChart.Data(27, 6)); seriesMarch.getData().add(new XYChart.Data(31, 6)); Scene scene = new Scene(ac,800,600); ac.getData().addAll(seriesMarch, seriesApril, seriesMay); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
图33-7演示了修改后的温度监控应用程序,用于显示三个月的天气数据:三月、四月和五月。
样式化面积图
示例33-7中每个月的颜色是根据在addAll
方法中声明的相应数据系列的顺序来定义的。这就是为什么图33-7中的三月份面积是黄色的。您可以通过CSS设置AreaChart
对象的颜色。
创建Chart.css
文件,并将其保存在AreaChartSample
应用程序的主类所在的同一目录中。将示例33-8中显示的行添加到Chart.css
文件中。
示例33-8 面积图的CSS样式
.default-color0.chart-area-symbol { -fx-background-color: #e9967a, #ffa07a; } .default-color1.chart-area-symbol { -fx-background-color: #f0e68c, #fffacd; } .default-color2.chart-area-symbol { -fx-background-color: #dda0dd, #d8bfd855; } .default-color0.chart-series-area-line { -fx-stroke: #e9967a; } .default-color1.chart-series-area-line { -fx-stroke: #f0e68c; } .default-color2.chart-series-area-line { -fx-stroke: #dda0dd; } .default-color0.chart-series-area-fill { -fx-fill: #ffa07a55; } .default-color1.chart-series-area-fill { -fx-fill: #fffacd55; } .default-color2.chart-series-area-fill { -fx-fill: #d8bfd855; }
chart-area-symbol
CSS类定义了图表图例中特定数据系列的符号的参数。示例33-8设置了图表图例中圆圈的内部和外部颜色。
chart-series-area-line
CSS类设置了面积图线的参数。在这个例子中,设置了线条描边的颜色。chart-series-area-fill
CSS类定义了区域的颜色和不透明度级别。
通过使用Scene
类的getStylesheets()
方法,将这些样式应用于AreaChartSample
应用程序,如示例33-9所示。
编译并运行此应用程序会产生修改后的面积图外观,如图33-8所示。
您可以从使用CSS样式来为JavaFX应用程序设置图表样式了解更多信息。
相关API文档