杰瑞科技汇

JFreeChart 教程,从零开始学图表绘制?

JFreeChart 教程:从入门到精通

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

JFreeChart 教程,从零开始学图表绘制?-图1
(图片来源网络,侵删)

目录

  1. 第一部分:JFreeChart 快速入门

    • 1. 环境准备
    • 2. 第一个图表:最简单的饼图
    • 3. 代码解析
  2. 第二部分:核心概念与架构

    • 1. 核心组件:ChartFactory, JFreeChart, Plot, Dataset
    • 2. 数据集
    • 3. 图表工厂
    • 4. 图表对象
    • 5. 绘图区
  3. 第三部分:创建常用图表

    • 1. 饼图
    • 2. 柱状图 / 条形图
    • 3. 折线图
    • 4. 散点图
    • 5. 时间序列图
    • 6. 环形图
  4. 第四部分:图表自定义与美化

    JFreeChart 教程,从零开始学图表绘制?-图2
    (图片来源网络,侵删)
    • 1. 设置标题和图例
    • 2. 自定义坐标轴
    • 3. 自定义数据标签和工具提示
    • 4. 设置背景色和边框
    • 5. 使用主题
  5. 第五部分:在实际项目中使用 JFreeChart

    • 1. 在 Swing 应用中显示图表
    • 2. 生成图表并保存为图片文件
    • 3. 在 Web 应用中动态生成图表
  6. 第六部分:高级技巧与注意事项

    • 1. 处理大数据量
    • 2. 交互功能
    • 3. 许可证问题

第一部分:JFreeChart 快速入门

1. 环境准备

你需要下载 JFreeChart 的 JAR 文件,你可以从其官方网站 SourceForge 下载最新版本。

Maven 用户 (推荐): 在你的 pom.xml 文件中添加以下依赖:

JFreeChart 教程,从零开始学图表绘制?-图3
(图片来源网络,侵删)
<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. 代码解析

  1. createDataset(): 创建数据集,对于饼图,我们使用 DefaultPieDataset,它是一个简单的键值对集合,用来表示每个部分的名称和值。
  2. ChartFactory.createPieChart(...): 这是 JFreeChart 的核心工厂类,它提供了一系列静态方法,用于快速创建各种类型的图表,我们传入标题、数据集和一些布尔选项来配置图表。
  3. JFreeChart 对象: 这是图表的核心对象,包含了图表的所有信息(标题、图例、绘图区等),创建后,你可以对它进行各种自定义。
  4. 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 调用,到深入 PlotRenderer 的自定义,JFreeChart 为你提供了强大的数据可视化能力,关键在于:

  1. 选择正确的 Dataset 来匹配你的数据结构。
  2. 使用 ChartFactory 快速创建一个基础图表。
  3. 通过获取 PlotRenderer 对象来精细控制图表的外观和行为。

希望这份教程能帮助你快速上手并精通 JFreeChart!

分享:
扫描分享到社交APP
上一篇
下一篇