Stacking charts in JavaFX

China☆狼群 提交于 2019-11-28 00:32:01

Jewelsea posted an example on a gist.

It basically comes down to using a StackPane for stacking the charts and modifying the visibility of all the overlays.

Here's a simpler modified version how I use it:

public class StackedChartSample 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) {

        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();

        // base chart
        final BarChart<String, Number> barChart = new BarChart<String, Number>(xAxis, yAxis);
        barChart.setLegendVisible(false);
        barChart.setAnimated(false);

        xAxis.setLabel("Country");
        yAxis.setLabel("Value");

        // overlay chart
        LineChart<String, Number> lineChart = new LineChart<String, Number>(xAxis, yAxis);
        lineChart.setLegendVisible(false);
        lineChart.setAnimated(false);
        lineChart.setCreateSymbols(true);
        lineChart.setAlternativeRowFillVisible(false);
        lineChart.setAlternativeColumnFillVisible(false);
        lineChart.setHorizontalGridLinesVisible(false);
        lineChart.setVerticalGridLinesVisible(false);
        lineChart.getXAxis().setVisible(false);
        lineChart.getYAxis().setVisible(false);
        lineChart.getStylesheets().addAll(getClass().getResource("chart.css").toExternalForm());

        barChart.getData().add( createChartSeries());
        lineChart.getData().add( createChartSeries());

        StackPane root = new StackPane();
        root.getChildren().addAll( barChart, lineChart);

        Scene scene = new Scene(root, 800, 600);

        stage.setScene(scene);
        stage.show();
    }

    private XYChart.Series<String,Number> createChartSeries() {

        XYChart.Series<String,Number> series = new XYChart.Series<String,Number>();
        series.getData().add(new XYChart.Data<String,Number>(austria, 25601.34));
        series.getData().add(new XYChart.Data<String,Number>(brazil, 20148.82));
        series.getData().add(new XYChart.Data<String,Number>(france, 10000));
        series.getData().add(new XYChart.Data<String,Number>(italy, 35407.15));
        series.getData().add(new XYChart.Data<String,Number>(usa, 12000));

        return series;
    }


    public static void main(String[] args) {
        launch(args);
    }
}

chart.css

.chart-plot-background {
-fx-background-color: transparent;
}
.default-color0.chart-series-line {
-fx-stroke: blue;
} 
.default-color0.chart-line-symbol { 
    -fx-background-color: blue, white;
}

I do not have enough "reputation" to add a comment below Roland's answer, but I fear that there is an issue with the proposed solution.

1) If the values of the 2nd series are not the same, the y-axis adapts to their range, but the 1st chart does not adapt in height.

Example below: the value of the first orange bar is 25,601: it should be less tall.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Exemple158_JavaFX_Overlaid_Stacked_Charts 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) {

    // x-axis and y-axis  for both charts:
    final CategoryAxis xAxis = new CategoryAxis();
    xAxis.setLabel("Country");
    final NumberAxis yAxis1 = new NumberAxis();
    yAxis1.setLabel("Value");

    // first chart:
    final BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis1);
    barChart.setLegendVisible(false);
    barChart.setAnimated(false);
    XYChart.Series<String, Number> series1 = new XYChart.Series<>();
    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));
    barChart.getData().add(series1);

    // second chart (overlaid):
    final LineChart<String, Number> lineChart = new LineChart<>(xAxis, yAxis1);
    lineChart.setLegendVisible(false);
    lineChart.setAnimated(false);
    lineChart.setCreateSymbols(true);
    lineChart.setAlternativeRowFillVisible(false);
    lineChart.setAlternativeColumnFillVisible(false);
    lineChart.setHorizontalGridLinesVisible(false);
    lineChart.setVerticalGridLinesVisible(false);
    lineChart.getXAxis().setVisible(false);
    lineChart.getYAxis().setVisible(false);
    lineChart.getStylesheets().addAll(getClass().getResource("Exemple158.css").toExternalForm());
    XYChart.Series<String, Number> series2 = new XYChart.Series<>();
    int delta = 10000;
    series2.getData().add(new XYChart.Data<>(AUSTRIA, 25601.34 + delta));
    series2.getData().add(new XYChart.Data<>(BRAZIL, 20148.82 + delta));
    series2.getData().add(new XYChart.Data<>(FRANCE, 10000 + delta));
    series2.getData().add(new XYChart.Data<>(ITALY, 35407.15 + delta));
    series2.getData().add(new XYChart.Data<>(USA, 12000 + delta));
    lineChart.getData().add(series2);

    StackPane root = new StackPane();
    root.getChildren().addAll(barChart, lineChart);
    Scene scene = new Scene(root, 800, 600);
    stage.setScene(scene);
    stage.show();
}

public static void main(String[] args) {
    launch(args);
}
}

CSS:

.chart-plot-background {
-fx-background-color: transparent;
}

.default-color0.chart-series-line {
-fx-stroke: blue;
}

.default-color0.chart-line-symbol { 
-fx-background-color: blue, white;
}

2) A solution is to set the bounds of the y-axis from the beginning:

final NumberAxis yAxis1 = new NumberAxis(0, 48000, 5000);

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!