Apache POI 饼图(Pie Chart)Java 实现

Last Modified: 2023/11/11

概述

本文介绍如何使用 Apache POI 在 word 文档中生成饼图,文档格式要求为 docx,对应于 Apache POI 中的 XWPFDocument。文中最后会附上完整的代码实现。

Word 饼图成品展示

在开始之前,放一张我们将要实现的饼图,这张饼图直观的展示了各个专业选修人数的占比。

POI 饼图实现

完整代码 Github 传送点

1、首先创建一个饼图,并设置一个标题

XWPFDocument document = new XWPFDocument();
XWPFChart chart = document.createChart(14 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER);
// 显示在饼图上面的标题
chart.setTitleText(chartData.getTitle());
// 设置标题是否覆盖图表
chart.setTitleOverlay(false);

2、设置饼图数据源

饼图的数据源有两个:一个是分类数据源;另一个值数据源,即各个分类对应的数值。对应到上图分类有四个:英语、数学、计算机和财经。值数据源则是由各个专业的选修人数构成。

// 分类数据源,即各个专业
XDDFCategoryDataSource categoryDS = XDDFDataSourcesFactory.fromArray(new String[]{"英语", "数学", "计算机", "财经"});
// 值数据源,即各个专业的选修人数
XDDFNumericalDataSource<Number> valueDS = XDDFDataSourcesFactory.fromArray(new Integer[]{10, 20, 30, 50});

// 将数据源绑定到饼图上
XDDFChartData data = chart.createData(ChartTypes.PIE, null, null);
XDDFChartData.Series series = data.addSeries(categoryDS, valueDS);

// 为了在饼图上显示百分比等信息,需要调用下面的方法
series.setShowLeaderLines(true);

上面的代码中用了两行代码将数据源绑定到饼图,是为了方便调用 series.setShowLeaderLines(true),其实绑定数据源也可以用一行代码搞定:

XDDFChartData data = chart.createData(ChartTypes.PIE, categoryDS, valueDS);

3、设置图例并完成绘制

// 图例
XDDFChartLegend legend = chart.getOrAddLegend();
// 图例的位置显示在图的正下方
legend.setPosition(LegendPosition.BOTTOM);
// 让每个分类的颜色区分开来
data.setVaryColors(true);
// 绘制饼图
chart.plot(data);

至此,使用 Apache POI API 在 word 中绘制饼图基本完成,此时运行程序可以得到下面这张图:

可以看出这张图和成品图略有不同,主要是每块饼上的除了显示百分比还额外显示了图例标识、系列名称、分类名称和数值。如果想隐藏这些信息仅显示一个百分比该如何实现呢?

为了能够灵活的控制分类、系列和数值等是否显示,我们先定义以下方法:

// 控制分类名称是否显示
public void showCateName(CTPieSer series, boolean val) {
  if (series.getDLbls().isSetShowCatName()) {
    series.getDLbls().getShowCatName().setVal(val);
  } else {
    series.getDLbls().addNewShowCatName().setVal(val);
  }
}

// 控制值是否显示
public void showVal(CTPieSer series, boolean val) {
  if (series.getDLbls().isSetShowVal()) {
    series.getDLbls().getShowVal().setVal(val);
  } else {
    series.getDLbls().addNewShowVal().setVal(val);
  }
}

// 控制值系列名称是否显示
public void showSerName(CTPieSer series, boolean val) {
  if (series.getDLbls().isSetShowSerName()) {
    series.getDLbls().getShowSerName().setVal(val);
  } else {
    series.getDLbls().addNewShowSerName().setVal(val);
  }
}

// 控制图例标识是否显示
public void showLegendKey(CTPieSer series, boolean val) {
  if (series.getDLbls().isSetShowLegendKey()) {
    series.getDLbls().getShowLegendKey().setVal(val);
  } else {
    series.getDLbls().addNewShowLegendKey().setVal(val);
  }
}

有了上面的方法之后,在绘制之前,调用上面的方法隐藏图例标识、系列名称、分类名称和数值,仅保留百分比即可:

// 隐藏图例标识、系列名称、分类名称和数值
XDDFPieChartData.Series s = (XDDFPieChartData.Series) series;
CTPieSer ctPieSer = s.getCTPieSer();
showCateName(ctPieSer, false);
showVal(ctPieSer, false);
showLegendKey(ctPieSer, false);
showSerName(ctPieSer, false);
// 绘制
chart.plot(data);
// 生成文档
try (FileOutputStream fo = new FileOutputStream("D:\\pie.docx")) {
    document.write(fo);
}

完整代码 Github 传送点

POI Maven 依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-full</artifactId>
    <version>5.2.3</version>
</dependency>

注:如果仅仅是绘制饼图可以不需要 poi-ooxml-full,但是在绘制折线图等图的时候则需要引入该依赖。最后有必要强调一下,不同版本的 poi 所需要引入依赖是不同的,需要看你的项目使用的 poi 版本决定,官方中对这一点也有说明。

ooxml-schema 不同版本 poi 要求不同,选错版本可能出现一些诡异的报错。

或许你还对 XWPF 中绘制折线图和柱状图感兴趣:

有问题吗?点此反馈!

温馨提示:反馈需要登录