DOC-03-36 柱状图(Bar Chart)
本章将介绍柱状图(Bar Chart),一种带有矩形条(Rectangular bar)的双轴图表,Rectangular bar可以水平放置也可以竖垂直放置。
每个Bar的长度与图表表示的特定数据是成比例的。Bar Chart一般用来展示散列数据。你可以使用多组Bar来分类绘制数据,如图36-1所示。
图36-1 Bar Chart样例
创建Bar Chart
要在你的JavaFX应用程序中创建Bar Chart,需要创建两个坐标轴、实例化BarClass类、定义数据序列并且把数据指定给Bar Chart。例36-1创建了一个有三组数据的Bar Chart来表示5个国家的金融数据。每个国家的数据被当作一个分类以水平坐标轴上的一组Bar来展示。
例36-1创建有3组数据的Bar Chart
Java
scene.getStylesheets().add("scaterchartsample/Chart.css");
1
scene.getStylesheets().add("scaterchartsample/Chart.css");
图36-2显示了此应用程序的运行结果。
图36-2创建有3组数据的bar chart
BarChart类有两个属性分别控制着两个Category数据的间距和同Category数据中两个Bar之间的间距。使用barGap和categoryGap属性来使图表中的Bar更好地分布。例36-2使用setBarGap和setCategoryGap方法来为这两个属性设置了特定的值。
例36-2设置Bar之间和Category之间的间距
Java
bc.setBarGap(3);
bc.setCategoryGap(20);
1
2
bc.setBarGap(3);
bc.setCategoryGap(20);
水平柱状图(Horizontal Bar Chart)
你可以通过为纵轴定义Category将Bar Chart的方向由垂直变为水平。例36-3为Country Summary应用程序实现了这个需求。将横轴定义为NumberAxis类型,纵轴定义为CategoryAxis类型。不要忘了修改BarChart对象的声明。
例36-3改变Bar Chart的方向
Java
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 = "Austria";
final static String brazil = "Brazil";
final static String france = "France";
final static String italy = "Italy";
final static String usa = "USA";
@Override public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
final NumberAxis xAxis = new NumberAxis();
final CategoryAxis yAxis = new CategoryAxis();
final BarChart bc =
new BarChart<>(xAxis,yAxis);
bc.setTitle("Country Summary");
xAxis.setLabel("Value");
xAxis.setTickLabelRotation(90);
yAxis.setLabel("Country");
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
importjavafx.application.Application;
importjavafx.scene.Scene;
importjavafx.scene.chart.BarChart;
importjavafx.scene.chart.CategoryAxis;
importjavafx.scene.chart.NumberAxis;
importjavafx.scene.chart.XYChart;
importjavafx.stage.Stage;
publicclassBarChartSampleextendsApplication{
finalstaticStringaustria="Austria";
finalstaticStringbrazil="Brazil";
finalstaticStringfrance="France";
finalstaticStringitaly="Italy";
finalstaticStringusa="USA";
@Overridepublicvoidstart(Stagestage){
stage.setTitle("Bar Chart Sample");
finalNumberAxisxAxis=newNumberAxis();
finalCategoryAxisyAxis=newCategoryAxis();
finalBarChartbc=
newBarChart<>(xAxis,yAxis);
bc.setTitle("Country Summary");
xAxis.setLabel("Value");
xAxis.setTickLabelRotation(90);
yAxis.setLabel("Country");
XYChart.Seriesseries1=newXYChart.Series();
series1.setName("2003");
series1.getData().add(newXYChart.Data(25601.34,austria));
series1.getData().add(newXYChart.Data(20148.82,brazil));
series1.getData().add(newXYChart.Data(10000,france));
series1.getData().add(newXYChart.Data(35407.15,italy));
series1.getData().add(newXYChart.Data(12000,usa));
XYChart.Seriesseries2=newXYChart.Series();
series2.setName("2004");
series2.getData().add(newXYChart.Data(57401.85,austria));
series2.getData().add(newXYChart.Data(41941.19,brazil));
series2.getData().add(newXYChart.Data(45263.37,france));
series2.getData().add(newXYChart.Data(117320.16,italy));
series2.getData().add(newXYChart.Data(14845.27,usa));
XYChart.Seriesseries3=newXYChart.Series();
series3.setName("2005");
series3.getData().add(newXYChart.Data(45000.65,austria));
series3.getData().add(newXYChart.Data(44835.76,brazil));
series3.getData().add(newXYChart.Data(18722.18,france));
series3.getData().add(newXYChart.Data(17557.31,italy));
series3.getData().add(newXYChart.Data(92633.68,usa));
Scenescene=newScene(bc,800,600);
bc.getData().addAll(series1,series2,series3);
stage.setScene(scene);
stage.show();
}
publicstaticvoidmain(String[]args){
launch(args);
}
}
需要注意上面调用了横轴的setTickLabelRotation方法来旋转Label以使文字更加易读。
修改后的程序运行结果如图36-3所示。
图36-3水平柱状图
水平柱状图在你想要表示排名数据时会很有用。
创建堆叠柱状图(Stacked Bar Chart)
你可以让Bar Chart中属于同一个Category的Bar都堆叠起来。使用StackedBarChart类来完成,如例36-4所示。
例36-4创建Stacked Bar Chart
Java
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 = "Austria";
final static String brazil = "Brazil";
final static String france = "France";
final static String italy = "Italy";
final static String usa = "USA";
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final StackedBarChart sbc =
new StackedBarChart<>(xAxis, yAxis);
final XYChart.Series series1 =
new XYChart.Series<>();
final XYChart.Series series2 =
new XYChart.Series<>();
final XYChart.Series series3 =
new XYChart.Series<>();
@Override
public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
sbc.setTitle("Country Summary");
xAxis.setLabel("Country");
xAxis.setCategories(FXCollections.observableArrayList(
Arrays.asList(austria, brazil, france, italy, usa)));
yAxis.setLabel("Value");
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
importjava.util.Arrays;
importjavafx.application.Application;
importjavafx.collections.FXCollections;
importjavafx.scene.Scene;
importjavafx.scene.chart.CategoryAxis;
importjavafx.scene.chart.NumberAxis;
importjavafx.scene.chart.StackedBarChart;
importjavafx.scene.chart.XYChart;
importjavafx.stage.Stage;
publicclassStackedBarChartSampleextendsApplication{
finalstaticStringaustria="Austria";
finalstaticStringbrazil="Brazil";
finalstaticStringfrance="France";
finalstaticStringitaly="Italy";
finalstaticStringusa="USA";
finalCategoryAxisxAxis=newCategoryAxis();
finalNumberAxisyAxis=newNumberAxis();
finalStackedBarChartsbc=
newStackedBarChart<>(xAxis,yAxis);
finalXYChart.Seriesseries1=
newXYChart.Series<>();
finalXYChart.Seriesseries2=
newXYChart.Series<>();
finalXYChart.Seriesseries3=
newXYChart.Series<>();
@Override
publicvoidstart(Stagestage){
stage.setTitle("Bar Chart Sample");
sbc.setTitle("Country Summary");
xAxis.setLabel("Country");
xAxis.setCategories(FXCollections.observableArrayList(
Arrays.asList(austria,brazil,france,italy,usa)));
yAxis.setLabel("Value");
series1.setName("2003");
series1.getData().add(newXYChart.Data<>(austria,25601.34));
series1.getData().add(newXYChart.Data<>(brazil,20148.82));
series1.getData().add(newXYChart.Data<>(france,10000));
series1.getData().add(newXYChart.Data<>(italy,35407.15));
series1.getData().add(newXYChart.Data<>(usa,12000));
series2.setName("2004");
series2.getData().add(newXYChart.Data<>(austria,57401.85));
series2.getData().add(newXYChart.Data<>(brazil,41941.19));
series2.getData().add(newXYChart.Data<>(france,45263.37));
series2.getData().add(newXYChart.Data<>(italy,117320.16));
series2.getData().add(newXYChart.Data<>(usa,14845.27));
series3.setName("2005");
series3.getData().add(newXYChart.Data<>(austria,45000.65));
series3.getData().add(newXYChart.Data<>(brazil,44835.76));
series3.getData().add(newXYChart.Data<>(france,18722.18));
series3.getData().add(newXYChart.Data<>(italy,17557.31));
series3.getData().add(newXYChart.Data<>(usa,92633.68));
Scenescene=newScene(sbc,800,600);
sbc.getData().addAll(series1,series2,series3);
stage.setScene(scene);
stage.show();
}
publicstaticvoidmain(String[]args){
launch(args);
}
}
在程序中给Stacked Bar Chart定义坐标轴时,你必须要明确地把数据Category指定给某一个坐标轴。例36-4中,通过使用setCategories方法将Category指定给横轴。上例中的程序运行结果如图36-4所示。
图36-4有5组数据的Stacked Bar Chart
比较图36-3和36-4中同样的数据。Stacked Bar Chart中的区域展示了横轴上任意点在纵轴上的累加值。例如,图36-4的纵轴上澳大利亚2004年的数据范围大概是25000到85000。但例36-4中澳大利亚2004年的数据是57401.85。图26-4中2004年的最高值85000表示澳大利亚2003和2004两年的累加值。
当你在程序中使用Bar Chart时,请记住BarChart和StackedBarChart中纵轴上的数据表示的含义是不一样的。要根应用据程序需求来选择最恰当的图表类型。
你可以通过调用setCategoryGap方法来指定两个Stacked Category之间的距离。例如,可以为Country Summary程序中的Bar Chart将该距离设置为50像素:sbc.setCategoryGap(50)。在例36-4中调用该方法以后,程序运行结果如图36-5所示。
图36-5指定Category的间距后的Stacked Bar Chart
让图表中的数据动起来
你可以实现动画图表来说明金融活动的动态特性。例36-5定义了动画时间线并且创建了Key Frames来随机为Bar Chart的数据设置X值。时间线在程序开始时开始,并且在auto-reverse模式中无限的继续下去。
例36-5 Bar Chart中的动画数据
Java
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();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Timelinetl=newTimeline();
tl.getKeyFrames().add(newKeyFrame(Duration.millis(500),
(ActionEventactionEvent)->{
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应用程序中,再次编译运行程序,你将看到坐标轴和绘制区域都会平滑地变化来适应Bar新的范围和长度。这是由Chart和Axis类的animated属性所致。该属性值默认为true来使任何数据改变都以动画形式展现。
在Country Summary应用程序中,当纵轴上的数据是以Category的形式表示并且不会改变时,你可以禁止该轴上的数据动画,以此来避免Country Lbel的闪烁。使用例36-6中所示的setAnimated方法。
例36-6管理数据变化的动画
Java
yAxis.setAnimated(false);
1
yAxis.setAnimated(false);
查看API文档来获取更多关于JavaFX图表特性的信息。
相关的API文档
· BarChart
· Chart
· XYChart
· Data
· Series
· Axis
· NumberAxis
· CategoryAxis
· Timeline
· KeyFrame
打赏一下
支付宝
微信