I am building a Java desktop app for which I need to generate charts. One of these needs to be a bar chart that has a line chart layered over it.
I used a StackPane for overlaying the two graphs and populated them individually, but as you can see in the picture they don't overlay correctly, the line graph starts to the left of the y axis. Also, this changes when the left y axis doesn't have a label (???), in the sense that the line shows correctly but the bars get messed up.
I also have two different Y axis for each chart, but the right one doesn't get displayed.
How can I make everything overlay nicely and each graph get positioned correctly? What am I doing wrong?
public class Graphs implements Initializable {
@FXML StackPane stackPane;
@FXML BarChart barChart;
@FXML CategoryAxis xAxis;
@FXML NumberAxis yAxis;
@FXML NumberAxis yAxisRight;
@FXML LineChart lineChartEffective;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
xAxis.setCategories(FXCollections.<String>observableArrayList("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"));
yAxis.setLowerBound(0);
yAxis.setUpperBound(100);
yAxis.setTickUnit(10);
yAxisRight.setSide(Side.RIGHT);
yAxisRight.setLowerBound(0);
yAxisRight.setUpperBound(50);
yAxisRight.setTickUnit(1);
barChart.setLegendVisible(false);
barChart.setAnimated(false);
barChart.setLegendVisible(false);
barChart.setAnimated(false);
barChart.setAlternativeRowFillVisible(false);
barChart.setAlternativeColumnFillVisible(false);
barChart.setHorizontalGridLinesVisible(false);
barChart.setVerticalGridLinesVisible(false);
barChart.getXAxis().setVisible(true);
barChart.getYAxis().setVisible(true);
barChart.getData().add(getAverageLoadPerFTE());
xAxis.setLabel("Month");
yAxis.setLabel("Level (%)");
yAxisRight.setLabel("Level (u)");
lineChartEffective.setLegendVisible(false);
lineChartEffective.setAnimated(false);
lineChartEffective.setCreateSymbols(true);
lineChartEffective.setAlternativeRowFillVisible(false);
lineChartEffective.setAlternativeColumnFillVisible(false);
lineChartEffective.setHorizontalGridLinesVisible(false);
lineChartEffective.setVerticalGridLinesVisible(false);
lineChartEffective.getXAxis().setVisible(false);
lineChartEffective.getYAxis().setVisible(true);
lineChartEffective.getStylesheets().addAll(getClass().getResource("chartEffective.css").toExternalForm());
lineChartEffective.getData().add( getEffectiveCustomerSupport());
}
private XYChart.Series<String,Number> getAverageLoadPerFTE() {
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
series.getData().add(new XYChart.Data<String,Number>("Jan", 58 ));
series.getData().add(new XYChart.Data<String,Number>("Feb", 54 ));
series.getData().add(new XYChart.Data<String,Number>("Mar", 47 ));
series.getData().add(new XYChart.Data<String,Number>("Apr", 34 ));
series.getData().add(new XYChart.Data<String,Number>("May", 33 ));
series.getData().add(new XYChart.Data<String,Number>("Jun", 32 ));
series.getData().add(new XYChart.Data<String,Number>("Jul", 30 ));
series.getData().add(new XYChart.Data<String,Number>("Aug", 36 ));
series.getData().add(new XYChart.Data<String,Number>("Sep", 29 ));
series.getData().add(new XYChart.Data<String,Number>("Oct", 33 ));
series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));
series.setName("Average load per FTE");
return series;
}
private XYChart.Series<String,Number> getEffectiveCustomerSupport() {
XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
series.getData().add(new XYChart.Data<String,Number>("Jan", 2.9 ));
series.getData().add(new XYChart.Data<String,Number>("Feb", 2.7 ));
series.getData().add(new XYChart.Data<String,Number>("Mar", 3.3 ));
series.getData().add(new XYChart.Data<String,Number>("Apr", 3.4 ));
series.getData().add(new XYChart.Data<String,Number>("May", 3.3 ));
series.getData().add(new XYChart.Data<String,Number>("Jun", 3.2 ));
series.getData().add(new XYChart.Data<String,Number>("Jul", 3.3 ));
series.getData().add(new XYChart.Data<String,Number>("Aug", 4 ));
series.getData().add(new XYChart.Data<String,Number>("Sep", 3.8 ));
series.getData().add(new XYChart.Data<String,Number>("Oct", 4.1 ));
series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));
series.setName("Effective customer support");
return series;
}
}
Graphs.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.chart.BarChart?>
<AnchorPane prefHeight="731.0" prefWidth="878.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Graphs">
<children>
<StackPane fx:id="stackPane" layoutX="26.0" layoutY="32.0" prefHeight="523.0" prefWidth="708.0">
<children>
<BarChart fx:id="barChart" >
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id = "yAxis" side="LEFT" />
</yAxis>
</BarChart>
<LineChart fx:id="lineChartEffective" stylesheets="@chartEffective.css">
<xAxis>
<CategoryAxis fx:id = "xAxis" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxisRight" side="RIGHT"/>
</yAxis>
</LineChart>
</children>
</StackPane>
</children>
</AnchorPane>
chartsEffective.css:
.chart-plot-background {
-fx-background-color: transparent;
}
.default-color0.chart-series-line {
-fx-stroke: #4b0082;
}
.default-color0.chart-line-symbol {
-fx-background-color: #4b0082, white;
}