Architecture & DesignWorking with JavaFX Chart APIs

Working with JavaFX Chart APIs

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

One of the most important aspects of reporting is to make the content as much visible as possible so that the essence of the information contained in the report reaches its audience quickly and effortlessly. Charts play a crucial role in this regard. Presenting raw data and trying to imagine the scenario associated with the data is not very easy, but charts represent a pictorial essence of the data and helps the viewer grasp the idea behind the crude data very quickly. JavaFX has built-in support to present crude data in picturesque form dynamically. The API has two facets: One either can extend the API classes and create a custom chart from scratch, or use the available chart-specific classes to create a chart with very minimum code. This article delves into key aspects of the chart APIs of JavaFX and show how to implement them. Quick examples are provided to assist you.

JavaFX Charts

JavaFX charts are not only easy to integrate with other parts of the application but also are imbibed with the extensible policy of object-oriented technology that may be customized as per the need of the developer. This is not a new thing, because object-oriented designs are always meant to be extensible, but the interesting part of the JavaFX chart API is that there are many ready-made chart classes that can be instantiated with a little or no change in its properties to get professional-looking charts. These chart classes are most common, customizable, and suit almost every need of the developer. In most cases, there is hardly any need to create a custom chart from scratch.

JavaFX provides eight such types of charts in the API library with their built-in functionality. Although there are many supporting classes and interfaces in the JavaFX chart API library, the concrete eight implementation is hierarchically arranged as follows.

The JavaFX chart API library hierarchy chart
Figure 1: The JavaFX chart API library hierarchy chart

Therefore, the eight common type of chart are: pie chart, bar chart, area chart, line chart, scatter chart, bubble chart, stacked area chart, and stacked bar chart.

The Pie Chart

The pie chart is a common chart format where information is rendered in a typical pie-slice structure. Each pie slice represents the proportional value of the data. The easiest way to create a pie chart in JavaFX is to instantiate the PieChart class and set the data as follows:

PieChart pie=new PieChart();

We can set the data for a pie chart with the help of the setData() method, which takes a parameter of type ObservableList<PieChart.Data>. The instance of PieChart.Data is actually a nested class of PieChart and renders one slice of the pie data. The constructor takes two parameters, as follows:

PieChart.Data(String title, Double value)

Here is a quick example to create a pie chart.

package org.mano.example;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createPieChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public PieChart createPieChart() {
      PieChart pie = new PieChart();
      ObservableList<PieChart.Data> data =
         FXCollections.observableArrayList();
      data.addAll(new PieChart.Data("Asia", 30.0),
         new PieChart.Data("Africa", 20.3),
         new PieChart.Data("North America", 16.3),
         new PieChart.Data("South America", 12.0),
         new PieChart.Data("Antartica", 8.9),
         new PieChart.Data("Europe", 6.7),
         new PieChart.Data("Australia", 5.2));

      pie.setData(data);
      pie.setTitle("The Continents: Land Area");
      return pie;
   }
}

Output

The finished pie chart from the preceding code
Figure 2: The finished pie chart from the preceding code

The XYChart

The XYChart is an abstract class which forms the basis of all two-axis charts in JavaFX. The two-axis charts are those where typically a single element represents a pair and is plotted in a Cartesian co-ordinate area marked by the x-axis as columns and the y-axis as rows. The concrete derivatives of this abstract class are: BarChart, AreaChart, BubbleChart, LineChart, ScatterChart, StackedAreaChart, and StackedBarChart. Unlike XYChart, the PieChart does not do not lay down data in an x- and y-axis format. This is the main difference between a PieChart and an XYChart. The data in an XYChart is ordered in a series. But, the way this series of data will be rendered depends upon the implementation or type of the XYChart actually instantiated.

Because XYChart is represented in an x- and y-axis format, the constructor of XYChart is as follows.

XYChart(Axis<X> xAxis, Axis<Y> yAxis)

Axis is an abstract class which extends Region. There are two concrete subclasses of this class, called CategoryAxis and ValueAxis. The CategoryAxis is instantiated to render labels of the chart in string format whereas the ValueAxis renders the data entries in Number format. The Number is also an abstract class which forms the base class for all numeric types in Java such as the wrapper classes: Double, Integer, Float, Long, Short, and so forth.

BarChart Example

A bar chart is typically used to show the relative difference between the different series of a given category. The following example illustrates how to create one in Java.

package org.mano.example;

import java.util.*;

import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.chart.*;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createBarChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
         getDummyChartData() {
      ObservableList<XYChart.Series<String, Double>> data =
         FXCollections.observableArrayList();
      Series<String, Double> as = new Series<>();
      Series<String, Double> bs = new Series<>();
      Series<String, Double> cs = new Series<>();
      Series<String, Double> ds = new Series<>();
      Series<String, Double> es = new Series<>();
      Series<String, Double> fs = new Series<>();
      as.setName("A-Series");
      bs.setName("B-Series");
      cs.setName("C-Series");
      ds.setName("D-Series");
      es.setName("E-Series");
      fs.setName("F-Series");

      Random r = new Random();

      for (int i = 1900; i < 2017; i += 10) {

         as.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
         bs.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
         cs.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
         ds.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
         es.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
         fs.getData().add(new XYChart.Data<>
         (Integer.toString(i), r.nextDouble()));
      }
      data.addAll(as, bs, cs, ds, es, fs);
      return data;
   }

   public XYChart<CategoryAxis, NumberAxis>
         createBarChart() {
      CategoryAxis xAxis = new CategoryAxis();
      NumberAxis yAxis = new NumberAxis();
      BarChart bc = new BarChart<>(xAxis, yAxis);
      bc.setData(getDummyChartData());
      bc.setTitle("Bar Chart on Random Number");
      return bc;
   }
}

Output

The finished bar chart from the preceding code
Figure 3: The finished bar chart from the preceding code

ScatterChart Example

The data items in a scatter chart are represented as symbols within the area of the XY axis. The previous bar chart code can be easily converted to create a scatter chart by making the following changes.

package org.mano.example;

import java.util.*;

import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.chart.*;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createScatterChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
         getDummyChartData() {
      // ... Same as above
   }

   public XYChart<CategoryAxis, NumberAxis>
         createScatterChart() {

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

      ScatterChart sc = new ScatterChart<>(xAxis, yAxis);
      sc.setData(getDummyChartData());
      sc.setTitle("Scatter chart on random data");

      return sc;
   }
}

Output

The finished scatter chart from the preceding code
Figure 4: The finished scatter chart from the preceding code

LineChart Example

As we can see, the data items in the scatter chart are represented with the help of dots or symbols. Sometimes, it is convenient to connect the dots. This improves the visibility of change in trends from one marked point to another. The line chart does exactly this. The next example illustrates the idea.

package org.mano.example;

// ... Import statements same as above

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createLineChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
         getDummyChartData() {

      // ... Same as above
   }

   public XYChart<CategoryAxis, NumberAxis> createLineChart() {
      CategoryAxis xAxis = new CategoryAxis();
      NumberAxis yAxis = new NumberAxis();
      LineChart lc = new LineChart<>(xAxis, yAxis);
      lc.setData(getDummyChartData());
      lc.setTitle("Line chart on random data");
      return lc;
   }
}

Output

The finished line chart from the preceding code
Figure 5: The finished line chart from the preceding code

StackedBarChart Example

The StackedBarChart is another version of the BarChart in the sense that here, instead of representing different bars one next to another, the StackedBarChart stacks the categories on top of another.

package org.mano.example;

// ... Import statements same as above

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createStackedBarChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
         getDummyChartData() {

      // ... Same as above
   }

   public XYChart<CategoryAxis, NumberAxis>
         createStackedBarChart() {
      CategoryAxis xAxis = new CategoryAxis();
      NumberAxis yAxis = new NumberAxis();
      StackedBarChart sbc = new StackedBarChart<>(xAxis, yAxis);
      sbc.setData(getDummyChartData());
      sbc.setTitle("Stacked bar chart on random data");
      return sbc;
   }
}

Output

The finished stacked bar chart from the preceding code
Figure 6: The finished stacked bar chart from the preceding code

AreaChart Example

In an AreaChart, the region under the lines connecting the dots are filled to represent a category.

package org.mano.example;

// ... Import statements same as above

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createAreaChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
      getDummyChartData() {

      // ... Same as above
   }

   public XYChart<CategoryAxis, NumberAxis> createAreaChart() {
      CategoryAxis xAxis = new CategoryAxis();
      NumberAxis yAxis = new NumberAxis();
      AreaChart ac = new AreaChart<>(xAxis, yAxis);
      ac.setData(getDummyChartData());
      ac.setTitle("Area chart on random data");
      return ac;

   }
}

Output

The finished area chart from the preceding code
Figure 7: The finished area chart from the preceding code

StackedAreaChart Example

The StackedAreaChart shows the sum of the values of the same category and do not show individual areas like the AreaChart does. This is in essence another version of the AreaChart.

package org.mano.example;

// ... Import statements same as above

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createStackedAreaChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<String, Double>>
         getDummyChartData() {

      // ... Same as above
   }

   public XYChart<CategoryAxis, NumberAxis> createStackedAreaChart() {
      CategoryAxis xAxis = new CategoryAxis();
      NumberAxis yAxis = new NumberAxis();
      StackedAreaChart sac = new StackedAreaChart<>(xAxis, yAxis);
      sac.setData(getDummyChartData());
      sac.setTitle("Stacked area chart on random data");
      return sac;
   }
}

Output

The finished stacked area chart from the preceding code
Figure 8: The finished stacked area chart from the preceding code

BubbleChart Example

The BubbleChart plots bubbles for data points in the series. This variation of the XYChart utilizes the additional properties of the XYChart.Data class in the sense that it is a special XYChart implementation among all the subclasses of the XYChart. Here, a data item is denoted by two or three parameters such as x-value, y-value, and, optionally, the value signifying the radius of the bubble. Here is an example to illustrate how to create one in Java.

package org.mano.example;

import java.util.*;

import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.chart.*;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class Main extends Application {

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

   @Override
   public void start(Stage stage) throws Exception {
      stage.setTitle("JavaFX Chart Demo");
      StackPane pane = new StackPane();
      pane.getChildren().add(createBubbleChart());
      stage.setScene(new Scene(pane, 400, 200));
      stage.show();
   }

   public ObservableList<XYChart.Series<Integer, Double>>
   getDummyChartData2() {
      ObservableList<XYChart.Series<Integer, Double>> data =
         FXCollections.observableArrayList();

      Series<Integer, Double> as = new Series<>();
      Series<Integer, Double> bs = new Series<>();
      Series<Integer, Double> cs = new Series<>();
      Series<Integer, Double> ds = new Series<>();
      Series<Integer, Double> es = new Series<>();
      Series<Integer, Double> fs = new Series<>();
      as.setName("A-Series");
      bs.setName("B-Series");
      cs.setName("C-Series");
      ds.setName("D-Series");
      es.setName("E-Series");
      fs.setName("F-Series");

      Random r = new Random();

      for (int i = 1900; i < 2017; i += 10) {
         double d = r.nextDouble();

         as.getData().add(new XYChart.Data<>
         (i, r.nextInt(32)+r.nextDouble(), 2 * d));
         bs.getData().add(new XYChart.Data<>
         (i,r.nextInt(32)+r.nextDouble(), 4 * d));
         cs.getData().add(new XYChart.Data<>
         (i,r.nextInt(32)+r.nextDouble(), 3 * d));
         ds.getData().add(new XYChart.Data<>
         (i,r.nextInt(32)+r.nextDouble(), 5 * d));
         es.getData().add(new XYChart.Data<>
         (i,r.nextInt(32)+r.nextDouble(), 1.5 * d));
         fs.getData().add(new XYChart.Data<>
         (i,r.nextInt(32)+r.nextDouble(), 1.7 * d));

      }

      data.addAll(as, bs, cs, ds, es, fs);
      return data;
   }

   public BubbleChart<Number, Number> createBubbleChart() {
      NumberAxis xAxis = new NumberAxis();
      NumberAxis yAxis = new NumberAxis();
      yAxis.setAutoRanging(false);
      yAxis.setLowerBound(0);
      yAxis.setUpperBound(30);

      xAxis.setAutoRanging(false);
      xAxis.setLowerBound(1900);
      xAxis.setUpperBound(2017);
      xAxis.setTickUnit(10);
      xAxis.setTickLabelFormatter(new StringConverter<Number>() {

         @Override
         public String toString(Number object) {
            return String.valueOf(object.intValue() / 10);
         }

         @Override
         public Number fromString(String string) {
            return Integer.valueOf(string) * 10;
         }
      });

      BubbleChart blc = new BubbleChart<>(xAxis, yAxis);
      blc.setData(getDummyChartData2());
      blc.setTitle("Bubble chart on random data");
      return blc;
   }
}

Output

The finished bubble chart from the preceding code
Figure 9: The finished bubble chart from the preceding code

Conclusion

One can use Cascading Style Sheets (CSS) to modify the default appearance of the JavaFX charts, such as altering the color scheme, modifying their legends and axes or chart symbols, and so on. JavaFX provides many chart-specific CSS tags to achieve this. The most important part of the JavaFX chart API is that it provides different variations of ready-to-use chart types. It is up to developers to choose the right type of chart that best matches their data-reporting scheme.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories