如何更改 apache poi 生成的图表以不使用平滑线并将空单元格显示为间隙?

How can I change charts generated by apache poi to not use smoothed lines and show empty cells as gaps?

我使用的是 POI 3.12-beta1,我的代码可以创建一个包含多个数据集并在图例中命名系列的折线图。但是,poi 中折线图的默认设置会生成一条在数据点上平滑的线。空值也被绘制为 0,但我们希望线条停在有空单元格的第一列。

在 xlsx 文件中呈现图表后,我可以进入图表属性并更改这些设置,但我们需要使用这些设置呈现 xlsx。我在可用 API 中找不到任何内容来更改这些设置。

我使用这个示例 class 作为我下面代码的起点 http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java

        Drawing drawing = sheet.createDrawingPatriarch();
        ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 17, 18, 30);
        Chart chart = drawing.createChart(anchor);
        ChartLegend legend = chart.getOrCreateLegend();
        legend.setPosition(LegendPosition.RIGHT);
        LineChartData data = chart.getChartDataFactory().createLineChartData();
        ChartAxis bottomAxis = chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
        ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);

        int row = 2;
        int startCol = 3;
        int endCol = 17;
        boolean abs = false;
        ChartDataSource<Number> xs = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(row, row, startCol, endCol));

        row = 10;
        int seriesCol = 0;
        ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(row, row, startCol, endCol));
        LineChartSerie ser1 = data.addSerie(xs, ys1);
        ser1.setTitle(new CellReference(sheet.getSheetName(), row, seriesCol, abs, abs));

        row = 11;
        ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(row, row, startCol, endCol));
        LineChartSerie ser2 = data.addSerie(xs, ys2);
        ser2.setTitle(new CellReference(sheet.getSheetName(), row, seriesCol, abs, abs));

        row = 12;
        ChartDataSource<Number> ys3 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(row, row, startCol, endCol));
        LineChartSerie ser3 = data.addSerie(xs, ys3);
        ser3.setTitle(new CellReference(sheet.getSheetName(), row, seriesCol, abs, abs));

        chart.plot(data, new ChartAxis[] { bottomAxis, leftAxis });

我找不到相同问题的任何解决方案,所以我最终试图找到一些 "creative workaround"。这根本不是一个干净的方法,但我会分享它以防万一。

原来默认的ChartPOI界面不允许做很多操作(修改Axis和Legend,仅此而已)。

不过,我确实使用 XLSX 文件,并且实现 XSSFChart class 提供了更多的功能,例如 setPlotOnlyVisibleCells 方法,它确实在 enabling/disabling 中的该选项中起作用"Hidden & Empty Cells" 菜单。然而,这不是我们想要的!

如果您查看 XLSX 文件格式(基本上是 XML),您会注意到有一个 "dispBlanksAs" XML 元素作为 Chart 元素的子元素,并且我们要将其设置为 "gap"。 (POI不会设置,相当于设置为"zero")。

不幸的是,目前 POI API 中没有这样的方法,所以我不得不求助于以下肮脏的代码来让它工作:

XSSFChart chart = (XSSFChart)drawing.createChart(anchor);
CTDispBlanksAs disp = CTDispBlanksAs.Factory.newInstance();
disp.setVal(STDispBlanksAs.GAP);
chart.getCTChart().setDispBlanksAs(disp);

这段代码很可能在很多方面都应该受到谴责,但它对我有用:)

重要的一点是,您需要在 class 路径上安装 ooxml-schemas 1.1 jar 才能工作。它甚至无法使用 poi-ooxml-schemas 3.12,因为它不包含 CTDispBlanksAs class.

的定义

希望未来版本的 POI 能够支持此功能。

感谢 Etienne 提供将空白设置为间隙的代码。我得到了 POI 开发人员的帮助,这里是解决原始问题中提到的两个问题的解决方案。

    XSSFChart chart = (XSSFChart)drawing.createChart(anchor);

    // this will set blank values as gaps in the chart so you 
    // can accurately plot data series of different lengths
    CTDispBlanksAs disp = CTDispBlanksAs.Factory.newInstance();
    disp.setVal(STDispBlanksAs.GAP);
    chart.getCTChart().setDispBlanksAs(disp);


    // setup chart, axes, data series, etc


    chart.plot(data, new ChartAxis[] { bottomAxis, leftAxis });

    // this must occur after the call to chart.plot above
    CTPlotArea plotArea = chart.getCTChart().getPlotArea();
    for (CTLineChart ch : plotArea.getLineChartList()) {
        for (CTLineSer ser : ch.getSerList()) {
            CTBoolean ctBool = CTBoolean.Factory.newInstance();
            ctBool.setVal(false);
            ser.setSmooth(ctBool);
        }
    }