JFreeChart 教程:从入门到精通
JFreeChart 是一个开源的 Java 图表库,功能强大,种类丰富,可以生成各种高质量的 2D 和 3D 图表,它被广泛应用于 Web 应用、Swing 和 JavaFX 桌面应用中。

目录
-
- 1. 环境准备
- 2. 第一个图表:最简单的饼图
- 3. 代码解析
-
- 1. 核心组件:
ChartFactory,JFreeChart,Plot,Dataset - 2. 数据集
- 3. 图表工厂
- 4. 图表对象
- 5. 绘图区
- 1. 核心组件:
-
- 1. 饼图
- 2. 柱状图 / 条形图
- 3. 折线图
- 4. 散点图
- 5. 时间序列图
- 6. 环形图
-
(图片来源网络,侵删)- 1. 设置标题和图例
- 2. 自定义坐标轴
- 3. 自定义数据标签和工具提示
- 4. 设置背景色和边框
- 5. 使用主题
-
- 1. 在 Swing 应用中显示图表
- 2. 生成图表并保存为图片文件
- 3. 在 Web 应用中动态生成图表
-
- 1. 处理大数据量
- 2. 交互功能
- 3. 许可证问题
第一部分:JFreeChart 快速入门
1. 环境准备
你需要下载 JFreeChart 的 JAR 文件,你可以从其官方网站 SourceForge 下载最新版本。
Maven 用户 (推荐): 在你的 pom.xml 文件中添加以下依赖:

<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.5.4</version> <!-- 请使用最新版本 -->
</dependency>
2. 第一个图表:最简单的饼图
让我们从一个经典的“Hello, World!”级别的饼图开始,这个例子将展示创建一个基本图表所需的最少代码。
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
public class FirstChart {
public static void main(String[] args) {
// 1. 准备数据集
PieDataset dataset = createDataset();
// 2. 使用 ChartFactory 创建图表
JFreeChart chart = ChartFactory.createPieChart(
"水果销售比例", // 图表标题
dataset, // 数据集
true, // 是否显示图例
true, // 是否生成工具提示
false // 是否生成URL
);
// 3. (可选) 自定义图表外观
customizeChart(chart);
// 4. 将图表显示在窗口中
ChartFrame frame = new ChartFrame("我的第一个饼图", chart);
frame.pack(); // 自动调整窗口大小以适应图表
frame.setVisible(true);
}
/**
* 创建一个示例数据集
*/
private static PieDataset createDataset() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("苹果", 30);
dataset.setValue("香蕉", 20);
dataset.setValue("橙子", 15);
dataset.setValue("葡萄", 35);
return dataset;
}
/**
* 自定义图表外观
*/
private static void customizeChart(JFreeChart chart) {
// 获取绘图区
PiePlot plot = (PiePlot) chart.getPlot();
// 设置标签格式:显示百分比
plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} ({2})"));
// 设置背景色为白色
plot.setBackgroundPaint(Color.WHITE);
}
}
运行这段代码,你将看到一个包含“苹果”、“香蕉”、“橙子”和“葡萄”销售比例的饼图窗口。
3. 代码解析
createDataset(): 创建数据集,对于饼图,我们使用DefaultPieDataset,它是一个简单的键值对集合,用来表示每个部分的名称和值。ChartFactory.createPieChart(...): 这是 JFreeChart 的核心工厂类,它提供了一系列静态方法,用于快速创建各种类型的图表,我们传入标题、数据集和一些布尔选项来配置图表。JFreeChart对象: 这是图表的核心对象,包含了图表的所有信息(标题、图例、绘图区等),创建后,你可以对它进行各种自定义。ChartFrame: 这是一个简单的 Swing 窗口类,它内部包含了一个ChartPanel,可以方便地显示JFreeChart对象。
第二部分:核心概念与架构
理解 JFreeChart 的核心架构对于创建复杂和自定义的图表至关重要。
1. 核心组件
JFreeChart 的设计遵循了清晰的分层结构:
Dataset(数据集): 图表的数据来源,它不关心数据如何呈现,只负责存储和管理数据。PieDataset用于饼图,CategoryDataset用于柱状图和折线图,XYDataset用于散点图和时间序列图。ChartFactory(图表工厂): 一个工具类,提供静态方法,根据Dataset快速创建JFreeChart对象的实例。JFreeChart(图表对象): 图表的顶层表示,它包含标题、图例和绘图区。Plot(绘图区): 图表的核心部分,负责将数据集Dataset中的数据可视化,饼图的绘图区是PiePlot,柱状图的绘图区是CategoryPlot,你可以通过修改Plot对象的属性来极大地改变图表的外观和行为。Renderer(渲染器): 与Plot配合使用,决定数据项的具体绘制样式。BarRenderer控制柱子的颜色和边框,LineAndShapeRenderer控制折线的样式和数据点的形状。
2. 数据集
PieDataset: 用于饼图,每个数据项有一个键(分类)和一个值(数值)。DefaultCategoryDataset: 用于柱状图、折线图等,数据按“行”和“列”组织,类似于一个二维表。- 行键:通常是数据系列名称,如 "2025年", "2025年"。
- 列键:通常是分类名称,如 "Q1", "Q2", "Q3", "Q4"。
DefaultXYDataset: 用于散点图、时间序列图,数据由一系列 (x, y) 坐标点组成。
3. 图表工厂
ChartFactory 是你开始创建图表的地方,它提供了 create...Chart 方法,如 createBarChart(), createLineChart() 等,这些方法简化了初始设置,但返回的 JFreeChart 对象是完全可定制的。
4. 图表对象
JFreeChart 对象是所有组件的容器,你可以通过它的方法获取和修改其他组件:
getTitle(): 获取/设置标题。getLegend(): 获取/设置图例。getPlot(): 获取绘图区。
5. 绘图区
Plot 是自定义的重点,对于柱状图,你可以通过 CategoryPlot 来:
- 设置 X 轴和 Y 轴。
- 设置渲染器来改变柱子的颜色。
- 设置背景网格线。
第三部分:创建常用图表
1. 饼图
已在第一部分展示。
2. 柱状图 / 条形图
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
public class BarChartExample {
public static void main(String[] args) {
DefaultCategoryDataset dataset = createDataset();
JFreeChart chart = ChartFactory.createBarChart(
"季度销售数据", // 标题
"季度", // X轴标签
"销售额", // Y轴标签
dataset, // 数据集
PlotOrientation.VERTICAL, // 图表方向
true, // 显示图例
true, // 生成工具提示
false // 生成URL
);
// 自定义绘图区
CategoryPlot plot = chart.getCategoryPlot();
// 设置Y轴范围
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
yAxis.setRange(0, 100); // 假设销售额在0-100之间
// 自定义柱状颜色
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setSeriesPaint(0, Color.BLUE); // 设置第一个系列的颜色为蓝色
ChartFrame frame = new ChartFrame("柱状图示例", chart);
frame.pack();
frame.setVisible(true);
}
private static DefaultCategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(23, "产品A", "Q1");
dataset.addValue(34, "产品A", "Q2");
dataset.addValue(22, "产品A", "Q3");
dataset.addValue(45, "产品A", "Q4");
dataset.addValue(33, "产品B", "Q1");
dataset.addValue(44, "产品B", "Q2");
dataset.addValue(55, "产品B", "Q3");
dataset.addValue(30, "产品B", "Q4");
return dataset;
}
}
3. 折线图
折线图与柱状图使用相同的数据集类型 DefaultCategoryDataset。
// ... (import 语句同上,增加 LineAndShapeRenderer)
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
public class LineChartExample {
public static void main(String[] args) {
DefaultCategoryDataset dataset = createDataset(); // 使用和柱状图一样的数据集创建方法
JFreeChart chart = ChartFactory.createLineChart(
"月度访问量趋势", // 标题
"月份", // X轴标签
"访问量", // Y轴标签
dataset, // 数据集
PlotOrientation.VERTICAL,
true,
true,
false
);
// 自定义折线样式
CategoryPlot plot = chart.getCategoryPlot();
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
// 显示数据点
renderer.setBaseShapesVisible(true);
// 设置第一条线为红色,圆形数据点
renderer.setSeriesPaint(0, Color.RED);
renderer.setSeriesShape(0, new Ellipse2D.Double(-3, -3, 6, 6));
// 设置第二条线为绿色,方形数据点
renderer.setSeriesPaint(1, Color.GREEN);
renderer.setSeriesShape(1, new Rectangle(-3, -3, 6, 6));
ChartFrame frame = new ChartFrame("折线图示例", chart);
frame.pack();
frame.setVisible(true);
}
// createDataset 方法同上
}
4. 散点图
散点图使用 DefaultXYDataset。
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.DefaultXYDataset;
public class ScatterChartExample {
public static void main(String[] args) {
double[][] data = {{1, 2, 3, 4, 5}, {2, 3, 5, 7, 4}}; // 第一行是X值,第二行是Y值
DefaultXYDataset dataset = new DefaultXYDataset();
dataset.addSeries("系列1", data);
JFreeChart chart = ChartFactory.createScatterPlot(
"身高与体重关系", // 标题
"身高 (cm)", // X轴标签
"体重 (kg)", // Y轴标签
dataset, // 数据集
PlotOrientation.VERTICAL,
true,
true,
false
);
// 自定义:只显示点,不显示线
XYPlot plot = chart.getXYPlot();
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
renderer.setSeriesLinesVisible(0, false); // 第一条线不显示
renderer.setSeriesShapesVisible(0, true); // 第一个数据点显示
plot.setRenderer(renderer);
ChartFrame frame = new ChartFrame("散点图示例", chart);
frame.pack();
frame.setVisible(true);
}
}
5. 时间序列图
时间序列图是 XY 图的一种特殊形式,X 轴是时间。
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import java.text.SimpleDateFormat;
public class TimeSeriesChartExample {
public static void main(String[] args) {
// 创建时间序列
TimeSeries series = new TimeSeries("股票价格");
series.add(new Day(1, 1, 2025), 150.2);
series.add(new Day(2, 1, 2025), 152.5);
series.add(new Day(3, 1, 2025), 151.8);
series.add(new Day(4, 1, 2025), 153.9);
series.add(new Day(5, 1, 2025), 155.1);
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(series);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"股票价格走势",
"日期",
"价格",
dataset,
true,
true,
false
);
// 自定义X轴日期格式
XYPlot plot = chart.getXYPlot();
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));
ChartFrame frame = new ChartFrame("时间序列图示例", chart);
frame.pack();
frame.setVisible(true);
}
}
6. 环形图
环形图是饼图的变种,中间有一个空洞。
// ... (import 语句同饼图)
import org.jfree.chart.plot.PiePlot;
public class DonutChartExample {
public static void main(String[] args) {
PieDataset dataset = FirstChart.createDataset(); // 复用第一部分的数据集
JFreeChart chart = ChartFactory.createPieChart(
"水果销售比例",
dataset,
true,
true,
false
);
PiePlot plot = (PiePlot) chart.getPlot();
// 设置环形图的半径比例 (0.0 是实心饼图, 0.5 是半环形)
plot.setCircular(false);
plot.setLabelGap(0.02); // 标签与边缘的间隙
ChartFrame frame = new ChartFrame("环形图示例", chart);
frame.pack();
frame.setVisible(true);
}
}
第四部分:图表自定义与美化
JFreeChart 的强大之处在于其高度的可定制性。
1. 设置标题和图例
JFreeChart chart = ...;chart.setTitle("新标题");
chart.getTitle().setFont(new Font("黑体", Font.BOLD, 18));
// 设置图例
chart.getLegend().setItemFont(new Font("宋体", Font.PLAIN, 12));
chart.getLegend().setFrame(BlockBorder.NONE); // 移除图例边框
2. 自定义坐标轴
以 CategoryPlot 为例:
CategoryPlot plot = chart.getCategoryPlot();
// X轴
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setLabelFont(new Font("Arial", Font.BOLD, 14));
domainAxis.setTickLabelFont(new Font("Arial", Font.PLAIN, 12));
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 标签旋转45度
// Y轴
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setLabelFont(new Font("Arial", Font.BOLD, 14));
rangeAxis.setTickLabelFont(new Font("Arial", Font.PLAIN, 12));
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); // 设置刻度为整数
3. 自定义数据标签和工具提示
对于饼图,可以在每个扇区上显示标签。
PiePlot plot = (PiePlot) chart.getPlot();
// 设置标签生成器,显示名称和百分比
plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}: ({2})"));
// 设置标签背景色和边框
plot.setLabelBackgroundPaint(Color.YELLOW);
plot.setLabelOutlinePaint(Color.BLACK);
plot.setLabelOutlineStroke(new BasicStroke(1.0f));
对于所有图表,工具提示是默认开启的,你可以自定义其内容。
4. 设置背景色和边框
// 设置图表背景 chart.setBackgroundPaint(Color.LIGHT_GRAY); // 设置绘图区背景 plot.setBackgroundPaint(Color.WHITE); plot.setRangeGridlinePaint(Color.GRAY); // 设置水平网格线颜色 plot.setDomainGridlinePaint(Color.GRAY); // 设置垂直网格线颜色 // 设置边框 plot.setOutlineStroke(new BasicStroke(2.0f)); plot.setOutlinePaint(Color.BLACK);
5. 使用主题
JFreeChart 提供了一些预设主题,可以快速美化图表。
import org.jfree.chart.StandardChartTheme;
// 创建一个主题
StandardChartTheme theme = new StandardChartTheme("JFree");
// 设置主题字体
theme.setLargeFont(new Font("SimSun", Font.BOLD, 20));
theme.setRegularFont(new Font("SimSun", Font.PLAIN, 15));
theme.setTitleFont(new Font("SimSun", Font.BOLD, 18));
// 将主题应用于图表
theme.apply(chart);
第五部分:在实际项目中使用 JFreeChart
1. 在 Swing 应用中显示图表
最佳实践是使用 ChartPanel,它提供了缩放、复制图像等交互功能。
import org.jfree.chart.ChartPanel;
import javax.swing.*;
public class SwingChartApp {
public static void main(String[] args) {
JFrame frame = new JFrame("JFreeChart in Swing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFreeChart chart = FirstChart.createChart(); // 假设你有一个返回 JFreeChart 的方法
ChartPanel chartPanel = new ChartPanel(chart);
frame.add(chartPanel);
frame.pack();
frame.setVisible(true);
}
}
2. 生成图表并保存为图片文件
使用 ChartUtilities 类。
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import java.io.File;
import java.io.IOException;
public class SaveChartAsImage {
public static void main(String[] args) {
JFreeChart chart = FirstChart.createChart(); // 获取图表对象
try {
// 保存为 PNG 格式
ChartUtilities.saveChartAsPNG(new File("chart.png"), chart, 800, 600);
System.out.println("图表已保存为 chart.png");
// 保存为 JPEG 格式
// ChartUtilities.saveChartAsJPEG(new File("chart.jpg"), chart, 800, 600);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 在 Web 应用中动态生成图表
你会在 Servlet 或 Controller 中生成图表,然后将其作为图片流输出到浏览器。
// 在 Servlet 的 doGet 或 doPost 方法中
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 创建图表
JFreeChart chart = FirstChart.createChart();
// 2. 设置响应头
response.setContentType("image/png");
response.setHeader("Content-Disposition", "attachment; filename=chart.png");
// 3. 将图表写入输出流
ChartUtilities.writeChartAsPNG(response.getOutputStream(), chart, 800, 600);
response.getOutputStream().close();
}
第六部分:高级技巧与注意事项
1. 处理大数据量
对于包含成千上万个数据点的图表,渲染会变得非常慢。
- 数据聚合: 在显示图表前,对数据进行聚合或采样。
- 快速渲染器: 使用
FastScatterPlot等为特定场景优化的渲染器。 - 异步加载: 对于 Web 应用,可以考虑先加载一个缩略图,然后让用户选择是否加载完整图表。
2. 交互功能
ChartPanel 提供了许多内置的交互功能:
- 缩放: 鼠标滚轮或右键菜单。
- 平移: 鼠标拖动。
- 工具提示: 鼠标悬停。
你可以通过
ChartPanel的方法来控制这些功能:ChartPanel panel = new ChartPanel(chart); panel.setMouseWheelEnabled(true); // 启用滚轮缩放 panel.setPopupMenu(null); // 禁用右键菜单
3. 许可证问题
非常重要! JFreeChart 使用 GNU Lesser General Public License (LGPL) 许可证。
- 对于开源项目: 如果你的项目也是遵循兼容的开源许可证(如 GPL, Apache 2.0, MIT 等),你可以直接使用 JFreeChart。
- 对于商业闭源项目: 你也可以使用 JFreeChart,因为 LGPL 允许你在闭源软件中链接和使用它,你不能修改 JFreeChart 的源代码并将其包含在你的闭源产品中,如果你需要修改,必须将你的修改也以 LGPL 许可开源。
在使用前,请务必阅读并理解 JFreeChart 许可证。
这份教程涵盖了 JFreeChart 的主要使用场景,从简单的 ChartFactory 调用,到深入 Plot 和 Renderer 的自定义,JFreeChart 为你提供了强大的数据可视化能力,关键在于:
- 选择正确的
Dataset来匹配你的数据结构。 - 使用
ChartFactory快速创建一个基础图表。 - 通过获取
Plot和Renderer对象来精细控制图表的外观和行为。
希望这份教程能帮助你快速上手并精通 JFreeChart!
