I have an application that displays several Line Charts with several Series like this:
I'd like to change the color of each Series but haven't found a way to achieve this. The only thing I found is how to change the default colors but that doesn't solve my problem.
Is there really now way to achieve individual colors for chart series?
The JavaFX CSS Reference Guide says the following for LineChart
:
Style class Comments Properties "chart-series-line series<i> default-color<j>"
Where <i>
is the index of the series and<j>
is the series’ color indexNode
"chart-line-symbol series<i> data<j> default-color<k>"
Where <i>
is the index of the series,<j>
is the index of the data within the series, and<k>
is the series’ color indexNode
"chart-line-symbol series<i> default-color<j>"
Where <i>
is the index of the series and<j>
is the series’ color indexLegendItem
Note: Although the line is only documented as a Node
, by default it is actually a javafx.scene.shape.Path
.
If you want to target a specific series' line, use .chart-series-line.series<i>
, where <i>
is replaced with the index of the series in the chart's data. And if you want to give a series of a specific chart a certain color, then simply give the chart an ID and use that in the CSS selector.
Here's an example. It uses so-called looked-up colors, which makes the CSS a little more scalable and organized. Also, they can have their values changed via the setStyle
method in code, allowing you to dynamically change the color programmatically. Another approach for that is to use a "data URL", showcased in this other Stack Overflow answer.
style.css:
/*
* The '-fx-stroke' is used to set the color of the line. The line is
* targeted by the '.chart-series-line.series<i>' selectors.
*
* The '-fx-background-color' is used to set the color of the legend
* symbol so it matches the line. This would also color the symbols
* on the line if they were shown. These symbol nodes are targeted
* by the '.chart-line-symbol.series<i>' selectors.
*
* Both the '-fx-series0-color' and '-fx-series1-color' "properties"
* are looked-up colors. You can change the value of a looked-up color
* in code by calling 'setStyle(...)' on the appropriate node.
*/
#firstChart {
-fx-series0-color: magenta;
-fx-series1-color: dodgerblue;
}
#secondChart {
-fx-series0-color: red;
-fx-series1-color: black;
}
#firstChart .chart-series-line.series0,
#firstChart .chart-line-symbol.series0 {
-fx-stroke: -fx-series0-color;
-fx-background-color: -fx-series0-color;
}
#firstChart .chart-series-line.series1,
#firstChart .chart-line-symbol.series1 {
-fx-stroke: -fx-series1-color;
-fx-background-color: -fx-series1-color;
}
#secondChart .chart-series-line.series0,
#secondChart .chart-line-symbol.series0 {
-fx-stroke: -fx-series0-color;
-fx-background-color: -fx-series0-color;
}
#secondChart .chart-series-line.series1,
#secondChart .chart-line-symbol.series1 {
-fx-stroke: -fx-series1-color;
-fx-background-color: -fx-series1-color;
}
Main.java:
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
var chart1 = createLineChart("Chart 1");
chart1.setId("firstChart");
chart1.getData().add(createSeries("f(x) = x", x -> x));
chart1.getData().add(createSeries("f(x) = 2x", x -> 2 * x));
/*
* Uncomment the line of code below to demonstrate dynamically changing
* the value of a looked-up color.
*/
// chart1.setStyle("-fx-series0-color: goldenrod;");
var chart2 = createLineChart("Chart 2");
chart2.setId("secondChart");
chart2.getData().add(createSeries("f(x) = x^2", x -> x * x));
chart2.getData().add(createSeries("f(x) = x^3", x -> x * x * x));
var root = new VBox(10, chart1, chart2);
root.setPadding(new Insets(10));
primaryStage.setScene(new Scene(root, 1000, 720));
primaryStage.getScene()
.getStylesheets()
.add(Main.class.getResource("/style.css").toString());
primaryStage.show();
}
private LineChart<Number, Number> createLineChart(String title) {
var chart = new LineChart<>(new NumberAxis(), new NumberAxis());
chart.setTitle(title);
chart.getXAxis().setLabel("x");
chart.getYAxis().setLabel("f(x)");
chart.setCreateSymbols(false);
return chart;
}
private XYChart.Series<Number, Number> createSeries(
String name,
UnaryOperator<Double> func) {
var series = new XYChart.Series<Number, Number>();
series.setName(name);
for (int x = 0; x < 20; x++) {
series.getData().add(new XYChart.Data<>(x, func.apply((double) x)));
}
return series;
}
}