Charts: PieChart, BarChart and LineChart
Charts in JavaFX are ordinary nodes from the javafx.scene.chart package, which is part of the javafx.controls module. You put them into a window like a button or a table and hand them the data as a list. JavaFX draws the labels, the legend, the colors and even an animation when the chart appears. Let's give the notebook a "Statistics" window: how many notes each category has and how many of them are important.
The statistics window
Create a class with a static method that builds and shows the window. The first version is a PieChart with hand-written data:
// src/main/java/com/example/notes/StatsWindow.java — first version
package com.example.notes;
import java.util.List;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.stage.Stage;
import javafx.stage.Window;
public class StatsWindow {
public static void show(Window owner, List<Note> notes) {
PieChart pie = new PieChart();
pie.setTitle("Notes by category");
pie.getData().add(new PieChart.Data("Work", 3));
pie.getData().add(new PieChart.Data("Home", 5));
pie.getData().add(new PieChart.Data("Ideas", 2));
Stage stage = new Stage();
stage.setTitle("Statistics");
stage.initOwner(owner);
stage.setScene(new Scene(pie, 450, 400));
stage.show();
}
}PieChart.Data is one slice: a label and a number. JavaFX computes the slice size itself as a share of the total.
A button in the main window
Add a button to the bottom row of main-view.fxml after the "Delete" button, and a method to the controller:
<!-- src/main/resources/com/example/notes/main-view.fxml — the bottom row -->
<Button text="Statistics" onAction="#showStats"/>// src/main/java/com/example/notes/MainController.java — a new method showStats()
@FXML
private void showStats() {
StatsWindow.show(table.getScene().getWindow(), notes);
}Click "Statistics" and a window opens with a circle of three slices, a label next to each and a legend at the bottom. The slices grow in with a short animation.
Data from the notes
Let's replace the hand-written numbers with a count. A stream with groupingBy builds a "category → number of notes" map; TreeMap sorts the categories alphabetically:
// src/main/java/com/example/notes/StatsWindow.java — the start of show()
Map<String, Long> byCategory = notes.stream()
.collect(Collectors.groupingBy(Note::category, TreeMap::new, Collectors.counting()));
PieChart pie = new PieChart();
pie.setTitle("Notes by category");
byCategory.forEach((category, count) ->
pie.getData().add(new PieChart.Data(category, count)));Now the circle shows the real notes: with three "Home" notes, two "Work" notes and one "Ideas" note, "Home" takes half of the circle. The window counts the data when it opens, so to see new notes, open it again.
Bars and series
BarChart and LineChart draw points on two axes. Labels along the horizontal axis use a CategoryAxis, numbers use a NumberAxis. The data is grouped into series, XYChart.Series: each series has its own name in the legend and its own color. Let's show two series side by side, all notes and important ones:
// src/main/java/com/example/notes/StatsWindow.java — the rest of show()
CategoryAxis xAxis = new CategoryAxis();
long max = byCategory.values().stream().mapToLong(Long::longValue).max().orElse(0);
NumberAxis yAxis = new NumberAxis(0, max + 1, 1);
yAxis.setLabel("Notes");
BarChart<String, Number> bar = new BarChart<>(xAxis, yAxis);
bar.setTitle("All and important");
XYChart.Series<String, Number> all = new XYChart.Series<>();
all.setName("All");
XYChart.Series<String, Number> important = new XYChart.Series<>();
important.setName("Important");
byCategory.forEach((category, count) -> {
long importantCount = notes.stream()
.filter(note -> note.category().equals(category) && note.important())
.count();
all.getData().add(new XYChart.Data<>(category, count));
important.getData().add(new XYChart.Data<>(category, importantCount));
});
bar.getData().add(all);
bar.getData().add(important);XYChart.Data is one point: an X value and a Y value. The NumberAxis(0, max + 1, 1) constructor sets the bounds and the tick step: notes are counted in whole numbers, while the axis on its own would pick a step like 0.25. Build the scene from both charts, new Scene(new HBox(pie, bar), 900, 450), and add the imports for BarChart, CategoryAxis, NumberAxis, XYChart, HBox, Map, TreeMap and Collectors. The circle is on the left, and on the right each category has two bars, orange and yellow.
LineChart
A line chart takes the same series; just change the class:
// src/main/java/com/example/notes/StatsWindow.java — instead of BarChart
LineChart<String, Number> line = new LineChart<>(xAxis, yAxis);The points of a series are joined by a line. It suits data where the X axis is time: days, months. A series can belong to only one chart, so two charts need two series.
| Class | What it draws |
|---|---|
PieChart | Shares of a whole |
BarChart | Bars by category |
LineChart | A line through points |
AreaChart | A line with the area under it filled |
ScatterChart | Separate points |
Common mistake
A bar chart is given two number axes: new BarChart<>(new NumberAxis(), new NumberAxis()). The window does not open: java.lang.IllegalArgumentException: Axis type incorrect, one of X,Y should be CategoryAxis and the other NumberAxis. One axis of a BarChart must be a CategoryAxis with labels, and the other a NumberAxis with numbers.