Apache POI 柱状图(Bar Chart)Java 实现

Last Modified: 2023/11/11

概述

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

Bar Chart 成品图

在开始之前,同样先放上成果展示,我们的目标就是实现该成品图

为了大家更好的理解这张图和以及后面的代码,我们对图中的元素做一下分解

从上图我们可以看出以下一些元素,这些元素在后面的代码中都会体现:

  • 第一个元素是分类:英语、数学、计算机和财经
  • 第二元素是系列:共有两个系列,第一个系列是选修人数,第二个系列是课程的课时数
  • 第三个元素是图例,通过图例我们能很轻松的区分出两个系列,其中第一个系列是红色柱状图,第二个系列是绿色柱状图

Java 实现柱状图

1、准备数据容器

在开始之前我们提供几个工具类,ChartData/SerieData 用来存储柱状图用到的数据,BarChartRenderer 用来绘制柱状图。可以结合后面的代码在回过头来查看,由于篇幅关系,省略 getter 和 setter:

public class ChartData {
  // 图表的标题
  private String title;
  // 分类
  private List<String> categories;
  // 每个系列的数据
  private List<SerieData> series;
}
public class SerieData {
  // 系列名称
  private String name;
  // 系列数据
  private List<Number> data;
  // 系列的颜色
  private PresetColor color = PresetColor.ALICE_BLUE;
}
/**
 * 柱状图绘制
 */
public class BarChartRenderer {
  public void render(XWPFDocument document, ChartData chartData) throws IOException, InvalidFormatException {
    // 这里的实现拆分到下面的代码片段中,从第 2 - 5 小节,第 6 小节为 main 方法,展示该方法的用法
  }
}

代码拆的很零碎,主要是方便讲述,完整代码 Github 传送点

2、在文档中创建图并构造 xy 轴

XWPFChart chart = document.createChart(14 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER);
XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT);
yAxis.setCrosses(AxisCrosses.AUTO_ZERO);
yAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

3、构造数据源

// 构造分类数据源
String[] categories = chartData.getCategories().toArray(new String[0]);
XDDFDataSource<String> categoryDS = XDDFDataSourcesFactory.fromArray(categories);
// 构造系列数据源
List<XDDFNumericalDataSource<Number>> valueDS = new ArrayList<>();
List<SerieData> seriesData = chartData.getSeries();
for (SerieData seriesDatum : seriesData) {
  XDDFNumericalDataSource<Number> s = XDDFDataSourcesFactory.fromArray(seriesDatum.getData().toArray(new Number[0]));
  valueDS.add(s);
}

这里构造系列数据源的时候使用了 for 循环,因为系列是可以有任意多个的,虽然我们这里只有两个系列:一个是选课人数,另一个是课时数。

4、将数据源绑定到图表

XDDFChartData data = chart.createData(ChartTypes.BAR, xAxis, yAxis);
// 控制柱子方向,柱子可以竖直方向也可以水平方向,这里为竖直方向
((XDDFBarChartData) data).setBarDirection(BarDirection.COL);
// 这可以控制柱子的宽度,值越大柱子越细
((XDDFBarChartData) data).setGapWidth(500);
// 如果只有一个系列,那么 setVaryColors(false),否则每个柱子的颜色都不一样
data.setVaryColors(seriesData.size() > 1);

// 将数据源绑定到图表
int i = 0;
for (XDDFNumericalDataSource<Number> value : valueDS) {
    XDDFChartData.Series series = data.addSeries(categoryDS, value);
    // 设置系列的名称,系列的名称会显示在图例中
    series.setTitle(seriesData.get(i).getName(), null);
    // 针对 LibreOffice 的设置,否则无法在 LibreOffice 中正常显示
    solidFillSeries(series, seriesData.get(i).getColor());
    i++;
}

private static void solidFillSeries(XDDFChartData.Series series, PresetColor color) {
  XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
  XDDFShapeProperties properties = series.getShapeProperties();
  if (properties == null) {
      properties = new XDDFShapeProperties();
  }
  properties.setFillProperties(fill);
  series.setShapeProperties(properties);
}

5、设置图例并绘制图表

// 图例
XDDFChartLegend legend = chart.getOrAddLegend();
// 图例显示在图表正下方
legend.setPosition(LegendPosition.BOTTOM);
legend.setOverlay(false);
// 绘制图表
chart.plot(data);

6、将图表保存到 Word 中

在 BarChartRenderer 中添加一个 main 方法,准备图表数据,并调用 render 方法绘制图表,最后将图表保存到 XWPF 文档中。

ChartData chartData = new ChartData();
chartData.setTitle("专业课选修人数/课时数");
chartData.setCategories(Arrays.asList("英语", "数学", "计算机", "财经"));

// 构造系列数据
List<SerieData> seriesData = new ArrayList<>();
// 选修人数:英语 100 人,数学 200 人,计算机 800 人,财经 50 人
seriesData.add(createSerieData("选修人数", Arrays.asList(100, 200, 800, 50), PresetColor.RED));
// 课时:英语 50 课时 ...
seriesData.add(createSerieData("课时数", Arrays.asList(50, 60, 40, 75), PresetColor.DARK_GREEN));
chartData.setSeries(seriesData);

XWPFDocument document = new XWPFDocument();
new BarChartRenderer().render(document, chartData);
try (FileOutputStream fo = new FileOutputStream("D:\\bar.docx")) {
    document.write(fo);
}

Apache 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 版本所需的依赖可能不同,这点在 Apache POI 饼图(Pie Chart)Java 实现 有说明,这里不再赘述。

有问题吗?点此反馈!

温馨提示:反馈需要登录