【JAVA - POI 合集】之 POI 操作word 图表,柱状图,折线图,雷达图,条形图 poi4.1.2

1.前言

        关于poi 操作word 的吐槽: 山路崎岖, 一言难尽啊!!!

        原本项目中的poi 版本是3.17的版本,但是3.17对于在word 中操作图表是有问题的。所以对项目的jar 包进行了升级,升级到了4.1.2。 要求JDK  1.8 以上. 现在用8以下的项目基本上也很少了。话不多说, 进入主题:

2.准备工作

poi版本:4.1.2 

涉及到的所有jar 包:

commons-compress-1.18.jar
commons-collections4-4.1.jar
poi-4.1.2.jar
poi-examples-4.1.2.jar
poi-excelant-4.1.2.jar
poi-ooxml-4.1.2.jar
poi-ooxml-schemas-4.1.2.jar
poi-scratchpad-4.1.2.jar
ooxml-schemas-1.4.jar
xmlbeans-3.1.0.jar

 

3.正文

POI 可以操作word 中的图表类型基本上 跟echarts 差不多。 包含 柱状图(条形图),折线图,雷达图,柱状+折现的组合图,饼图等。 这次就主要说几个常用的图。

POI 操作word 图表的方式分为两种(我接触到的):

第一种:创建一个word 模板,在word 文档中事先插入柱状图,或者其他要用到的图表。通过将数据刷到图表对应的内置EXCEL 表格中,将数据展示在图表中。

第二种:动态插入图表,在word 文档中事先插入对应的标记 exp ${barChart_1} 找到该标记,将标记替换为空,并将后台生成的图表插入到word 文档中。

3.1 两种方式优缺点对比

第一种优点:图表的格式可以很好的控制,坐标轴,标题,数据标签,误差线,网格线,图例等都可以事先在模板中设置好,最终只需要关心数据的问题就可以了。 缺点:如果有动态插入,且图表数量不固定的情况下,就无法事先在模板中创建对应的图表进行展示。

第二种优点:可以做到动态插入,只需要事先在指定的位置中打入标记。 如果标记也不固定可以在插入图表前,先对word 中段落进行遍历,将标记${barChart_1}插入到指定的位置,插入的图表的时候在将插入的标记替换为图表。缺点:样式不容易控制,生成的图表和在word 中直接创建的图表略有差异。基础的插入缺失很多属性, 需要将属性分别设置到图表中。还存在部分属性不生效的问题。(有大神解决的话,本人虚心求教)

3.2 代码展示

下方代码是操作固定模板中事先创建好的图表

tips:(1)在word文档中插入标记的时候需要先在notepad++ 这类纯文本编辑器中将标记写好,然后复制到word 文档中,否则这个标记可能会被word 拆分成多个词,无法进行匹配。(2)输入图表标题的时候,尽量在输入法中一次性将标题输入完成,不要分开多次插入。如图所示:

JAVA poi 动态插入图表, 一些属性的设置

1:设置图例的位置

        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.BOTTOM); // 图例位置:上下左右

2:设置柱状图为条形图

        XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, xAxis, yAxis);
barChart.setBarDirection(BarDirection.COL); // COL 为条形图  BAR 为柱状图

3:设置X轴的文字一直在最下方, 不会因为负数的原因导致图形和X轴的标签文字重合

        XDDFCategoryAxis xAxisLine = chartLine.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置
        xAxisLine.setTickLabelPosition(AxisTickLabelPosition.LOW); // 设置X轴的文字一直在最下方

4:展示数据标签 和调整数据标签的位置

CTPlotArea plotArea = chartLine.getCTChart().getPlotArea();
for (CTLineSer ser : plotArea.getLineChartArray(0).getSerList()) {
        CTDLbls ctdLbls = ser.addNewDLbls();
        ctdLbls.addNewShowVal().setVal(true);// 是否展示数值
        ctdLbls.addNewDLblPos().setVal(STDLblPos.IN_END);//数据标签位置
}

5:设置折线图的线条样式和标记点样式

        lineSeries.setSmooth(false); // 线条样式:true平滑曲线,false折线
        lineSeries.setMarkerStyle(MarkerStyle.NONE); // 标记点样式

6:设置数据标签的格式

        barSeries.getValuesData().setFormatCode("##0.0"); // 保留一位小数

7:如果有多条折线图或者柱状图, 调整柱状图的颜色

private static void solidFillSeries(CTBarSer ser, int i) {
        List<Integer[]> colorArr = new ArrayList<>();
        colorArr.add(new Integer[]{127, 100, 162});
        colorArr.add(new Integer[]{155,187,89});
        colorArr.add(new Integer[]{192,80,77});
        colorArr.add(new Integer[]{79,128,189});
        Integer[] color = colorArr.get(i);
        CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
        Color col1 = new Color(color[0],color[1],color[2]);
        rgb.setVal(new byte[]{(byte) col1.getRed(), (byte) col1.getGreen(), (byte)         col1.getBlue()});
        CTSolidColorFillProperties fillProp =         CTSolidColorFillProperties.Factory.newInstance();
        fillProp.setSrgbClr(rgb);
        CTShapeProperties ctShapeProperties = CTShapeProperties.Factory.newInstance();
        ctShapeProperties.setSolidFill(fillProp);
        ser.setSpPr(ctShapeProperties);
}

 下方代码是操作固定模板中事先创建号的图表:

/**
* 操作模板中的图表, 需要根据图表的标题来找到指定的图表
*/
public  static void charGeneration(XWPFDocument doc, String tit, List<JSONObject> dataArray){ 
    if (dataArray != null && dataArray.size() > 0) {
        List<POIXMLDocumentPart> relations = doc.getRelations(); // 获取模版中所有的表格模版
            int index=0;
            for (POIXMLDocumentPart poixmlDocumentPart : relations)
                if (poixmlDocumentPart instanceof XWPFChart) { //判断是不是图表类型
                    XWPFChart chart = (XWPFChart) poixmlDocumentPart;
                    String charType = ""; // charType 1 普通图表柱状图  2 折线图单条和2条 3 雷达图 4 多条折线图
                    XDDFTitle xddfTitletitle = chart.getTitle();
                    XDDFTextBody body = xddfTitletitle.getBody();
                    CTTextBody xmlObject = body.getXmlObject();
                    String tt = xmlObject.toString(); //图表的标题
                    List<String> keyList = new ArrayList<>();
                    List<String> keyListTemp = new ArrayList<>();
                    List<String> titleArr = new ArrayList<>();
                    //根据属性第一列名称切换数据类型
                    CTChart ctChart = null;
                    CTPlotArea plotArea = null;

                    if (tt.contains(tit) && tit.equals("图表1")){//折线图
                        //刷新内置excel数据
                        charType = "2"; // charType 1 普通图表柱状图  2 折线图 3 雷达图
                        keyList.add("nd");
                        keyList.add("value1");
                        keyList.add("value2");
                        titleArr.add("");
                        titleArr.add("餐补");
                        titleArr.add("交通补贴");
                        ctChart = chart.getCTChart();
                        plotArea = ctChart.getPlotArea();
                    }else if (tt.contains(tit) && tit.contains("图表2")) {
                        charType = "1";
                        keyList.add("ssnd");
                        keyList.add("value1");
                        keyList.add("value2");
                        titleArr.add("");
                        titleArr.add("收入");
                        titleArr.add("支出");
                        ctChart = chart.getCTChart();
                        plotArea = ctChart.getPlotArea();
                    }
                    if (StringUtils.isNotEmpty(charType)) {
                        /**
                         * 每个word 中的图表都会对应一个内置的excel .用来存放表格的数据.
                         * 所以需要像图表的数据先写入内置的excel 中
                         */
                        refreshExcel(chart, dataArray,keyList,titleArr);

                        //刷新页面显示数
                        List<String> newKey = new ArrayList<>(); //之所以要new 一个新的对象,直接赋值,只是赋值了引用地址

                    if (charType.equals("1")) {
                            CTBarChart barChart = plotArea.getBarChartArray(0);
                            List <CTBarSer> serList = barChart.getSerList();
                            int position = 1;
                            refreshNumGraphContent(barChart, serList,                 dataArray,keyList,titleArr);
                        }
                        if (charType.equals("2")) {
                            CTLineChart lineChart = plotArea.getLineChartArray(0);
                            List <CTLineSer> serList = lineChart.getSerList();
                            int position = 1;
                            refreshLineStrGraphContent(lineChart, serList, dataArray,keyList,titleArr);
                        }


                        break;
                    }

    }



}

/**
     * 刷新折线图数据方法
     *
     * @param typeChart
     * @param serList
     * @param dataList
     * @param position
     * @return
     */
    public static boolean refreshLineStrGraphContent(CTLineChart lineChart,
                                                     List<?> serList, List<JSONObject> dataList,List<String> keyList,
                                                     List<String> titleList) {

        boolean result = true;
        int position = 1;

        if (dataList.size() < 1) {
            return false;
        }
        List<String> tList = new ArrayList();

        int keyIndex=1;
        //更新数据区域
        for (int i = 0; i < serList.size(); i++) {
            CTAxDataSource cat = null;
            CTNumDataSource val = null;
            CTLineSer ser =lineChart.getSerArray(i);
            cat = ser.getCat();
            // 获取图表的值
            val = ser.getVal();
            CTSerTx tx = ser.getTx();
            CTStrRef strRefH = cat.getStrRef();
            CTStrData strCacheH = strRefH.getStrCache();
            CTStrData strCache = tx.getStrRef().getStrCache();
            CTNumData numData = val.getNumRef().getNumCache();
            strCache.setPtArray((CTStrVal[]) null); // unset old axis text
            strCacheH.setPtArray((CTStrVal[]) null); // unset old axis text
            numData.setPtArray((CTNumVal[]) null); // unset old values
            // set model
            int idx = 0;

            CTStrVal strVal1 = strCache.addNewPt();//序列名称
            if (titleList.size() == 2) {
                strVal1.setIdx(i);
                strVal1.setV(titleList.get(1));
            }else{
                strVal1.setIdx(i);
                strVal1.setV(titleList.get(i+1));
            }
            for (int j = 0; j < dataList.size(); j++) {

                CTStrVal strVal = strCacheH.addNewPt();//序列名称
                strVal.setIdx(idx);
                strVal.setV(dataList.get(j).getString(keyList.get(0)));

                for (int i1 = 0; i1 < keyList.size(); i1++) {
                    String value = "0";

                    if (i1 == 0) {
                        if (idx>0){
                            continue;
                        }else{

                        }
                    }else{
                        if (StringUtil.checkChinese(dataList.get(j).getString(keyList.get(keyIndex)))){
                            continue;
                        }
                        String zb = "0";
                        if (dataList.get(j).get(keyList.get(keyIndex))!=null && !dataList.get(j).getString(keyList.get(keyIndex)).trim().equals("--")){
                            zb = dataList.get(j).getString(keyList.get(keyIndex));
                            if(StringUtil.isNullString(zb)){
                                zb = "0";
                            }
                            if (zb.indexOf("%")>0){
                                BigDecimal b = new BigDecimal(100);
                                zb = zb.replace("%","");
                                zb = new BigDecimal(zb).divide(b).setScale(4, BigDecimal.ROUND_HALF_UP).toString();
                            }
                        }
                        if(new BigDecimal(zb)!=null){
                            value=new BigDecimal(zb).toString();
                        }
                        if(!"0".equals(value)){
                            CTNumVal numVal = numData.addNewPt();//序列值
                            numVal.setIdx(idx);
                            numVal.setV(value);
                        }
                        idx++;
                        break;
                    }
                }
            }
            numData.getPtCount().setVal(idx);
            if (i==0){
                strCache.getPtCount().setVal(idx);
                String legendDataRange = new CellRangeAddress(0, 0, 1, idx + 1)
                        .formatAsString("Sheet1", true);
                tx.getStrRef().setF(legendDataRange);
                //赋值横坐标数据区域
                String axDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", true);
                cat.getStrRef().setF(axDataRange);
            }
            //数据区域
            String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                    .formatAsString("Sheet1", false);
            val.getNumRef().setF(numDataRange);
            // 设置系列生成方向
            if (keyList.size() != 2) {
                keyIndex++;
            }
        }
        return result;
    }

/**
     * 刷新数据
     * @param chart
     * @param dataList
     * @param titleArr
     * @param showtailArr
     * @param ispercentArr
     * @return
     */
    public static boolean refreshExcel(XWPFChart chart,
                                       List<JSONObject> dataList,List<String> keyList,List<String> titleArr) {
        boolean result = true;
        Workbook wb = new XSSFWorkbook();
        Sheet sheet = wb.createSheet("Sheet1");
        //根据数据创建excel第一行标题行
        sheet.createRow(0).createCell(0).setCellValue("");
        for (int i = 1; i < titleArr.size(); i++) {
            sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i)==null?"":titleArr.get(i));
        }

        //遍历数据行
        for (int i = 0; i < dataList.size(); i++) {
            JSONObject baseFormMap = dataList.get(i);//数据行
            //fldNameArr字段属性
            for (int j = 0; j < keyList.size(); j++) {
                if(sheet.getRow(i+1)==null){
                    if(j==0){
                        try {
                            sheet.createRow(i+1).createCell(j).setCellValue(baseFormMap.getString(keyList.get(j))==null?"":baseFormMap.getString(keyList.get(j)));
                        } catch (Exception e) {
                            if(baseFormMap.get(keyList.get(i))==null){
                                sheet.createRow(i+1).createCell(j).setCellValue("");
                            }else{
                                sheet.createRow(i+1).createCell(j).setCellValue(baseFormMap.getString(keyList.get(j)));
                            }
                        }
                    }
                }else{
                    String dvl = baseFormMap.getString(keyList.get(j));
                    if (StringUtil.checkChinese(dvl)) {
                        continue;
                    }
                    double value=0d;
                    String zb = "0";
                    if (baseFormMap.getString(keyList.get(j))!=null && !baseFormMap.getString(keyList.get(j)).trim().equals("--")){
                        zb = baseFormMap.getString(keyList.get(j));
                        if(StringUtil.isNullString(zb)){
                            zb = "0";
                        }
                        if (zb.indexOf("%")>0){
                            BigDecimal b = new BigDecimal(100);
                            zb = zb.replace("%","");
                            zb = new BigDecimal(zb).divide(b).setScale(4, BigDecimal.ROUND_UP).toString();
                        }
                    }
                    if(new BigDecimal(zb)!=null){
                        value=new BigDecimal(zb).doubleValue();
                    }
                    if(StringUtils.isEmpty(dvl)){
                        sheet.getRow(i+1).createCell(j);
                    }else{
                        sheet.getRow(i+1).createCell(j).setCellValue(value);
                    }
                }
            }
        }
        // 更新嵌入的workbook
        POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
        OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();

        try {
            wb.write(xlsOut);
            xlsOut.close();
        } catch (IOException e) {
            e.printStackTrace();
            result = false;
        } finally {
            if (wb != null) {
                try {
                    wb.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    result = false;
                }
            }
        }
        return result;
    }

动态插入图表:

public static void insetChart(XWPFDocument document, List<JSONObject> list) throws Exception {
//根据数据的条数, 插入对应数量的标记
boolean breakPoint = true; // 终止多层循环
        // 1、创建word文档对象
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        if (hxqyList.size() > 0) {
            for (XWPFParagraph per : paragraphs) {
                if (breakPoint) {
                    List<XWPFRun> runs = per.getRuns();
                    for (XWPFRun run : runs) {
                        //获取文本的值
                        String text = run.getText(0);
                        if (StringUtils.isNotEmpty(text)) {
                            if (text.contains("${hxqyChart_1}")) {
                                for (int i = 0; i < hxqySize; i++) {
                                    run.addCarriageReturn();
                                    XWPFRun run1 = per.createRun();
                                    run1.setText("${hxqyChart_"+(i+2)+"}");
                                    run1.addCarriageReturn();
                                    run1.setFontFamily("宋体");
                                    run1.setFontSize(14);
                                    per.addRun(run1);
                                }
                                breakPoint=false;
                                break;
                            }
                        }
                    }
                }
            }
        }
        for (JSONObject hxObject : hxqyList) {
            int runIndex = 1;
            for (XWPFParagraph per : paragraphs) {
                List<XWPFRun> runs = per.getRuns();
                for (XWPFRun run : runs) {
                    //获取文本的值
                    String text = run.getText(0);
                    if (StringUtils.isNotEmpty(text)) {
                        if (text.contains("hxqyChart")) {
                            run.setText("1.2."+runIndex+hxObject.getString("nsrmc"), 0);
                            per.setAlignment(ParagraphAlignment.LEFT);//对齐方式
                            run.setText(hxObject.getString(""), 1);
                            run.addBreak();
                            String zcfzTitle = "柱状图";
                            String zcfzTitle1 = "折线图";
                            //插入柱状图
                            insertBarchar(document, run,zcfzTitle,hxObject.getJSONArray("zcfzzk_zzt"));
                            //插入折线图
                            insertLineChart(document,run,zcfzTitle1,hxObject.getJSONArray("zcfzzk_zxt"));
                         
                        }
                    }

                }
            }
            runIndex++;
        }
        





}
private static void insertBarchar(XWPFDocument document, XWPFRun run, String title, JSONArray dataArray) throws Exception{
        List<JSONObject> dataObjList = new ArrayList<>();
        if (dataArray != null && dataArray.size() > 0) {
            dataObjList = JSONObject.parseArray(dataArray.toJSONString(), JSONObject.class);
        }
        // 2、创建chart图表对象,抛出异常
        XWPFChart chart = document.createChart(run, (int)(14.5 * Units.EMU_PER_CENTIMETER), 9 * Units.EMU_PER_CENTIMETER);
        chart.setChartTopMargin(1000L);
        // 3、图表相关设置
        chart.setTitleText(title); // 图表标题
        chart.setTitleOverlay(false); // 图例是否覆盖标题

        // 4、图例设置
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.BOTTOM); // 图例位置:上下左右
        String[] xAxisData = new String[4];
        Double[] yAxisData = new Double[4];
        Double[] yAxisData1 = new Double[4];
        for (int i = 0; i < dataObjList.size(); i++) {
            if (title.equals("柱状图1")) { //双柱状图
                xAxisData[i] = dataObjList.get(i).getString("ssnd");
                yAxisData[i] = dataObjList.get(i).getDouble("value1");
                yAxisData1[i] = dataObjList.get(i).getDouble("value2");
            }else if (title.equals("柱状图2")) {//单柱状图
                xAxisData[i] = dataObjList.get(i).getString("ssnd");
                yAxisData[i] = dataObjList.get(i).getDouble("value1");
            }
        }

        // 5、X轴(分类轴)相关设置
        XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置

        XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData); // 设置X轴数据

        // 6、Y轴(值轴)相关设置
        XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置
        yAxis.setCrossBetween(AxisCrossBetween.BETWEEN); // 设置图柱的位置:BETWEEN居中


        // 7、创建柱状图对象
        XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, xAxis, yAxis);
        barChart.setBarDirection(BarDirection.COL); // 设置柱状图的方向:BAR横向,COL竖向,默认是BAR

        if (title.equals("图表1")) {
            XDDFNumericalDataSource<Double> yAxisSource = XDDFDataSourcesFactory.fromArray(yAxisData); // 设置Y轴数据
            XDDFNumericalDataSource<Double> yAxisSource1 = XDDFDataSourcesFactory.fromArray(yAxisData1); // 设置Y轴数据
            // 8、加载柱状图数据集
            XDDFBarChartData.Series barSeries = (XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSource);
            XDDFBarChartData.Series barSeries2 = (XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSource1);
            barSeries.setTitle("收入",null);
            barSeries2.setTitle("支出",null);
            barSeries.getValuesData().setFormatCode("##0.00");
            barSeries2.getValuesData().setFormatCode("##0.00");
        }else{
            XDDFNumericalDataSource<Double> yAxisSource = XDDFDataSourcesFactory.fromArray(yAxisData); // 设置Y轴数据
            // 8、加载柱状图数据集
            XDDFBarChartData.Series barSeries = (XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSource);
            barSeries.getValuesData().setFormatCode("##0.00");
           
            barSeries.setTitle("收入",null);
           
        }
        CTPlotArea plotArea = chart.getCTChart().getPlotArea();
        for (CTBarSer ser : plotArea.getBarChartArray(0).getSerList()) {
            CTDLbls ctdLbls = ser.addNewDLbls();
            ctdLbls.addNewShowCatName().setVal(false);// 是否展示对应x轴上的值(类型名称)
            ctdLbls.addNewShowVal().setVal(true);// 是否展示数值
            ctdLbls.addNewShowSerName().setVal(false);// 是否展示归属折线名称(系列名称)
            ctdLbls.addNewShowLegendKey().setVal(false);// 是否展示图例(图例项标示)
            ctdLbls.addNewDLblPos().setVal(STDLblPos.IN_END);
        }
        // 9、绘制柱状图
        chart.plot(barChart);
    }

private static void insertLineChart(XWPFDocument document,XWPFRun run,String title,JSONArray dataArray) throws Exception{
        List<JSONObject> dataObjList = JSONObject.parseArray(dataArray.toJSONString(), JSONObject.class);
        XWPFChart chartLine = document.createChart(run, (int)(14.5 * Units.EMU_PER_CENTIMETER),
                9 * Units.EMU_PER_CENTIMETER);
        chartLine.setChartTopMargin(1000L);
        // 3、图表相关设置
        chartLine.setTitleText(title); // 图表标题
        chartLine.setTitleOverlay(false); // 图例是否覆盖标题

        // 4、图例设置
        XDDFChartLegend legendLine = chartLine.getOrAddLegend();
        legendLine.setPosition(LegendPosition.BOTTOM); // 图例位置:上下左右

        // 5、X轴(分类轴)相关设置
        XDDFCategoryAxis xAxisLine = chartLine.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置
        xAxisLine.setTickLabelPosition(AxisTickLabelPosition.LOW); // 设置X周的文字一直在最下方
        String[] xAxisDataLine = new String[4];
        Double[] yAxisDataLine_1 = new Double[4];
        Double[] yAxisDataLine_2 = new Double[4];
        for (int i = 0; i < dataObjList.size(); i++) {
            xAxisDataLine[i] = dataObjList.get(i).getString("ssqj");
            if (title.equals("图表1")) {
                yAxisDataLine_1[i] = dataObjList.get(i).getDouble("value1");
                yAxisDataLine_2[i] = dataObjList.get(i).getDouble("value2");
            } else if (title.equals("图表2")) {
                yAxisDataLine_1[i] = dataObjList.get(i).getDouble("bdl_1");
            }
        }


        XDDFCategoryDataSource xAxisSourceLine = XDDFDataSourcesFactory.fromArray(xAxisDataLine); // 设置X轴数据

        // 6、Y轴(值轴)相关设置
        XDDFValueAxis yAxisLine = chartLine.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置
        yAxisLine.setCrossBetween(AxisCrossBetween.BETWEEN); // 设置图柱的位置:BETWEEN居中

        // 7、创建柱状图对象
        XDDFLineChartData lineChart = (XDDFLineChartData) chartLine.createData(ChartTypes.LINE, xAxisLine, yAxisLine);
        if (title.equals("图表1")) {//双折线图
            XDDFNumericalDataSource<Double> yAxisSourceLine = XDDFDataSourcesFactory.fromArray(yAxisDataLine_1); // 设置Y轴数据
            XDDFNumericalDataSource<Double> yAxisSourceLine2 = XDDFDataSourcesFactory.fromArray(yAxisDataLine_2); // 设置Y轴数据
            // 8、加载柱状图数据集
            XDDFLineChartData.Series lineSeries = (XDDFLineChartData.Series) lineChart.addSeries(xAxisSourceLine, yAxisSourceLine);
            lineSeries.setTitle("收入", null); // 图例标题
            XDDFLineChartData.Series lineSeries2 = (XDDFLineChartData.Series) lineChart.addSeries(xAxisSourceLine, yAxisSourceLine2);
            lineSeries2.setTitle("支出", null); // 图例标题
            setLineSeriesStyle(lineSeries);
            setLineSeriesStyle(lineSeries2);
        }else{
            XDDFNumericalDataSource<Double> yAxisSourceLine = XDDFDataSourcesFactory.fromArray(yAxisDataLine_1); // 设置Y轴数据
            XDDFLineChartData.Series lineSeries = (XDDFLineChartData.Series) lineChart.addSeries(xAxisSourceLine, yAxisSourceLine);
            
            lineSeries.setTitle("营业收入",null);
            
            setLineSeriesStyle(lineSeries);
        }




        CTPlotArea plotArea = chartLine.getCTChart().getPlotArea();
        for (CTLineSer ser : plotArea.getLineChartArray(0).getSerList()) {
            CTDLbls ctdLbls = ser.addNewDLbls();
            ctdLbls.addNewShowCatName().setVal(false);// 是否展示对应x轴上的值(类型名称)
            ctdLbls.addNewShowVal().setVal(true);// 是否展示数值
            ctdLbls.addNewShowSerName().setVal(false);// 是否展示归属折线名称(系列名称)
            ctdLbls.addNewShowLegendKey().setVal(false);// 是否展示图例(图例项标示)
            ctdLbls.addNewDLblPos().setVal(STDLblPos.IN_END);//数据标签
        }
        // 9、绘制柱状图
        chartLine.plot(lineChart);
    }

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
您好!关于 Java POI 对比图表-蝴蝶图的问题,我可以给您提供一些参考意见。 首先,需要明确的是,POIJava 语言操作 Microsoft Office 文件的一种 API,可以用来创建、读取和修改 Excel 文件。而对比图表-蝴蝶图是 Excel 中的一种图表类型,用于比较两个相似数据系列之间的差异。 在 Java POI 中创建对比图表-蝴蝶图,可以参考以下步骤: 1. 创建一个工作簿对象,并在其中创建一个工作表对象。 2. 在工作表中创建两个数据系列,并设置其数据范围。 3. 创建一个蝴蝶图对象,并将其插入到工作表中。 4. 将两个数据系列添加到蝴蝶图中,并设置其名称和颜色等属性。 这里给出一个简单的示例代码,供您参考: ``` // 创建一个工作簿对象 Workbook wb = new XSSFWorkbook(); // 在工作簿中创建一个工作表对象 Sheet sheet = wb.createSheet("蝴蝶图"); // 在工作表中创建两个数据系列 Row row1 = sheet.createRow(0); row1.createCell(0).setCellValue("产品A"); row1.createCell(1).setCellValue(100); row1.createCell(2).setCellValue(200); row1.createCell(3).setCellValue(300); Row row2 = sheet.createRow(1); row2.createCell(0).setCellValue("产品B"); row2.createCell(1).setCellValue(150); row2.createCell(2).setCellValue(250); row2.createCell(3).setCellValue(350); // 创建一个蝴蝶图对象,并将其插入到工作表中 Drawing<?> drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 20); Chart chart = drawing.createChart(anchor); ChartLegend legend = chart.getOrCreateLegend(); legend.setPosition(LegendPosition.TOP_RIGHT); // 将两个数据系列添加到蝴蝶图中,并设置其名称和颜色等属性 ChartDataSource<Number> xs = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 1, 3)); ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 1, 3)); ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 1, 3)); LineChartData data1 = chart.getChartDataFactory().createLineChartData(); LineChartSeries series1 = data1.addSeries(xs, ys1); series1.setTitle("产品A"); series1.setSmooth(false); series1.setMarkerSize((short) 6); series1.setMarkerStyle(MarkerStyle.CIRCLE); series1.setLineColor(IndexedColors.BLACK.index); LineChartData data2 = chart.getChartDataFactory().createLineChartData(); LineChartSeries series2 = data2.addSeries(xs, ys2); series2.setTitle("产品B"); series2.setSmooth(false); series2.setMarkerSize((short) 6); series2.setMarkerStyle(MarkerStyle.TRIANGLE); series2.setLineColor(IndexedColors.RED.index); chart.plot(data1, new ChartAxis[]{}, new ChartAxis[]{}, data2); ``` 以上是一个简单的示例代码,用于演示如何使用 Java POI 创建对比图表-蝴蝶图。实际应用中,还需要根据具体需求进行适当调整和优化。希望这些信息能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值