柱状图(Bar Chart),一种带有矩形条(Rectangular bar)的双轴图表,Rectangular bar可以水平放置也可以竖垂直放置。
每个Bar的长度与图表表示的特定数据是成比例的。Bar Chart一般用来展示散列数据。你可以使用多组Bar来分类绘制数据
例子:
创建Bar Chart
要在你的JavaFX应用程序中创建Bar Chart,需要创建两个坐标轴、实例化BarClass类、定义数据序列并且把数据指定给Bar Chart。例创建了一个有三组数据的Bar Chart来表示5个国家的金融数据。每个国家的数据被当作一个分类以水平坐标轴上的一组Bar来展示
BarChart类有两个属性分别控制着两个Category数据的间距和同Category数据中两个Bar之间的间距。使用barGap和categoryGap属性来使图表中的Bar更好地分布。例使用setBarGap和setCategoryGap方法来为这两个属性设置了特定的值。
例 设置Bar之间和Category之间的间距
1 2 | bc.setBarGap(3); bc.setCategoryGap(20); |
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 { @Override public void start(Stage stage) { stage.setTitle("柱状统计图"); final NumberAxis yAxis = new NumberAxis();//定义一个数字轴起名为y轴 final CategoryAxis xAxis = new CategoryAxis();//定义一个分类轴起名为x轴 final BarChart<String,Number> bc = new BarChart<>(xAxis,yAxis);//创建一个柱状图(条形图) bc.setTitle("mxc值");//设置图的标题 xAxis.setLabel("圈子");//设置x轴标签 yAxis.setLabel("总值");//设置y轴标签 XYChart.Series series1 = new XYChart.Series();//创建数据序列1 series1.setName("m");//序列标识 series1.getData().add(new XYChart.Data("天朝",888996 ));//设置数据序列值 series1.getData().add(new XYChart.Data("漂亮国",995820));//设置数据序列值 series1.getData().add(new XYChart.Data("大鹅", 568212));//设置数据序列值 XYChart.Series series2 = new XYChart.Series();//创建数据序列2 series2.setName("x");//序列标识 series2.getData().add(new XYChart.Data("天朝",898996 ));//设置数据序列值 series2.getData().add(new XYChart.Data("漂亮国",925820));//设置数据序列值 series2.getData().add(new XYChart.Data("大鹅", 60212));//设置数据序列值 XYChart.Series series3 = new XYChart.Series();//创建数据序列2 series3.setName("c");//序列标识 series3.getData().add(new XYChart.Data("天朝",898996 ));//设置数据序列值 series3.getData().add(new XYChart.Data("漂亮国",925820));//设置数据序列值 series3.getData().add(new XYChart.Data("大鹅", 60212));//设置数据序列值 Scene scene = new Scene(bc,800,600);//创建场景,场景上挂载柱状图对象bc bc.getData().addAll(series1, series2,series3);//柱状图对象上挂载3个数据序列 stage.setScene(scene);//舞台上挂载场景 stage.show();//舞台展现 } public static void main(String[] args) { launch(args); }//启动javaFX程序 }
——————————————————————————————
水平柱状图(Horizontal Bar Chart)
通过为纵轴定义Category将Bar Chart的方向由垂直变为水平。将横轴定义为NumberAxis类型,纵轴定义为CategoryAxis类型。不要忘了修改BarChart对象的声明
/** * @author zhaoyong * @Date 2022/5/18 * @Description */ 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 BarChartTest 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("防守能力"); 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("体力"); 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("进攻能力"); 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方法来旋转Label以使文字更加易读
水平柱状图在你想要表示排名数据时会很有用
——————————————————
创建堆叠柱状图(Stacked Bar Chart)
Bar Chart中属于同一个Category的Bar都堆叠起来。使用StackedBarChart类来完成
创建Stacked Bar Chart
/** * @author zhaoyong * @Date 2022/5/18 * @Description */ 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 magician = "法师"; final static String fighter = "战士"; final static String hunter = "猎人"; final static String thief = "盗贼"; final static String doctor = "医疗师"; 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("Country"); xAxis.setCategories(FXCollections.<String>observableArrayList( Arrays.asList(magician, fighter, hunter, thief, doctor))); yAxis.setLabel("Value"); series1.setName("防守能力"); series1.getData().add(new XYChart.Data<>(magician, 20)); series1.getData().add(new XYChart.Data<>(fighter, 80)); series1.getData().add(new XYChart.Data<>(hunter, 40)); series1.getData().add(new XYChart.Data<>(thief, 20)); series1.getData().add(new XYChart.Data<>(doctor, 10)); series2.setName("攻击能力"); series2.getData().add(new XYChart.Data<>(magician, 80)); series2.getData().add(new XYChart.Data<>(fighter, 60)); series2.getData().add(new XYChart.Data<>(hunter, 65)); series2.getData().add(new XYChart.Data<>(thief, 50)); series2.getData().add(new XYChart.Data<>(doctor, 10)); series3.setName("生命能力"); series3.getData().add(new XYChart.Data<>(magician, 20)); series3.getData().add(new XYChart.Data<>(fighter, 50)); series3.getData().add(new XYChart.Data<>(hunter, 55)); series3.getData().add(new XYChart.Data<>(thief, 70)); series3.getData().add(new XYChart.Data<>(doctor, 100)); 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); } }
——————————————————
Stacked Bar Chart定义坐标轴时,你必须要明确地把数据Category指定给某一个坐标轴。例中,通过使用setCategories方法将Category指定给横轴
Stacked Bar Chart中的区域展示了横轴上任意点在纵轴上的累加值
当你在程序中使用Bar Chart时,请记住BarChart和StackedBarChart中纵轴上的数据表示的含义是不一样的。要根应用据程序需求来选择最恰当的图表类型
你可以通过调用setCategoryGap方法来指定两个Stacked Category之间的距离
sbc.setCategoryGap(50)
让图表中的数据动起来
动画时间线并且创建了Key Frames来随机为Bar Chart的数据设置X值。时间线在程序开始时开始,并且在auto-reverse模式中无限的继续下去
Bar Chart中的动画数据
示例代码
/** * @author zhaoyong * @Date 2022/5/18 * @Description */ import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; 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; import javafx.util.Duration; public class BarChartTest 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("防守能力"); 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("体力"); 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("进攻能力"); 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); yAxis.setAnimated(false); Timeline tl = new Timeline();//创建一个时间线对象 tl.getKeyFrames().add(new KeyFrame(Duration.millis(500), (ActionEvent actionEvent) -> {//每当过去500毫秒作为激发事件,并调用如下事件响应回调函数体内容 bc.getData().stream().forEach((series) -> {//lamda表达式 series.getData().stream().forEach((data) -> {//lamda表达式,每个数据序列下的数据轴上的数据随机取数变换 data.setXValue(Math.random() * 1000); }); }); } )); tl.setCycleCount(Animation.INDEFINITE);//无线循环次数播放效果 tl.setAutoReverse(true);//自动翻转 tl.play();//开始播放动画执行 stage.setScene(scene);//舞台上挂载场景 stage.show();//舞台展现 } public static void main(String[] args) { launch(args); } }
再次编译运行程序,你将看到坐标轴和绘制区域都会平滑地变化来适应Bar新的范围和长度。这是由Chart和Axis类的animated属性所致。该属性值默认为true来使任何数据改变都以动画形式展现
当纵轴上的数据是以Category的形式表示并且不会改变时,你可以禁止该轴上的数据动画,以此来避免国家label的闪烁
管理数据变化的动画
Java
1 | yAxis.setAnimated(false); |
/** * @author zhaoyong * @Date 2022/5/18 * @Description */ import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; 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; import javafx.util.Duration; public class BarChartTest 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("防守能力"); 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("体力"); 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("进攻能力"); 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); yAxis.setAnimated(false); Timeline tl = new Timeline();//创建一个时间线对象 tl.getKeyFrames().add(new KeyFrame(Duration.millis(500), (ActionEvent actionEvent) -> {//每当过去500毫秒作为激发事件,并调用如下事件响应回调函数体内容 bc.getData().stream().forEach((series) -> {//lamda表达式 series.getData().stream().forEach((data) -> {//lamda表达式,每个数据序列下的数据轴上的数据随机取数变换 data.setXValue(Math.random() * 1000); }); }); } )); tl.setCycleCount(Animation.INDEFINITE);//无线循环次数播放效果 tl.setAutoReverse(true);//自动翻转 tl.play();//开始播放动画执行 stage.setScene(scene);//舞台上挂载场景 stage.show();//舞台展现 } public static void main(String[] args) { launch(args); } }