文档



JavaFX:使用JavaFX UI组件

36 柱状图

本章介绍柱状图,它是一个具有矩形柱的两轴图表,可以是垂直或水平的。

每个柱的长度与图表所表示的特定值成比例。通常,柱状图用于显示离散数据。您可以使用柱状图的组作为类别来绘制数据,如图36-1所示。

图36-1 示例柱状图

图36-1的描述如下
"图36-1 示例柱状图"的描述

创建柱状图

在JavaFX应用程序中创建柱状图,需要创建两个轴,实例化BarChar类,定义数据系列,并将数据分配给图表。示例36-1创建了一个柱状图,用于展示关于五个国家的财务信息的三个数据系列。每个国家都被呈现为一个类别,即水平轴上的一组柱状图。

示例36-1 创建一个包含三个数据系列的柱状图

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
 
public class BarChartSample extends Application {
    final static String austria = "奥地利";
    final static String brazil = "巴西";
    final static String france = "法国";
    final static String italy = "意大利";
    final static String usa = "美国";
 
    @Override public void start(Stage stage) {
        stage.setTitle("柱状图示例");
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        final BarChart<String,Number> bc = 
            new BarChart<>(xAxis,yAxis);
        bc.setTitle("国家概况");
        xAxis.setLabel("国家");       
        yAxis.setLabel("数值");
 
        XYChart.Series series1 = new XYChart.Series();
        series1.setName("2003");       
        series1.getData().add(new XYChart.Data(austria, 25601.34));
        series1.getData().add(new XYChart.Data(brazil, 20148.82));
        series1.getData().add(new XYChart.Data(france, 10000));
        series1.getData().add(new XYChart.Data(italy, 35407.15));
        series1.getData().add(new XYChart.Data(usa, 12000));      
        
        XYChart.Series series2 = new XYChart.Series();
        series2.setName("2004");
        series2.getData().add(new XYChart.Data(austria, 57401.85));
        series2.getData().add(new XYChart.Data(brazil, 41941.19));
        series2.getData().add(new XYChart.Data(france, 45263.37));
        series2.getData().add(new XYChart.Data(italy, 117320.16));
        series2.getData().add(new XYChart.Data(usa, 14845.27));  
        
        XYChart.Series series3 = new XYChart.Series();
        series3.setName("2005");
        series3.getData().add(new XYChart.Data(austria, 45000.65));
        series3.getData().add(new XYChart.Data(brazil, 44835.76));
        series3.getData().add(new XYChart.Data(france, 18722.18));
        series3.getData().add(new XYChart.Data(italy, 17557.31));
        series3.getData().add(new XYChart.Data(usa, 92633.68));  
        
        Scene scene  = new Scene(bc,800,600);
        bc.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

图36-2显示了在编译和运行此应用程序时的预期输出。

图36-2 创建一个包含三个数据系列的柱状图

图36-2的描述如下
"图36-2 创建一个包含三个数据系列的柱状图"的描述

BarChart类的两个属性可以管理数据类别之间的间距以及同一类别中的柱状图之间的间距。使用barGapcategoryGap属性来更好地分布图表中的柱状图。示例36-2使用setBarGapsetCategoryGap方法为这些属性设置特定值。

示例36-2 设置柱状图和类别之间的间距

bc.setBarGap(3);
bc.setCategoryGap(20);

水平柱状图

您可以通过为垂直轴定义类别来将柱状图的方向从垂直变为水平。在Country Summary应用程序中,示例36-3实现了这一点。声明NumberAxis类型的水平轴和CategoryAxis类型的垂直轴。不要忘记修改BarChart对象的声明。

示例36-3 改变柱状图的方向

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
 
public class BarChartSample extends Application {
    final static String austria = "奥地利";
    final static String brazil = "巴西";
    final static String france = "法国";
    final static String italy = "意大利";
    final static String usa = "美国";
 
    @Override public void start(Stage stage) {
        stage.setTitle("柱状图示例");
        final NumberAxis xAxis = new NumberAxis();
        final CategoryAxis yAxis = new CategoryAxis();
        final BarChart<Number,String> bc = 
            new BarChart<>(xAxis,yAxis);
        bc.setTitle("国家摘要");
        xAxis.setLabel("值");  
        xAxis.setTickLabelRotation(90);
        yAxis.setLabel("国家");        
 
        XYChart.Series series1 = new XYChart.Series();
        series1.setName("2003");       
        series1.getData().add(new XYChart.Data(25601.34, austria));
        series1.getData().add(new XYChart.Data(20148.82, brazil));
        series1.getData().add(new XYChart.Data(10000, france));
        series1.getData().add(new XYChart.Data(35407.15, italy));
        series1.getData().add(new XYChart.Data(12000, usa));      
        
        XYChart.Series series2 = new XYChart.Series();
        series2.setName("2004");
        series2.getData().add(new XYChart.Data(57401.85, austria));
        series2.getData().add(new XYChart.Data(41941.19, brazil));
        series2.getData().add(new XYChart.Data(45263.37, france));
        series2.getData().add(new XYChart.Data(117320.16, italy));
        series2.getData().add(new XYChart.Data(14845.27, usa));  
        
        XYChart.Series series3 = new XYChart.Series();
        series3.setName("2005");
        series3.getData().add(new XYChart.Data(45000.65, austria));
        series3.getData().add(new XYChart.Data(44835.76, brazil));
        series3.getData().add(new XYChart.Data(18722.18, france));
        series3.getData().add(new XYChart.Data(17557.31, italy));
        series3.getData().add(new XYChart.Data(92633.68, usa));  
        
        Scene scene  = new Scene(bc,800,600);
        bc.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

请注意,在水平轴上调用setTickLabelRotation方法来旋转标签,使值的标题更易读。

编译和运行修改后的应用程序的结果如图36-3所示。

图36-3 水平条形图

图36-3的描述如下
"图36-3 水平条形图"的描述

当您想将数据表示为排名列表时,水平条形图特别有帮助。

创建堆叠柱状图

您可以使用柱状图来表示堆叠在一个类别中的数据。使用JavaFX API中提供的StackedBarChart类,如示例36-4所示。

示例36-4 创建堆叠柱状图

import java.util.Arrays;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
 
public class StackedBarChartSample extends Application {
 
    final static String austria = "奥地利";
    final static String brazil = "巴西";
    final static String france = "法国";
    final static String italy = "意大利";
    final static String usa = "美国";
    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final StackedBarChart<String, Number> sbc =
            new StackedBarChart<>(xAxis, yAxis);
    final XYChart.Series<String, Number> series1 =
            new XYChart.Series<>();
    final XYChart.Series<String, Number> series2 =
            new XYChart.Series<>();
    final XYChart.Series<String, Number> series3 =
            new XYChart.Series<>();
 
    @Override
    public void start(Stage stage) {
        stage.setTitle("柱状图示例");
        sbc.setTitle("国家摘要");
        xAxis.setLabel("国家");
        xAxis.setCategories(FXCollections.<String>observableArrayList(
                Arrays.asList(austria, brazil, france, italy, usa)));
        yAxis.setLabel("值");
        series1.setName("2003");
        series1.getData().add(new XYChart.Data<>(austria, 25601.34));
        series1.getData().add(new XYChart.Data<>(brazil, 20148.82));
        series1.getData().add(new XYChart.Data<>(france, 10000));
        series1.getData().add(new XYChart.Data<>(italy, 35407.15));
        series1.getData().add(new XYChart.Data<>(usa, 12000));
        series2.setName("2004");
        series2.getData().add(new XYChart.Data<>(austria, 57401.85));
        series2.getData().add(new XYChart.Data<>(brazil, 41941.19));
        series2.getData().add(new XYChart.Data<>(france, 45263.37));
        series2.getData().add(new XYChart.Data<>(italy, 117320.16));
        series2.getData().add(new XYChart.Data<>(usa, 14845.27));
        series3.setName("2005");
        series3.getData().add(new XYChart.Data<>(austria, 45000.65));
        series3.getData().add(new XYChart.Data<>(brazil, 44835.76));
        series3.getData().add(new XYChart.Data<>(france, 18722.18));
        series3.getData().add(new XYChart.Data<>(italy, 17557.31));
        series3.getData().add(new XYChart.Data<>(usa, 92633.68));
        Scene scene = new Scene(sbc, 800, 600);
        sbc.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

在应用程序中定义堆叠条形图的坐标轴时,必须明确地将数据的类别分配给特定的轴。在示例36-4中,使用setCategories方法将类别分配给水平轴。该应用程序生成的条形图如图36-4所示。

图36-4 带有五个数据类别的堆叠条形图

图36-4的描述如下
"图36-4 带有五个数据类别的堆叠条形图"的描述

图36-3中显示的数据与图36-4中的相同数据进行比较。堆叠条形图中的区域显示了沿水平轴的任意点上垂直轴上的累积值。例如,在图36-4的垂直轴上,奥地利的2004年值范围从大约25,000到大约85,000。然而,示例36-4中的数据显示奥地利在2004年的值为57,401.85。在图36-4中,约85,000的2004年高值表示了奥地利在2003年和2004年的累积结果。

在开发JavaFX应用程序中的条形图时,请记住BarChartStackedBarChart的垂直轴上的数据解释方式不同。选择最能说明应用程序任务的图表类型。

您可以通过设置setCategoryGap方法中的值来指定堆叠类别之间的距离。例如,您可以为Country Summary条形图设置50像素的距离:sbc.setCategoryGap(50);

将此方法应用于示例36-4中的堆叠条形图时,条形图的类别如图36-5所示。

图36-5 带有指定类别间距的堆叠条形图

图36-5的描述如下
"图36-5 带有指定类别间距的堆叠条形图"的描述

在图表中实现数据动画

您可以实现动画图表来展示金融活动的动态行为。 示例36-5 定义了一个动画时间轴,并创建了关键帧来随机设置柱状图数据的X值。时间轴在应用程序启动时开始,并以自动反转模式无限循环。

示例36-5 在柱状图中实现数据动画

Timeline tl = new Timeline();
tl.getKeyFrames().add(new KeyFrame(Duration.millis(500), 
    (ActionEvent actionEvent) -> {
        bc.getData().stream().forEach((series) -> {
            series.getData().stream().forEach((data) -> {
                data.setXValue(Math.random() * 1000);
            });
        });
    }
));
tl.setCycleCount(Animation.INDEFINITE);
tl.setAutoReverse(true);
tl.play();

当您将此代码片段添加到示例36-3中的Country Summary应用程序中,然后编译和运行修改后的代码,您会注意到轴和图表绘图平滑地改变以适应范围内的新值和柱状图的新长度。这是因为ChartAxis类的animated属性默认设置为true,以动画方式显示任何数据更改。

对于Country Summary应用程序,当该轴上的数据以类别形式呈现且不会更改时,您可以禁止沿垂直轴动画数据。为了避免国家标签的闪烁,可以使用setAnimated方法,如示例36-6所示。

示例36-6 管理数据更改的动画

yAxis.setAnimated(false);

有关JavaFX图表的功能和能力的更多信息,请参阅API文档。

相关API文档 

关闭窗口

目录

JavaFX:使用JavaFX UI组件

展开 折叠