You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Excel版Apache POI柱线组合图代码适配为PowerPoint可用版本

Apache POI 生成PPT柱形折线组合图表实现方案

实现效果和下图完全匹配:
柱线组合表示例

适配可行性说明

Excel的图表实现逻辑可以直接迁移到PPT场景,Apache POI针对PPT的XSLFChart类和Excel的XSSFChart类底层逻辑同源,只需要替换容器层API,同时重构数据读取逻辑,就可以支持直接传入列表作为输入参数,不需要依赖外部Excel文件。

前置依赖

建议使用Apache POI 5.2.0及以上版本,低版本对PPT次坐标轴的支持存在已知缺陷,可能导致折线数据不显示。Maven依赖配置如下:

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

核心实现代码

以下代码支持直接传入分类标签列表、柱形系列数值列表、折线系列数值列表三个参数,直接生成目标组合图表插入到PPT幻灯片中:

import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.util.Units;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;

import java.io.FileOutputStream;
import java.util.List;

public class PptComboChartGenerator {
    /**
     * 生成柱线组合图表并插入到指定幻灯片
     * @param slide 目标幻灯片
     * @param x 图表左上角X坐标(单位:磅)
     * @param y 图表左上角Y坐标(单位:磅)
     * @param width 图表宽度(单位:磅)
     * @param height 图表高度(单位:磅)
     * @param categories X轴分类标签列表
     * @param barValues 柱形系列数值列表(绑定主Y轴)
     * @param lineValues 折线系列数值列表(绑定次Y轴)
     * @param barSeriesName 柱形系列名称
     * @param lineSeriesName 折线系列名称
     * @throws Exception
     */
    public void generateComboChart(XSLFSlide slide, int x, int y, int width, int height,
                                   List<String> categories, List<Double> barValues, List<Double> lineValues,
                                   String barSeriesName, String lineSeriesName) throws Exception {
        // 创建图表容器
        XSLFChart chart = slide.createChart();
        chart.setAnchor(new java.awt.Rectangle(x, y, width, height));

        // 初始化图表底层结构
        CTChart ctChart = chart.getCTChart();
        CTPlotArea plotArea = ctChart.getPlotArea();

        // 创建柱形系列(主坐标轴)
        CTBarChart barChart = plotArea.addNewBarChart();
        barChart.addNewVaryColors().setVal(false);
        barChart.addNewBarDir().setVal(STBarDir.COL);

        // 绑定柱形系列分类和数值
        CTBarSer barSer = barChart.addNewSer();
        barSer.addNewIdx().setVal(0);
        barSer.addNewTx().setV(barSeriesName);

        // 分类轴数据
        CTAxDataSource catDs = barSer.addNewCat();
        CTStrData catStrData = catDs.addNewStrLit();
        for (int i = 0; i < categories.size(); i++) {
            catStrData.addNewPt().setIdx(i);
            catStrData.getPtArray(i).setV(categories.get(i));
        }

        // 柱形数值数据
        CTNumDataSource barValDs = barSer.addNewVal();
        CTNumData barNumData = barValDs.addNewNumLit();
        for (int i = 0; i < barValues.size(); i++) {
            barNumData.addNewPt().setIdx(i);
            barNumData.getPtArray(i).setV(barValues.get(i).toString());
        }

        // 绑定柱形到主坐标轴
        barChart.addNewAxId().setVal(12345); // 主类别轴ID
        barChart.addNewAxId().setVal(12346); // 主数值轴ID

        // 创建折线系列(次坐标轴)
        CTLineChart lineChart = plotArea.addNewLineChart();
        lineChart.addNewVaryColors().setVal(false);

        CTLineSer lineSer = lineChart.addNewSer();
        lineSer.addNewIdx().setVal(1);
        lineSer.addNewTx().setV(lineSeriesName);
        lineSer.addNewSmooth().setVal(false); // 折线是否平滑

        // 折线复用相同分类轴
        CTAxDataSource lineCatDs = lineSer.addNewCat();
        CTStrData lineCatStrData = lineCatDs.addNewStrLit();
        for (int i = 0; i < categories.size(); i++) {
            lineCatStrData.addNewPt().setIdx(i);
            lineCatStrData.getPtArray(i).setV(categories.get(i));
        }

        // 折线数值数据
        CTNumDataSource lineValDs = lineSer.addNewVal();
        CTNumData lineNumData = lineValDs.addNewNumLit();
        for (int i = 0; i < lineValues.size(); i++) {
            lineNumData.addNewPt().setIdx(i);
            lineNumData.getPtArray(i).setV(lineValues.get(i).toString());
        }

        // 绑定折线到次坐标轴
        lineChart.addNewAxId().setVal(12345); // 共享主类别轴
        lineChart.addNewAxId().setVal(12347); // 次数值轴ID

        // 配置主类别轴
        CTCatAx catAx = plotArea.addNewCatAx();
        catAx.addNewAxId().setVal(12345);
        catAx.addNewScaling().addNewOrientation().setVal(STOrientation.MAX_MIN);
        catAx.addNewAxPos().setVal(STAxPos.B);
        catAx.addNewCrossAx().setVal(12346);
        catAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);

        // 配置主数值轴(柱形用)
        CTValAx mainValAx = plotArea.addNewValAx();
        mainValAx.addNewAxId().setVal(12346);
        mainValAx.addNewScaling().addNewOrientation().setVal(STOrientation.MIN_MAX);
        mainValAx.addNewAxPos().setVal(STAxPos.L);
        mainValAx.addNewCrossAx().setVal(12345);
        mainValAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);

        // 配置次数值轴(折线用)
        CTValAx secondaryValAx = plotArea.addNewValAx();
        secondaryValAx.addNewAxId().setVal(12347);
        secondaryValAx.addNewScaling().addNewOrientation().setVal(STOrientation.MIN_MAX);
        secondaryValAx.addNewAxPos().setVal(STAxPos.R);
        secondaryValAx.addNewCrossAx().setVal(12345);
        secondaryValAx.addNewCrosses().setVal(STCrosses.MAX);
        secondaryValAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);

        // 显示图例
        ctChart.addNewLegend().addNewLegendPos().setVal(STLegendPos.B);
    }

    // 调用示例
    public static void main(String[] args) throws Exception {
        try (XMLSlideShow ppt = new XMLSlideShow()) {
            XSLFSlide slide = ppt.createSlide();
            PptComboChartGenerator generator = new PptComboChartGenerator();

            // 传入自定义列表数据
            List<String> categories = List.of("1月", "2月", "3月", "4月", "5月", "6月");
            List<Double> barValues = List.of(120.0, 200.0, 150.0, 250.0, 180.0, 300.0);
            List<Double> lineValues = List.of(0.8, 0.95, 0.75, 0.9, 0.82, 0.98);

            generator.generateComboChart(slide, Units.toEMU(50), Units.toEMU(50), Units.toEMU(600), Units.toEMU(400),
                    categories, barValues, lineValues, "销售额", "完成率");

            try (FileOutputStream out = new FileOutputStream("combo_chart.pptx")) {
                ppt.write(out);
            }
        }
    }
}

代码说明

  • 所有输入数据都通过参数列表传入,没有依赖任何外部Excel文件读取逻辑
  • 柱形系列默认绑定左侧主Y轴,折线系列绑定右侧次Y轴,两个Y轴的刻度范围会根据传入的数值自动计算
  • 可通过调整坐标、宽高参数控制图表在幻灯片中的位置和大小,也可以扩展代码添加系列颜色、刻度格式等自定义样式

内容的提问来源于stack exchange,提问作者Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:48:04