文档



JavaFX:使用JavaFX UI组件

33 面积图

本章介绍面积图,这是另一种二轴图表类型。

与折线图类似,它将数据呈现为一系列由直线连接的点。然而,轴和线之间的区域会被填充颜色。每个数据系列都会使用不同的颜色进行填充。图33-1显示了一个具有两个数据系列的面积图。

图33-1 典型的面积图

图33-1的描述如下
"图33-1 典型的面积图"的描述

创建面积图

要在应用程序中创建一个简单的面积图,至少需要定义两个轴,通过实例化AreaChart类创建AreaChart对象,使用XYChart.Series类创建一个或多个数据系列,并将数据分配给图表。

在实例化AreaChart类时,可以在构造函数中指定一个包含数据系列的可观察列表,或者通过在AreaChart对象上调用getDataaddAll方法稍后添加系列。

示例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)的数据。

使用getDataaddAll方法将数据系列分配给图表。因为最后添加的seriesMay数据,所以对应的绿色区域覆盖了显示四月数据的黄色区域。

编译和运行应用程序的结果如图33-2所示。

图33-2 带有两个数据系列的面积图

图33-2的描述如下
"图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-3的描述如下
"图33-3 堆叠面积图(带有两个区域)"的描述

图33-3中显示的数据与图33-2中的相同数据进行比较。堆叠面积图中的区域显示了沿水平轴的任意点上垂直轴上的累积值。例如,堆叠面积图中5月15日垂直轴上显示的值为36,这不对应于当天的实际温度。该值表示4月15日和5月15日的温度的累积结果。

在开发JavaFX应用程序中的面积图时,请记住垂直轴上的数据根据面积图的类型(AreaChartStackedAreaChart)进行解释。选择最适合应用程序任务的数据表示形式。

设置轴和刻度属性

温度监控应用程序的输出在图33-2图33-3中以默认的双精度格式呈现轴上的数值,而不是以用户友好的方式呈现。例如,月份应该是整数,范围在1到31之间,而不是浮点数。

JavaFX SDK API提供了几种方法来调整图表轴上呈现的值的外观。 图33-4显示了图表轴的主要元素,包括刻度线和刻度标签,用于指示范围的数值。

图33-4 轴的元素

图33-4的描述如下
"图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所示。

示例33-4 将次刻度线计数设置为零

xAxis.setMinorTickCount(0);

此属性定义每个主刻度线之间要显示的次刻度线的数量。通过将其值设置为0,您可以禁用水平轴上的次刻度线。

当您将来自示例33-3示例33-4的代码行添加到温度监控应用程序中时,水平轴将如图33-5所示发生变化。

图33-5 设置水平轴

图33-5的描述如下
"图33-5 设置水平轴"的描述

如果您的应用程序不需要显示刻度标签,请使用setTickLabelsVisible方法并将值设置为false。同样,如果您不希望刻度标记可见,请使用setTickMarkVisible方法并将值设置为false

使用示例33-5中显示的代码行来调整垂直轴的值范围。

示例33-5 指定垂直轴的数据范围

final NumberAxis yAxis = new NumberAxis(0, 27, 5);

您还可以调整刻度标记,使次要刻度标记和主要刻度标记具有相等的长度。使用示例33-6中显示的tickLengthminorTickLength属性。

示例33-6 调整主要和次要刻度标记的长度

yAxis.setMinorTickLength(yAxis.getTickLength());

当您将示例33-5示例33-6中的代码行添加到温度监控应用程序中时,垂直轴会发生变化,如图33-6所示。

图33-6 设置垂直轴

图33-6的描述如下
"图33-6 设置垂直轴"的描述

添加负值

由于温度监控应用程序中的垂直轴是使用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 添加负数据

图33-7的描述如下
"图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-9 将CSS样式应用于场景

scene.getStylesheets().add("areachartsample/Chart.css");

编译并运行此应用程序会产生修改后的面积图外观,如图33-8所示。

图33-8 样式化的面积图

图33-8的描述如下
"图33-8 样式化的面积图"的描述

您可以从使用CSS样式来为JavaFX应用程序设置图表样式了解更多信息。

相关API文档 

关闭窗口

目录

JavaFX:使用JavaFX UI组件

展开 折叠