© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
K. Sharan, P. SpäthLearn JavaFX 17https://doi.org/10.1007/978-1-4842-7848-2_20

20. Understanding Charts

Kishori Sharan1   and Peter Späth2
(1)
Montgomery, AL, USA
(2)
Leipzig, Sachsen, Germany
 
In this chapter, you will learn:
  • What a chart is

  • What the Chart API is in JavaFX

  • How to create different types of charts using the Chart API

  • How to style charts with CSS

The examples of this chapter lie in the com.jdojo.chart package. In order for them to work, you must add a corresponding line to the module-info.java file:
...
opens com.jdojo.chart to javafx.graphics, javafx.base;
...

What Is a Chart?

A chart is a graphical representation of data. Charts provide an easier way to analyze large volume of data visually. Typically, they are used for monitoring and reporting purposes. Different types of charts exist. They differ in the way they represent the data. Not all types of charts are suitable for analyzing all types of data. For example, a line chart is suitable for understanding the comparative trend in data, whereas a bar chart is suitable for comparing data in different categories.

JavaFX supports charts, which can be integrated in a Java application by writing few lines of code. It contains a comprehensive, extensible Chart API that provides built-in support for several types of charts.

Understanding the Chart API

The Chart API consists of a number of predefined classes in the javafx.scene.chart package. Figure 20-1 shows a class diagram for classes representing different types of charts.
Figure 20-1

A class diagram for the classes representing charts in JavaFX

The abstract Chart is the base class for all charts. It inherits the Node class. Charts can be added to a scene graph. They can also be styled with CSS as any other nodes. I will discuss styling charts in the sections that discuss specific types of charts. The Chart class contains properties and methods common to all types of charts.

JavaFX divides charts into two categories:
  • Charts having no axis

  • Charts having an x-axis and a y-axis

The PieChart class falls into the first category. It has no axis, and it is used to draw a pie chart.

The XYChart class falls into the second category. It is the abstract base class for all charts having two axes. Its subclasses, for example, LineChart, BarChart, etc., represent specific types of charts.

Every chart in JavaFX has three parts:
  • A title

  • A legend

  • Content (or data)

Different types of charts define their data differently. The Chart class contains the following properties that are common to all types of charts:
  • title

  • titleSide

  • legend

  • legendSide

  • legendVisible

  • animated

The title property specifies the title for a chart. The titleSide property specifies the location of the title. By default, the title is placed above the chart content. Its value is one of the constants of the Side enum: TOP (default), RIGHT, BOTTOM, and LEFT.

Typically, a chart uses different types of symbols to represent data in different categories. A legend lists symbols with their descriptions. The legend property is a Node, and it specifies the legend for the chart. By default, a legend is placed below the chart content. The legendSide property specifies the location of the legend, which is one of the constants of the Side enum: TOP, RIGHT, BOTTOM (default), and LEFT. The legendVisible property specifies whether the legend is visible. By default, it is visible.

The animated property specifies whether the change in the content of the chart is shown with some type of animation. By default, it is true.

Styling Charts with CSS

You can style all types of charts. The Chart class defines properties common to all types of charts. The default CSS style-class name for a chart is chart. You can specify the legendSide, legendVisible, and titleSide properties for all charts in a CSS as shown:
.chart {
        -fx-legend-side: top;
        -fx-legend-visible: true;
        -fx-title-side: bottom;
}
Every chart defines two substructures:
  • chart-title

  • chart-content

The chart-title is a Label, and the chart-content is a Pane. The following styles set the background color for all charts to yellow and the title font to Arial 16px bold:
.chart-content {
        -fx-background-color: yellow;
}
.chart-title {
        -fx-font-family: "Arial";
        -fx-font-size: 16px;
        -fx-font-weight: bold;
}
The default style-class name for legends is chart-legend. The following style sets the legend background color to light gray:
.chart-legend {
        -fx-background-color: lightgray;
}
Every legend has two substructures:
  • chart-legend-item

  • chart-legend-item-symbol

The chart-legend-item is a Label, and it represents the text in the legend. The chart-legend-item-symbol is a Node, and it represents the symbol next to the label, which is a circle by default. The following style sets the font size for the labels in legends to 10px and the legend symbols to an arrow:
.chart-legend-item {
        -fx-font-size: 16px;
}
.chart-legend-item-symbol {
        -fx-shape: "M0 -3.5 v7 l 4 -3.5z";
}
Note

Many examples in this chapter use external resources such as CSS files. You will need to make sure the ResourceUtil class points to the resources directory (part of the sources bundle provided with the book). Download the sources from www.apress.com/source-code.

Data Used in Chart Examples

I will discuss different types of charts shortly. Charts will use data from Table 20-1, which has the actual and estimated population of some countries in the world. The data has been taken from the report published by the United Nations at www.un.org. The population values have been rounded.
Table 20-1

Current and Estimated Populations (in Millions) of Some Countries in the World

 

1950

2000

2050

2100

2150

2200

2250

2300

China

555

1275

1395

1182

1149

1201

1247

1285

India

358

1017

1531

1458

1308

1304

1342

1372

Brazil

54

172

233

212

202

208

216

223

UK

50

59

66

64

66

69

71

73

USA

158

285

409

437

453

470

483

493

Understanding the PieChart

A pie chart consists of a circle divided into sectors of different central angles. Typically, a pie is circular. The sectors are also known as pie pieces or pie slices. Each sector in the circle represents a quantity of some kind. The central angle of the area of a sector is proportional to the quantity it represents. Figure 20-2 shows a pie chart that displays the population of five countries in the year 2000.
Figure 20-2

A pie chart showing the population of five countries in 2000

An instance of the PieChart class represents a pie chart. The class contains two constructors:
  • PieChart()

  • PieChart(ObservableList<PieChart.Data> data)

The no-args constructor creates a pie chart with no content. You can add the content later using its data property. The second constructor creates a pie chart with the specified data as its content.
// Create an empty pie chart
PieChart chart = new PieChart();
A slice in a pie chart is specified as an instance of the PieChart.Data class. A slice has a name (or a label) and a pie value represented by the name and pieValue properties of the PieChart.Data class, respectively. The following statement creates a slice for a pie chart. The slice name is “China,” and the pie value is 1275:
PieChart.Data chinaSlice = new PieChart.Data("China", 1275);
The content of a pie chart (all slices) is specified in an ObservableList<PieChart.Data>. The following snippet of code creates an ObservableList<PieChart.Data> and adds three pie slices to it:
ObservableList<PieChart.Data> chartData = FXCollections.observableArrayList();
chartData.add(new PieChart.Data("China", 1275));
chartData.add(new PieChart.Data("India", 1017));
chartData.add(new PieChart.Data("Brazil", 172));
Now, you can use the second constructor to create a pie chart by specifying the chart content:
// Create a pie chart with content
PieChart charts = new PieChart(chartData);
You will use populations of different countries in 2050 as the data for all our pie charts. Listing 20-1 contains a utility class. Its getChartData() method returns an ObservableList of PieChart.Data to be used as data for a pie chart. You will use this class in our examples in this section.
// PieChartUtil.java
package com.jdojo.chart;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.PieChart;
public class PieChartUtil {
        public static ObservableList<PieChart.Data> getChartData() {
               ObservableList<PieChart.Data> data =
                        FXCollections. observableArrayList();
               data.add(new PieChart.Data("China", 1275));
               data.add(new PieChart.Data("India", 1017));
               data.add(new PieChart.Data("Brazil", 172));
               data.add(new PieChart.Data("UK", 59));
               data.add(new PieChart.Data("USA", 285));
               return data;
        }
}
Listing 20-1

A Utility Class to Generate Data for Pie Charts

The PieChart class contains several properties:
  • data

  • startAngle

  • clockwise

  • labelsVisible

  • labelLineLength

The data property specifies the content for the chart in an ObservableList<PieChart.Data>.

The startAngle property specifies the angle in degrees to start the first pie slice. By default, it is zero degrees, which corresponds to a three o’clock position. A positive startAngle is measured anticlockwise. For example, a 90-degree startAngle will start at the 12 o’clock position.

The clockwise property specifies whether the slices are placed clockwise starting at the startAngle. By default, it is true.

The labelsVisible property specifies whether the labels for slices are visible. Labels for slices are displayed close to the slice, and they are placed outside the slices. The label for a slice is specified using the name property of the PieChart.Data class. In Figure 20-2, “China,” “India,” “Brazil,” etc., are labels for slices.

Labels and slices are connected through straight lines. The labelLineLength property specifies the length of those lines. Its default value is 20.0 pixels.

The program in Listing 20-2 uses a pie chart to display the population for five countries in 2000. The program creates an empty pie chart and sets its title. The legend is placed on the left side. Later, it sets the data for the chart. The data is generated in the getChartData() method , which returns an ObservableList<PieChart.Data> containing the name of the countries as the labels for pie slices and their populations as pie values. The program displays a window as shown in Figure 20-2.
// PieChartTest.java
package com.jdojo.chart;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class PieChartTest extends Application {
        public static void main(String[] args) {
               Application.launch(args);
        }
        @Override
        public void start(Stage stage) {
               PieChart chart = new PieChart();
               chart.setTitle("Population in 2000");
               // Place the legend on the left side
               chart.setLegendSide(Side.LEFT);
               // Set the data for the chart
               ObservableList<PieChart.Data> chartData =
                        PieChartUtil.getChartData();
               chart.setData(chartData);
               StackPane root = new StackPane(chart);
               Scene scene = new Scene(root);
               stage.setScene(scene);
               stage.setTitle("A Pie Chart");
               stage.show();
        }
}
Listing 20-2

Using the PieChart Class to Create a Pie Chart

Customizing Pie Slices

Each pie slice data is represented by a Node. The reference to the Node can be obtained using the getNode() method of the PieChart.Data class. The Node is created when the slices are added to the pie chart. Therefore, you must call the getNode() method on the PieChart.Data representing the slice after adding it to the chart. Otherwise, it returns null. The program in Listing 20-3 customizes all pie slices of a pie chart to add a tool tip to them. The tool tip shows the slice name, pie value, and percent pie value. The addSliceTooltip() method contains the logic to accessing the slice Nodes and adding the tool tips. You can customize pie slices to animate them, let the user drag them out from the pie using the mouse, etc. See Figure 20-3.
Figure 20-3

A pie slice showing a tool tip with its pie value and percentage of the total pie

// PieSliceTest.java
// ...find in the book's download area.
Listing 20-3

Adding Tool Tips to Pie Slices

Styling the PieChart with CSS

All properties, except the data property, defined in the PieChart class, can be styled using CSS as shown in the following:
.chart {
        -fx-clockwise: false;
        -fx-pie-label-visible: true;
        -fx-label-line-length: 10;
        -fx-start-angle: 90;
}
Four style classes are added to each pie slice added to a pie chart:
  • chart-pie

  • data<i>

  • default-color<j>

  • negative

The <i> in the style-class name data<i> is the slice index. The first slice has the class data0, the second data1, the third data2, etc.

The <j> in the style-class name default-color<j> is the color index of the series. In a pie chart, you can think of each slice as a series. The default CSS (Modena.css) defines eight series colors. If your pie slice has more than eight slices, the slice color will be repeated. The concept of series in a chart will be more evident when I discuss two-axis charts in the next section.

The negative style class is added only when the data for the slice is negative.

Define a style for a chart-pie style-class name if you want that style to apply to all pie slices. The following style will set a white border with 2px of background insets for all pie slices. It will show a wider gap between two slices as you have set 2px insets:
.chart-pie {
        -fx-border-color: white;
        -fx-background-insets: 2;
}
You can define colors for pie slices using the following styles. It defines colors for only five slices. Slices beyond the sixth one will use default colors:
.chart-pie.default-color0 {-fx-pie-color: red;}
.chart-pie.default-color1 {-fx-pie-color: green;}
.chart-pie.default-color2 {-fx-pie-color: blue;}
.chart-pie.default-color3 {-fx-pie-color: yellow;}
.chart-pie.default-color4 {-fx-pie-color: tan;}

Using More Than Eight Series Colors

It is quite possible that you will have more than eight series (slices in a pie chart) in a chart, and you do not want to repeat the colors for the series. The technique is discussed for a pie chart. However, it can be used for a two-axis chart as well.

Suppose you want to use a pie that will display populations of ten countries. If you use the code for this pie chart, the colors for the ninth and tenth slices will be the same as the colors for the first and second slices, respectively. First, you need to define the colors for the ninth and tenth slices as shown in Listing 20-4.
/* additional_series_colors.css */
.chart-pie.default-color8 {
        -fx-pie-color: gold;
}
.chart-pie.default-color9 {
        -fx-pie-color: khaki;
}
Listing 20-4

Additional Series Colors

The pie slices and the legend symbols will be assigned style-class names such as default-color0, default-color2default-color7. You need to identify the nodes for the slices and legend symbols associated with data items with an index greater than seven and replace their default-color<j> style-class name with the new ones. For example, for the ninth and tenth slices, the style-class names are default-color0 and default-color1 as the color series number is assigned as (dataIndex % 8). You will replace them with default-color9 and default-color10.

The program in Listing 20-5 shows how to change the colors for the slices and legend symbols. It adds ten slices to a pie chart. The setSeriesColorStyles() method replaces the style-class names for the slice nodes for the ninth and tenth slices and for their associated legend symbols. Figure 20-4 shows the pie chart. Notice the colors for “Germany” and “Indonesia” are gold and khaki as set in the CSS. Comment the last statement in the start() method , which is a call to the setSeriesColorStyles(), and you will find that the colors for “Germany” and “Indonesia” will be the same as the colors for “China” and “India.”
// PieChartExtraColor.java
// ...find in the book's download area.
Listing 20-5

A Pie Chart Using Color Series Up to Index 10

Figure 20-4

A pie chart using over eight slice colors

Using Background Images for Pie Slices

You can also use a background image in a pie slice. The following style defines the background image for the first pie slice:
.chart-pie.data0 {
        -fx-background-image: url("china_flag.jpg");
}
Listing 20-6 contains the content of a CSS file named pie_slice.css. It defines styles that specify the background images used for pie slices, the preferred size of the legend symbols, and the length of the line joining the pie slices and their labels.
// pie_slice.css
/* Set a background image for pie slices */
.chart-pie.data0 {-fx-background-image: url("china_flag.jpg");}
.chart-pie.data1 {-fx-background-image: url("india_flag.jpg");}
.chart-pie.data2 {-fx-background-image: url("brazil_flag.jpg");}
.chart-pie.data3 {-fx-background-image: url("uk_flag.jpg");}
.chart-pie.data4 {-fx-background-image: url("usa_flag.jpg");}
/* Set the preferred size for legend symbols */
.chart-legend-item-symbol {
        -fx-pref-width: 100;
        -fx-pref-height: 30;
}
.chart {
        -fx-label-line-length: 10;
}
Listing 20-6

 A CSS for Customizing Pie Slices

The program in Listing 20-7 creates a pie chart. It uses the same data as you have been using in our previous examples. The difference is that it sets a CSS defined in a pie_slice.css file:
// Set a CSS for the scene
scene.getStylesheets().addAll("resources/css/pie_slice.css");
The resulting window is shown in Figure 20-5. Notice that slices and legend symbols show the flags of the countries. It is important to keep in mind that you have matched the index of the chart data and the index in the CSS file to match countries and their flags.
Figure 20-5

A pie chart using a background image for its slices

Tip

It is also possible to style the shape of the line joining the pie slices and their labels, labels for the pie slices, and the legend symbols in a pie chart.

// PieChartCustomSlice.java
// ...find in the book's download area.
Listing 20-7

Using Pie Slices with a Background Image

Understanding the XYChart

An instance of a concrete subclass of the abstract XYChart<X,Y> class defines a two-axis chart. The generic type parameters X and Y are the data types of values plotted along the x-axis and y-axis, respectively.

Representing Axes in an XYChart

An instance of a concrete subclass of the abstract Axis<T> class defines an axis in the XYChart . Figure 20-6 shows a class diagram for the classes representing axes.
Figure 20-6

A class diagram for classes representing axes in an XYChart

The abstract Axis<T> class is the base class for all classes representing axes. The generic parameter T is the type of the values plotted along the axis, for example, String, Number, etc. An axis displays ticks and tick labels. The Axis<T> class contains properties to customize the ticks and tick labels. An axis can have a label, which is specified in the label property.

The concrete subclasses CategoryAxis and NumberAxis are used for plotting String and Number data values along an axis, respectively. They contain properties specific to the data values. For example, NumberAxis inherits ValueAxis<T>’s lowerBound and upperBound properties, which specify the lower and upper bounds of the data plotted on the axis. By default, the range of the data on an axis is automatically determined based on the data. You can turn off this feature by setting the autoRanging property in the Axis<T> class to false. The following snippet of code creates an instance of the CategoryAxis and NumberAxis and sets their labels:
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("Country");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Population (in millions)");
Tip

Use a CategoryAxis to plot String values along an axis, and use a NumberAxis to plot numeric values along an axis.

Adding Data to an XYChart

Data in an XYChart represents points in the 2D plane defined by the x-axis and y-axis. A point in a 2D plane is specified using the x and y coordinates, which are values along the x-axis and y-axis, respectively. The data in an XYChart is specified as an ObservableList of named series. A series consists of multiple data items, which are points in the 2D plane. How the points are rendered depends on the chart type. For example, a scatter chart shows a symbol for a point, whereas a bar chart shows a bar for a point.

An instance of the nested static XYChart.Data<X,Y> class represents a data item in a series. The class defines the following properties:
  • XValue

  • YValue

  • extraValue

  • node

The XValue and YValue are the values for the data item along the x-axis and y-axis, respectively. Their data types need to match the data type of the x-axis and y-axis for the chart. The extraValue is an Object, which can be used to store any additional information for the data item. Its use depends on the chart type. If the chart does not use this value, you can use it for any other purpose: for example, to store the tool tip value for the data item. The node specifies the node to be rendered for the data item in the chart. By default, the chart will create a suitable node depending on the chart type.

Suppose both axes of an XYChart plot numeric values. The following snippet of code creates some data items for the chart. The data items are the population of China in 1950, 2000, and 2050:
XYChart.Data<Number, Number> data1 = new XYChart.Data<>(1950, 555);
XYChart.Data<Number, Number> data2 = new XYChart.Data<>(2000, 1275);
XYChart.Data<Number, Number> data3 = new XYChart.Data<>(2050, 1395);
An instance of the nested static XYChart.Series<X,Y> class represents a series of data items. The class defines the following properties:
  • name

  • data

  • chart

  • node

The name is the name of the series. The data is an ObservableList of XYChart.Data<X,Y>. The chart is a read-only reference to the chart to which the series belong. The node is a Node to display for this series. A default node is automatically created based on the chart type. The following snippet of code creates a series, sets its name, and adds data items to it:
XYChart.Series<Number, Number> seriesChina = new XYChart.Series<>();
seriesChina.setName("China");
seriesChina.getData().addAll(data1, data2, data3);
The data property of the XYChart class represents the data for the chart. It is an ObservableList of XYChart.Series class. The following snippet of code creates and adds the data for an XYChart chart assuming the data series seriesIndia and seriesUSA exist:
XYChart<Number, Number> chart = ...
chart.getData().addAll(seriesChina, seriesIndia, seriesUSA);

How the data items for a series are displayed depends on the specific chart type. Every chart type has a way to distinguish one series from another.

You will reuse the same series of data items representing the population of some countries in some years several times. Listing 20-8 has code for a utility class. The class consists of two static methods that generate and return XYChart data. The getCountrySeries() method returns the list of series that plots the years along the x-axis and the corresponding populations along the y-axis. The getYearSeries() method returns a list of series that plots the countries along the x-axis and the corresponding populations along the y-axis. You will be calling these methods to get data for our XYCharts in subsequent sections.
// XYChartDataUtil.java
// ...abbreviated, find the full listing in the book's download area.
package com.jdojo.chart;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;
@SuppressWarnings("unchecked")
public class XYChartDataUtil {
    public static
    ObservableList<XYChart.Series<Number, Number>> getCountrySeries() {
        XYChart.Series<Number, Number> seriesChina =
            new XYChart.Series<>();
        seriesChina.setName("China");
        seriesChina.getData().addAll(
            new XYChart.Data<>(1950, 555),
            new XYChart.Data<>(2000, 1275),
            ...
        );
        ...
        ObservableList<XYChart.Series<Number, Number>> data =
          FXCollections.<XYChart.Series<Number, Number>>observableArrayList();
        data.addAll(seriesChina, seriesIndia, seriesUSA);
        return data;
    }
    ...
}
Listing 20-8

A Utility Class to Generate Data Used in XYCharts

Understanding the BarChart

A bar chart renders the data items as horizontal or vertical rectangular bars. The lengths of the bars are proportional to the value of the data items.

An instance of the BarChart class represents a bar chart. In a bar chart, one axis must be a CategoryAxis and the other a ValueAxis/NumberAxis. The bars are drawn vertically or horizontally, depending on whether the CategoryAxis is the x-axis or the y-axis.

The BarChart contains two properties to control the distance between two bars in a category and the distance between two categories:
  • barGap

  • categoryGap

The default value is 4 pixels for the barGap and 10 pixels for the categoryGap.

The BarChart class contains three constructors to create bar charts by specifying axes, data, and gap between two categories:
  • BarChart(Axis<X> xAxis, Axis<Y> yAxis)

  • BarChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

  • BarChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data, double categoryGap)

Notice that you must specify at least the axes when you create a bar chart. The following snippet of code creates two axes and a bar chart with those axes:
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("Country");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Population (in millions)");
// Create a bar chart
BarChart<String, Number> chart = new BarChart<>(xAxis, yAxis);
The bars in the chart will appear vertically as the category axis is added as the x-axis. You can populate the chart with data using its setData() method :
// Set the data for the chart
chart.setData(XYChartDataUtil.getYearSeries());
The program in Listing 20-9 shows how to create and populate a vertical bar chart as shown in Figure 20-7.
// VerticalBarChart.java
// ...find in the book's download area.
Listing 20-9

Creating a Vertical Bar Chart

Figure 20-7

A vertical bar chart

The program in Listing 20-10 shows how to create and populate a horizontal bar chart as shown in Figure 20-8. The program needs to supply data to the chart in an ObservableList of XYChart.Series<Number,String>. The getYearSeries() method in the XYChartDataUtil class returns XYChart.Series<String,Number>. The getChartData() method in the program converts the series data from <String,Number> to <Number,String> format as needed to create a horizontal bar chart.
// HorizontalBarChart.java
// ...find in the book's download area.
Listing 20-10

Creating a Horizontal Bar Chart

Figure 20-8

A horizontal bar chart

Tip

Each bar in a bar chart is represented with a node. The user can interact with the bars in a bar chart, by adding event handlers to the nodes representing the data items. Please refer to the section on the pie chart for an example in which you added tool tips for the pie slices.

Styling the BarChart with CSS

By default, a BarChart is given style-class names: chart and bar-chart.

The following style sets the default values for the barGap and categoryGap properties for all bar charts to 0px and 20px. The bars in the same category will be placed next to each other:
.bar-chart {
        -fx-bar-gap: 0;
        -fx-category-gap: 20;
}
You can customize the appearance of the bars for each series or each data item in a series. Each data item in a BarChart is represented by a node. The node gets five default style-class names:
  • chart-bar

  • series<i>

  • data<j>

  • default-color<k>

  • negative

In series<i>, <i> is the series index. For example, the first series is given the style-class name as series0, the second as series1, etc.

In data<j>, <j> is the index of the data item within a series. For example, the first data item in each series gets a style-class name as data0, the second as data1, etc.

In default-color<k>, <k> is the series color index. For example, each data item in the first series will get a style-class name as default-color0, in the second series default-color1, etc. The default CS defines only eight series colors. The value for <k> is equal to (i%8), where i is the series index. That is, series colors will repeat if you have more than eight series in a bar chart. Please refer to the pie chart section on how to use unique colors for series with index greater than eight. The logic will be similar to the one used for a pie chart, with a difference that, this time, you will be looking up the bar-legend-symbol within a series instead of a pie-legend-symbol.

The negative class is added if the data value is negative.

Each legend item in a bar chart is given the following style-class names:
  • chart-bar

  • series<i>

  • bar-legend-symbol

  • default-color<j>

In series<i>, <i> is the series index. In default-color<j>, <j> is the color index of the series. The legend color will repeat, as the bar colors do, if the number of series exceeds eight.

The following style defines the color of the bars for all data items in series with series indices 0, 8, 16, 24, etc., as blue:
.chart-bar.default-color0 {
        -fx-bar-fill: blue;
}

Understanding the StackedBarChart

A stacked bar chart is a variation of the bar chart. In a stacked bar chart, the bars in a category are stacked. Except for the placement of the bars, it works the same way as the bar chart.

An instance of the StackedBarChart class represents a stacked bar chart. The bars can be placed horizontally or vertically. If the x-axis is a CategoryAxis, the bars are placed vertically. Otherwise, they are placed horizontally. Like the BarChart, one of the axes must be a CategoryAxis and the other a ValueAxis/NumberAxis.

The StackedBarChart class contains a categoryGap property that defines the gap between bars in adjacent categories. The default gap is 10px. Unlike the BarChart class, the StackedBarChart class does not contain a barGap property, as the bars in one category are always stacked.

The constructors of the StackedBarChart class are similar to the ones for the BarChart class. They let you specify the axes, chart data, and category gap.

There is one notable difference in creating the CategoryAxis for the BarChart and the StackedBarChart. The BarChart reads the category values from the data, whereas you must explicitly add all category values to the CategoryAxis for a StackedBarChart:
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("Country");
// Must set the categories in a StackedBarChart explicitly. Otherwise,
// the chart will not show bars.
xAxis.getCategories().addAll("China," "India," "Brazil," "UK," "USA");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Population (in millions)");
StackedBarChart<String, Number> chart = new StackedBarChart<>(xAxis, yAxis);
The program in Listing 20-11 shows how to create a vertical stacked bar chart. The chart is shown in Figure 20-9. To create a horizontal stacked bar chart, use a CategoryAxis as the y-axis.
// VerticalStackedBarChart.java
// ...find in the book's download area.
Listing 20-11

Creating a Vertical Stacked Bar Chart

Figure 20-9

A vertical stacked bar chart

Styling the StackedBarChart with CSS

By default, a StackedBarChart is given style-class names: chart and stacked-bar-chart.

The following style sets the default value for the categoryGap properties for all stacked bar charts to 20px. The bars in a category will be placed next to each other:
.stacked-bar-chart {
        -fx-category-gap: 20;
}

In a stacked bar chart, the style-class names assigned to the nodes representing bars and legend items are the same as that of a bar chart. Please refer to the section “Styling the BarChart with CSS” for more details.

Understanding the ScatterChart

A bar chart renders the data items as symbols. All data items in a series use the same symbol. The location of the symbol for a data item is determined by the values on the data item along the x-axis and y-axis.

An instance of the ScatterChart class represents a scatter chart. You can use any type of Axis for the x-axis and y-axis. The class does not define any additional properties. It contains constructors that allow you to create a scatter chart by specifying axes and data:
  • ScatterChart(Axis<X> xAxis, Axis<Y> yAxis)

  • ScatterChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

Recall that the autoRanging for an Axis is set to true by default. If you are using numeric values in a scatter chart, make sure to set the autoRanging to false. It is important to set the range of the numeric values appropriately to get uniformly distributed points in the chart. Otherwise, the points may be located densely in a small area, and it will be hard to read the chart.

The program in Listing 20-12 shows how to create and populate a scatter chart as shown in Figure 20-10. Both axes are numeric axes. The x-axis is customized. The autoRanging is set to false; reasonable lower and upper bounds are set. The tick unit is set to 50. If you do not customize these properties, the ScatterChart will automatically determine them, and the chart data will be hard to read:
NumberAxis xAxis = new NumberAxis();
xAxis.setLabel("Year");
xAxis.setAutoRanging(false);
xAxis.setLowerBound(1900);
xAxis.setUpperBound(2300);
xAxis.setTickUnit(50);
// ScatterChartTest.java
package com.jdojo.chart;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ScatterChartTest extends Application {
        public static void main(String[] args) {
               Application.launch(args);
        }
        @Override
        public void start(Stage stage) {
               NumberAxis xAxis = new NumberAxis();
               xAxis.setLabel("Year");
               // Customize the x-axis, so points are scattered uniformly
               xAxis.setAutoRanging(false);
               xAxis.setLowerBound(1900);
               xAxis.setUpperBound(2300);
               xAxis.setTickUnit(50);
               NumberAxis yAxis = new NumberAxis();
               yAxis.setLabel("Population (in millions)");
               ScatterChart<Number,Number> chart =
                        new ScatterChart<>(xAxis, yAxis);
               chart.setTitle("Population by Year and Country");
               // Set the data for the chart
               ObservableList<XYChart.Series<Number,Number>> chartData =
                   XYChartDataUtil.getCountrySeries();
               chart.setData(chartData);
               StackPane root = new StackPane(chart);
               Scene scene = new Scene(root);
               stage.setScene(scene);
               stage.setTitle("A Scatter Chart");
               stage.show();
        }
}
Listing 20-12

Creating a Scatter Chart

Figure 20-10

A scatter chart

Tip

You can use the node property for data items to specify symbols in a ScatterChart.

Styling the ScatterChart with CSS

The ScatterChart is not assigned any additional style-class name other than chart.

You can customize the appearance of the symbols for each series or each data item in a series. Each data item in a ScatterChart is represented by a node. The node gets five default style-class names:
  • chart-symbol

  • series<i>

  • data<j>

  • default-color<k>

  • negative

Please refer to the section “Styling the BarChart with CSS” for more details on the meanings of <i>, <j>, and <k> in these style-class names.

Each legend item in a scatter chart is given the following style-class names:
  • chart-symbol

  • series<i>

  • data<j>

  • default-color<k>

The following style will display the data items in the first series as triangles filled in blue. Note that only eight color series are defined. After that, colors are repeated as discussed at length in the section on the pie chart.
.chart-symbol.default-color0 {
        -fx-background-color: blue;
        -fx-shape: "M5, 0L10, 5L0, 5z";
}

Understanding the LineChart

A line chart displays the data items in a series by connecting them by line segments. Optionally, the data points themselves may be represented by symbols. You can think of a line chart as a scatter chart with symbols in a series connected by straight line segments. Typically, a line chart is used to view the trend in data change over time or in a category.

An instance of the LineChart class represents a line chart. The class contains a createSymbols property, which is set to true by default. It controls whether symbols are created for the data points. Set it to false to show only straight lines connecting the data points in a series.

The LineChart class contains two constructors to create line charts by specifying axes and data:
  • LineChart(Axis<X> xAxis, Axis<Y> yAxis)

  • LineChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

The program in Listing 20-13 shows how to create and populate a line chart as shown in Figure 20-11. The program is the same as for using the scatter chart, except that it uses the LineChart class. The chart displays circles as symbols for data items. You can remove the symbols by using the following statement, after you create the line chart:
// Do not create the symbols for the data items
chart.setCreateSymbols(false);
// LineChartTest.java
// ...find in the book's download area.
Listing 20-13

Creating a Line Chart

Figure 20-11

A line chart

Styling the LineChart with CSS

The LineChart is not assigned any additional style-class name other than chart. The following style specifies that the LineChart should not create symbols:
.chart {
        -fx-create-symbols: false;
}
The LineChart creates a Path node to show the lines connecting all data points for a series. A line for a series is assigned the following style-class names:
  • chart-series-line

  • series<i>

  • default-color<j>

Here, <i> is the series index, and <j> is the color index of the series.

If the createSymbols property is set to true, a symbol is created for each data point. Each symbol node is assigned the following style-class names:
  • chart-line-symbol

  • series<i>

  • data<j>

  • default-color<k>

Here, <i> is the series index, <j> is the data item index within a series, and <k> is the color index of the series.

Each series is assigned a legend item, which gets the following style-class names:
  • chart-line-symbol

  • series<i>

  • default-color<j>

The following styles set the line stroke for the color index 0 of the series to blue. The symbol for the series is also shown in blue:
.chart-series-line.default-color0 {
        -fx-stroke: blue;
}
.chart-line-symbol.default-color0 {
        -fx-background-color: blue, white;
}

Understanding the BubbleChart

A bubble chart is very similar to a scatter chart, except that it has the ability to represent three values for a data point. A bubble is used to represent a data item in a series. You can set the radius of the bubble to represent the third value for the data point.

An instance of the BubbleChart class represents a bubble chart. The class does not define any new properties. A bubble chart uses the extraValue property of the XYChart.Data class to get the radius of the bubble. The bubble is an ellipse whose radii are scaled based on the scale used for the axes. Bubbles look more like a circle (or less stretched on one direction) if the scales for the x-axis and y-axis are almost equal.

Tip

The bubble radius is set by default, which is scaled using the scale factor of the axes. You may not see the bubbles if the scale factors for axes are very small. To see the bubbles, set the extraValue in data items to a high value or use higher scale factors along the axes.

The BubbleChart class defines two constructors:
  • BubbleChart(Axis<X> xAxis, Axis<Y> yAxis)

  • BubbleChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

The program in Listing 20-14 shows how to create a bubble chart as shown in Figure 20-12. The chart data is passed to the setBubbleRadius() method , which explicitly sets the extraValue for all data points to 20px. If you want to use the radii of bubbles to represent another dimension of data, you can set the extraValue accordingly.
// BubbleChartTest.java
// ...find in the book's download area.
Listing 20-14

Creating a Bubble Chart

Figure 20-12

A bubble chart

Styling the BubbleChart with CSS

The BubbleChart is not assigned any additional style-class name other than chart.

You can customize the appearance of the bubbles for each series or each data item in a series. Each data item in a BubbleChart is represented by a node. The node gets four default style-class names:
  • chart-bubble

  • series<i>

  • data<j>

  • default-color<k>

Here, <i> is the series index, <j> is the data item index within a series, and <k> is the color index of the series.

Each series is assigned a legend item, which gets the following style-class names:
  • chart-bubble

  • series<i>

  • bubble-legend-symbol

  • default-color<k>

Here, <i> and <k> have the same meanings as described earlier.

The following style sets the fill color for the series color index 0 to blue. The bubbles and legend symbols for the data items in the first series will be displayed in blue. The color will repeat for series indices 8, 16, 24, etc.
.chart-bubble.default-color0 {
        -fx-bubble-fill: blue;
}

Understanding the AreaChart

The area chart is a variation of the line chart. It draws lines connecting all data items in a series and, additionally, fills the area between where the line and the x-axis are painted. Different colors are used to paint areas for different series.

An instance of the AreaChart represents an area chart. Like the LineChart class, the class contains a createSymbols property to control whether symbols are drawn at the data points. By default, it is set to true. The class contains two constructors:
  • AreaChart(Axis<X> xAxis, Axis<Y> yAxis)

  • AreaChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

The program in Listing 20-15 shows how to create an area chart as shown in Figure 20-13. There is nothing new in the program, except that you have used the AreaChart class to create the chart. Notice that the area for a series overlays the area for the preceding series.
// AreaChartTest.java
// ...find in the book's download area.
Listing 20-15

Creating an Area Chart

Figure 20-13

An area chart

Styling the AreaChart with CSS

The AreaChart is not assigned any additional style-class name other than chart. The following style specifies that the AreaChart should not create symbols for representing the data points:
.chart {
        -fx-create-symbols: false;
}
Each series in an AreaChart is represented by a Group containing two Path nodes. One Path represents the line segment connecting all data points in the series, and another Path represents the area covered by the series. The Path node representing the line segment for a series is assigned the following style-class names:
  • chart-series-area-line

  • series<i>

  • default-color<j>

Here, <i> is the series index, and <j> is the color index of the series.

The Path node representing the area for a series is assigned the following style-class names:
  • chart-series-area-fill

  • series<i>

  • default-color<j>

Here, <i> is the series index, and <j> is the color index of the series.

If the createSymbols property is set to true, a symbol is created for each data point. Each symbol node is assigned the following style-class names:
  • chart-area-symbol

  • series<i>

  • data<j>

  • default-color<k>

Here, <i> is the series index, <j> is the data item index within a series, and <k> is the color index of the series.

Each series is assigned a legend item, which gets the following style-class names:
  • chart-area-symbol

  • series<i>

  • area-legend-symbol

  • default-color<j>

Here, <i> is the series index, and <j> is the color index of the series.

The following style sets the area fill color for the color index 0 for the series to blue with 20% opacity. Make sure to set transparent colors for the area fills as areas overlap in an AreaChart :
.chart-series-area-fill.default-color0 {
        -fx-fill: rgba(0, 0, 255, 0.20);
}
The following styles set the blue as the color for symbols, line segment, and legend symbol for the color index 0 for the series:
/* Data point symbols color */
.chart-area-symbol.default-color0. {
        -fx-background-color: blue, white;
}
/* Series line segment color */
.chart-series-area-line.default-color0 {
        -fx-stroke: blue;
}
/* Series legend symbol color */
.area-legend-symbol.default-color0 {
        -fx-background-color: blue, white;
}

Understanding the StackedAreaChart

The stacked area chart is a variation of the area chart. It plots data items by painting an area for each series. Unlike the area chart, areas for series do not overlap; they are stacked.

An instance of the StackedAreaChart represents a stacked area chart. Like the AreaChart class, the class contains a createSymbols property. The class contains two constructors:
  • StackedAreaChart (Axis<X> xAxis, Axis<Y> yAxis)

  • StackedAreaChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<XYChart.Series<X,Y>> data)

The program in Listing 20-16 shows how to create a stacked area chart as shown in Figure 20-14. The program is the same as the one that created an AreaChart, except that you have used the StackedAreaChart class to create the chart.
// StackedAreaChartTest.java
// ...find in the book's download area.
Listing 20-16

Creating a Stacked Area Chart

Figure 20-14

A stacked area chart

Styling the StackedAreaChart with CSS

Styling a StackedAreaChart is the same as styling an AreaChart. Please refer to the section “Styling the AreaChart with CSS” for more details.

Customizing XYChart Appearance

You have seen how to apply chart-specific CSS styles to customize the appearance of charts. In this section, you will look at some more ways to customize the XYChart plot and axes. The XYChart class contains several boolean properties to change the chart plot appearance:
  • alternativeColumnFillVisible

  • alternativeRowFillVisible

  • horizontalGridLinesVisible

  • verticalGridLinesVisible

  • horizontalZeroLineVisible

  • verticalZeroLineVisible

The chart area is divided into a grid of columns and rows. Horizontal lines are drawn passing through major ticks on the y-axis making up rows. Vertical lines are drawn passing through major ticks on the x-axis making up columns.

Setting Alternate Row/Column Fill

The alternativeColumnFillVisible and alternativeRowFillVisible control whether alternate columns and rows in the grid are filled. By default, alternativeColumnFillVisible is set to false, and alternativeRowFillVisible is set to true.

As of the time of this writing, setting the alternativeColumnFillVisible and alternativeRowFillVisible properties does not have any effects in JavaFX 8, which uses Modena CSS by default. There are two solutions. You can use the Caspian CSS for your application using the following statement:
Application.setUserAgentStylesheet(Application.STYLESHEET_CASPIAN);
The other solution is to include the following styles in your application CSS:
.chart-alternative-column-fill {
        -fx-fill: #eeeeee;
        -fx-stroke: transparent;
        -fx-stroke-width: 0;
}
.chart-alternative-row-fill {
        -fx-fill: #eeeeee;
        -fx-stroke: transparent;
        -fx-stroke-width: 0;
}

These styles are taken from Caspian CSS. These styles set the fill and stroke properties to null in Modena CSS.

Showing Zero Line Axes

The axes for a chart may not include zero lines. Whether zero lines are included depends on the lower and upper bounds represented by the axes. The horizontalZeroLineVisible and verticalZeroLineVisible control whether zero lines should be visible. By default, they are visible. Note that the zero line for an axis is visible only when the axis has both positive and negative data to plot. If you have negative and positive values along the y-axis, an additional horizontal axis will appear indicating the zero value along the y-axis. The same rule applies for values along the x-axis. If the range for an axis is set explicitly using its lower and upper bounds, the visibility of the zero line depends on whether zero falls in the range.

Showing Grid Lines

The horizontalGridLinesVisible and verticalGridLinesVisible specify whether the horizontal and vertical grid lines are visible. By default, both are set to true.

Formatting Numeric Tick Labels

Sometimes, you may want to format the values displayed on a numeric axis. You want to format the labels for the numeric axis for different reasons:
  • You want to add prefixes or suffixes to the tick labels. For example, you may want to display a number 100 as $100 or 100M.

  • You may be supplying the chart scaled data to get an appropriate scale value for the axis. For example, for the actual value 100, you may be supplying 10 to the chart. In this case, you would like to display the actual value 100 for the label.

The ValueAxis class contains a tickLabelFormatter property, which is a StringConverter, and it is used to format tick labels. By default, tick labels for a numeric axis are formatted using a default formatter. The default formatter is an instance of the static inner class NumberAxis.DefaultFormatter.

In our examples of XYChart, you had set the label for the y-axis to “Population (in millions)” to indicate that the tick values on the axis are in millions. You can use a label formatter to append “M” to the tick values to indicate the same meaning. The following snippet of code will accomplish this:
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Population");
// Use a formatter for tick labels on y-axis to append
// M (for millions) to the population value
yAxis.setTickLabelFormatter(new StringConverter<Number>() {
        @Override
        public String toString(Number value) {
               // Append M to the value
               return Math.round(value.doubleValue()) + "M";
        }
        @Override
        public Number fromString(String value) {
               // Strip M from the value
               value = value.replaceAll("M", "");
               return Double.parseDouble(value);
        }
});
The NumberAxis.DefaultFormatter works better for adding a prefix or suffix to tick labels. This formatter is kept in sync with the autoRanging property for the axis. You can pass a prefix and a suffix to the constructor. The following snippet of code accomplishes the same thing as the preceding snippet of code:
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Population");
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis, null, "M"));

You can customize several visual aspects of an Axis. Please refer to the API documentation for the Axis class and its subclasses for more details.

The program in Listing 20-17 shows how to customize a line chart. The chart is shown in Figure 20-15. It formats the tick labels on the y-axis to append “M” to the label value. It hides the grid lines and shows the alternate column fills.
// CustomizingCharts.java
// ...find in the book's download area.
Listing 20-17

Formatting Tick Labels and Customizing Chart Plot

Figure 20-15

 A line chart with formatted tick labels and customized plot

Summary

A chart is a graphical representation of data. Charts provide an easier way to analyze a large volume of data visually. Typically, they are used for reporting purposes. Different types of charts exist. They differ in the way they represent the data. Not all types of charts are suitable for analyzing all types of data. For example, a line chart is suitable for understanding the comparative trend in data, whereas a bar chart is suitable for comparing data in different categories.

JavaFX supports charts, which can be integrated in a Java application by writing a few lines of code. It contains a comprehensive, extensible Chart API that provides built-in support for several types of charts. The Chart API consists of a number of predefined classes in the javafx.scene.chart package. Few of those classes are Chart, XYChart, PieChart, BarChart, and LineChart.

The abstract Chart is the base class for all charts. It inherits the Node class. Charts can be added to a scene graph. They can also be styled with CSS as any other nodes. Every chart in JavaFX has three parts: a title, a legend, and data. Different types of charts define their data differently. The Chart class contains the properties to deal with the title and legend.

A chart can be animated. The animated property in the Chart class specifies whether the change in the content of the chart is shown with some type of animation. By default, it is true.

A pie chart consists of a circle divided into sectors of different central angles. Typically, a pie is circular. The sectors are also known as pie pieces or pie slices. Each sector in the circle represents a quantity of some kind. The central angle of the area of a sector is proportional to the quantity it represents. An instance of the PieChart class represents a pie chart.

A bar chart renders the data items as horizontal or vertical rectangular bars. The lengths of the bars are proportional to the value of the data items. An instance of the BarChart class represents a bar chart.

A stacked bar chart is a variation of the bar chart. In a stacked bar chart, the bars in a category are stacked. Except for the placement of the bars, it works the same way as the bar chart. An instance of the StackedBarChart class represents a stacked bar chart.

A scatter chart renders the data items as symbols. All data items in a series use the same symbol. The location of the symbol for a data item is determined by the values on the data item along the x-axis and y-axis. An instance of the ScatterChart class represents a scatter chart.

A line chart displays the data items in a series by connecting them by line segments. Optionally, the data points themselves may be represented by symbols. You can think of a line chart as a scatter chart with symbols in a series connected by straight line segments. Typically, a line chart is used to view the trend in data change over time or in a category. An instance of the LineChart class represents a line chart.

A bubble chart is very similar to a scatter chart, except that it has the ability to represent three values for a data point. A bubble is used to represent a data item in a series. You can set the radius of the bubble to represent the third value for the data point. An instance of the BubbleChart class represents a bubble chart.

The area chart is a variation of the line chart. It draws lines connecting all data items in a series and, additionally, fills the area between where the line and the x-axis are painted. Different colors are used to paint areas for different series. An instance of the AreaChart represents an area chart.

The stacked area chart is a variation of the area chart. It plots data items by painting an area for each series. Unlike the area chart, areas for series do not overlap; they are stacked. An instance of the StackedAreaChart represents a stacked area chart.

Besides using CSS to customize the appearance of charts, the Chart API provides several properties and methods to customize charts’ appearance such as adding alternate row/column fills, showing zero line axes, showing grid lines, and formatting numeric tick labels.

The next chapter will discuss how to work with images in JavaFX using the Image API.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.180.223