Charts in Java Swing With JFreeChart

Java Swing, the GUI toolkit for Java, has no built-in graphing and charting package. Several free packages are available, the best of which is widely considered to be JFreeChart. JFreeChart is open source and free even for commercial use. So what's the catch? The guys who have created JFreeChart don't provide any tutorials on how to use it, and indeed they sell the developer guide (which is no doubt excellent) at a premium price.

So while you can view the Javadoc documentation here, you're a bit stuck if you want a basic sample application to work from.

Well, not entirely stuck; you can un-jar the demos that come with JFreeChart and browse to the source code.

However, to save you the trouble, I've already done just that, and here's a very brief tutorial on using JFreeChart (after all, I don't want to undermine the efforts of the developers to sell their documentation!).

A Basic Swing Chart Application



In this tutorial, we'll create a simple XY line chart. Don't be afraid to consult the JFreeChart API guide to find out what the various function parameters do (since I won't explain them here).

The first step is, of course, to create a dataset to work with. You'll probably want a method that formats your data for JFreeChart, like this:

 
private XYDataset createDataset() {

        DefaultXYDataset ds = new DefaultXYDataset();

        double[][] data = { {0.1, 0.2, 0.3}, {1, 2, 3} };

        ds.addSeries("series1", data);

        return ds;
    }
 

The data corresponding to a single line or set of bars on a chart is known as a "series", and you can have multiple lines (series) on one chart.

As you can see, I've hardcoded my data; there's one array for the x coordinates of your data points and one array for the y coordinates. But of course, you can read these values from a file or database.

Notice that for each chart type, there is an interface that the dataset for that chart type must implement. To help you implement the interface, there's a default implementation of each type available.

Now you can do this:

 
XYDataset ds = createDataset();
 

The next step is to create a chart and pass it your dataset. The ChartFactory methods have various parameters that you can see by looking at the API doc.

 
JFreeChart chart = 
ChartFactory.createXYLineChart("Test Chart",
                "x", "y", ds, PlotOrientation.VERTICAL, true, true,
                false);
 

Now finally you can add your chart to your Swing container. For that you'll need a ChartPanel. Then you can add it just like you'd add a JPanel or whatever.

 
ChartPanel cp = new ChartPanel(chart);
 

The Finished Work



The finished application looks like this:



OK, I didn't say it would be the most exciting chart ever. But it's not bad for ten minutes' work!

Here's the source:

 
import java.util.HashSet;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.data.xy.XYDataset;

public class App {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Charts");

                frame.setSize(600, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);

                XYDataset ds = createDataset();
                JFreeChart chart = ChartFactory.createXYLineChart("Test Chart",
                        "x", "y", ds, PlotOrientation.VERTICAL, true, true,
                        false);

                ChartPanel cp = new ChartPanel(chart);

                frame.getContentPane().add(cp);
            }
        });

    }

    private static XYDataset createDataset() {

        DefaultXYDataset ds = new DefaultXYDataset();

        double[][] data = { {0.1, 0.2, 0.3}, {1, 2, 3} };

        ds.addSeries("series1", data);

        return ds;
    }

}