[JAVA] Graph creation with JFreeChart

Now that I've recently needed to write a program that uses JFreeChart to generate graphs, I'll summarize how to use JFreeChart.

concept

If you start by looking at the sample code, you can quickly create a simple graph, but if it gets a little complicated, you will soon lose track of where to set it. To prevent that from happening, let's start with the concept of JFreeChart.

グラフサンプル

Chart

Represents the entire graph. Normally, you create a Chart using the ChartFactory method, so it's easy to think that Chart determines the type of graph (Renderer determines the type of graph), but Chart's own direct belongings are the title and legend. (Legned), and only the Plot described below, the Chart is like just the whole frame.

Plot

The entire drawing area of the graph including the axes becomes a plot. The main items to bring are the Dataset, Renderer, and Axis. There are two types of Plot, Category Plot and XY Plot, depending on how you hold the data. Only Category type Dataset and Renderer can be set in Category Plot, and only XY type Dataset and Renderer can be set in XY Plot.

Category type

In a graph like that used in business, the Y-axis is a normal number, but the X-axis is not a normal number, and if it is a sales graph for each product, it will be a character string like product A. This is Category, and you need to use Category Plot to create such a graph.

In the above explanation, the terms X-axis and Y-axis are used for the sake of clarity, but depending on the graph, the meanings of the X-axis and Y-axis may be opposite. In JFreeChart, the name of the axis is called Domain Axis for the normal X-axis (representing Category) and Value Axis for the Y-axis.

XY type

For graphs where the X-axis is also a normal number, as is often the case in mathematics, use XY Plot.

In a typical monthly sales-like graph, the X-axis is the date, which can be represented by either Category Plot or XY Plot. In the former, 2017/7 is not treated as a continuous numerical value, but as a character string. In reality, many people use Category Plot. This is because the Category type renderer has more types of bar graphs.

Dataset

A Dataset is a collection of data to be displayed. In the Category type Dataset, the X-axis = Category value (example: April 2017), the Y-axis value (example: 10), and the data breakdown = Series, if any, the value (example: product A) is 1. It becomes one data.

Renderer

Renderer actually draws the graph based on the Dataset, and the type of Renderer = the type of graph. You can find out what kind of Renderer you have in Javadoc [org.jfreechart.chart.renderer.category Package](http://www.jfree.org/jfreechart/api/javadoc/org/jfree/chart/renderer/category/ package-summary.html) and [org.jfreechart.chart.renderer.xy package](http://www.jfree.org/jfreechart/api/javadoc/org/jfree/chart/renderer/xy/package-summary. Check the class of html).

To customize the look of your graph, use Renderer methods.

When creating a composite graph, add a Renderer / Dataset pair to the Plot for each graph type.

Sample code

Category type

This is the code that generates the sample graph shown at the beginning. If you have the above explanation in mind, you can easily understand it.

JFreeChartSample.java


public class JFreeChartSample {

	public void createChart(ChartType type) { //Allows you to change whether the bar part is a stack or a set with an argument
		//Creating a basic stacked bar chart Renderer/Dataset#0
		JFreeChart chart = ChartFactory.createStackedBarChart("Title", "Category", "Value", barDataset());
		CategoryPlot plot = (CategoryPlot) chart.getPlot(); //StackedBarChart is a Category type
		String filename = type.getFilename();
		if (type == ChartType.CLUSTERED) { //Change to collective bar chart
			BarRenderer barRenderer = new BarRenderer();
			barRenderer.setItemMargin(0.0); //Bar spacing within a category
			plot.setRenderer(barRenderer);
		}
		//Addition of polygonal line (total)
		LineAndShapeRenderer lineRenderer1 = new LineAndShapeRenderer();
		plot.setRenderer(1, lineRenderer1); // Renderer#1
		plot.setDataset(1, lineDataset1()); // Dataset#1
		//Renderer because I want to add a polygonal line (compared to the previous year) and separate the axis./Separate Dataset
		LineAndShapeRenderer lineRenderer2 = new LineAndShapeRenderer();
		plot.setRenderer(2, lineRenderer2); // Renderer#2
		plot.setDataset(2, lineDataset2()); // Dataset#2
		//Add axis
		NumberAxis axis = new NumberAxis("Compared to the previous year(%)");
		axis.setRange(0, 200);
		plot.setRangeAxis(1, axis); // RangeAxis#1
		plot.mapDatasetToRangeAxis(2, 1); // Dataset#2 is Range Axis#Use 1
		//Legend position
		chart.getLegend().setPosition(RectangleEdge.RIGHT);
		//Change drawing order Default descending order (#0 is the last) → Ascending order (#0 is displayed first, later is displayed above)
		plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
		
		//Image generation
		try {
			ChartUtilities.saveChartAsPNG(new File(filename), chart, 600, 400);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public enum ChartType {
		STACKED("stackedChart.png "), CLUSTERED("clusteredChart.png ");
		private String filename;
		ChartType(String filename) { this.filename = filename; }
		public String getFilename() { return filename; }
	}

	private DefaultCategoryDataset barDataset() {
 		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(10.0, "Product A", "April 2017");
		dataset.addValue(15.0, "Product B", "April 2017");
		dataset.addValue(10.0, "Product A", "May 2017");
		dataset.addValue(5.0, "Product B", "May 2017");
		dataset.addValue(5.0, "Product C", "May 2017");
		dataset.addValue(5.0, "Product A", "June 2017");
		dataset.addValue(10.0, "Product C", "June 2017");
		return dataset;
	}
	
	private DefaultCategoryDataset lineDataset1() {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(25.0, "total", "April 2017");
		dataset.addValue(20.0, "total", "May 2017");
		dataset.addValue(15.0, "total", "June 2017");
		return dataset;
	}

	private DefaultCategoryDataset lineDataset2() {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(100.0, "Compared to the previous year", "April 2017");
		dataset.addValue(60.0, "Compared to the previous year", "May 2017");
		dataset.addValue(80.0, "Compared to the previous year", "June 2017");
		return dataset;
	}
}

Recommended Posts

Graph creation with JFreeChart
CLI creation with thor
Java multi-project creation with Gradle
Introduced graph function with rails
API creation with Rails + GraphQL
Use Microsoft Graph with standard Java
Inquiry application creation with Spring Boot
[Rails] Initial data creation with seed
Web application creation with Nodejs with Docker
[Rails 6] Interactive graph drawing with Ajax + chart.js
Tool creation with JavaFX & self-contained package (distribution)
Tool creation with JavaFX & self-contained package (JavaFX edition)