饼图 Apache POI (4.1.1) - 如何将数据标签的数字格式设置为 0,00

Pie Chart Apache POI (4.1.1) - How to get the number format of data labels to 0,00

我在互联网上做了一些搜索(和代码检查),但似乎找不到我要找的东西...

我是做什么的: 我在 excel 中创建了一个饼图,它工作正常,除了百分比值显示在前几个小数位之外:

我在生成的 Excel 中玩了一下,如果我能以编程方式访问“类别”- 数字 属性,那将会有所帮助:

在我的代码中,我已经尝试设置数字格式,这对我来说没有任何改变:

public void createPieChartInSheet(Workbook wb, XSSFDrawing drawing, String chartTitle, XSSFClientAnchor anchor, LinkedList<Triple<String, XDDFDataSource<String>, XDDFNumericalDataSource<Double>>> chartSeries, LinkedList<byte[]> colorScheme) {
    XSSFChart chart = drawing.createChart(anchor);
    chart.setTitleText(chartTitle);
    chart.setTitleOverlay(false);

    XDDFDataSource<String> cat = chartSeries.get(0).getMiddle();
    XDDFNumericalDataSource<Double> val = chartSeries.get(0).getRight();

    XDDFChartData data = chart.createData(ChartTypes.PIE, null, null);
    Series series = data.addSeries(cat, val);
    series.setTitle(chartSeries.get(0).getLeft(), null);

    // Add data labels
    if (!chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).isSetDLbls()) {
        chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDLbls();
    }
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowVal().setVal(true);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewNumFmt().setFormatCode("0,00");

    setPieChartColors(colorScheme, chart, series);
    chart.plot(data);
}

我在寻找正确的东西吗?感谢任何帮助 - 谢谢!

总是很难找出与 Excel 相关的问题,因为文档不清晰,而且有很多 XML 标签没有意​​义的名称。

我发现有用的一种方法是比较实际 xml 工作和不工作 excel 文件。

所以我创建了一个不工作的 excel 使用程序,然后使用 MS Excel 进行编辑以应用格式来创建一个工作的 excel。 然后通过解压后的xl\charts\chart1.xml比较excel, 发现问题是由于以下行
来自节目

<c:numFmt formatCode="0.00"/>

用 MS 编辑后 Excel

<c:numFmt formatCode="0.00" sourceLinked="0"/>

“0”为假,默认值为“1”(真)。

来自 the document of sourceLinked, I guess the formatting will follow the source(cell original format) when set to true, so we need to set to false to make our formatting effective. We can do so by calling CTNumFmt#setSourceLinked(boolean) 错误。

以下程序演示了如何生成具有自定义数字格式的饼图。(基于 ),运行 on POI 4.1.1。

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumFmt;

public class CustomDecimalPlace {
    public static void main(String[] args) throws FileNotFoundException, IOException {
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            XSSFSheet sheet = wb.createSheet("piechart");
            final int NUM_OF_ROWS = 2;
            final int NUM_OF_COLUMNS = 10;

            // Create a row and put some cells in it. Rows are 0 based.
            Row row;
            Cell cell;
            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
                row = sheet.createRow((short) rowIndex);
                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
                    cell = row.createCell((short) colIndex);
                    if (rowIndex == 0) {
                        cell.setCellValue("Cat " + (colIndex + 1));
                    } else {
                        cell.setCellValue(((double) 101) / ((double) (colIndex + 1)));
                    }
                }
            }

            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 4, 10, 25);

            XSSFChart chart = drawing.createChart(anchor);
            chart.setTitleText("Pie Chart");
            chart.setTitleOverlay(false);
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.TOP_RIGHT);

            XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                    new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
            XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                    new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
            XDDFChartData data = chart.createData(ChartTypes.PIE, null, null);
            data.setVaryColors(true);
            data.addSeries(cat, val);
            chart.plot(data);
            if (!chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).isSetDLbls()) {
                chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDLbls();
            }
            CTDLbls dLbls = chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls();
            dLbls.addNewShowVal().setVal(true);
            dLbls.addNewShowSerName().setVal(false);
            dLbls.addNewShowCatName().setVal(false);
            dLbls.addNewShowPercent().setVal(false);
            dLbls.addNewShowLegendKey().setVal(false);
            CTNumFmt addNewNumFmt = dLbls.addNewNumFmt();
            addNewNumFmt.setFormatCode("0.00");
            // Set false to not follow source format
            addNewNumFmt.setSourceLinked(false);
            // Write the output to a file
            try (FileOutputStream fileOut = new FileOutputStream("ooxml-pie-chart.xlsx")) {
                wb.write(fileOut);
            }
        }
    }
}

Excel 图表从存储值的单元格的数字格式中获取其数据标签数字格式。这称为“源链接”,是默认设置。因此,只需使用您想要的数字格式对这些单元格进行格式化即可。

但是如果你想让数据标签有一个特殊的其他数字格式,你需要在 DLbls 元素中添加一个 NumFmt 元素。你已经完成了。但是这个 NumFmt 不能是源代码链接。而且它必须有自己的 FormatCode,在 XML 中总是 en_US。本地化是由 Excel GUI 而不是在源 XML 中完成的。所以在你的情况下它必须是 0.00 因为点是小数点分隔符而逗号是 en_US 中的千位分隔符。但是如果你想让它有两个十进制数字的默认十进制数字格式,它必须是 #,##0.00.

按如下方式更改您的代码:

...
    // Add data labels
    if (!chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).isSetDLbls()) {
        chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDLbls();
    }
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowVal().setVal(true);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
    
    //chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewNumFmt().setFormatCode("0,00");
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewNumFmt();
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().getNumFmt().setSourceLinked(false);
    chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().getNumFmt().setFormatCode("#,##0.00");
...

这对我有用,并导致在我的德语 Excel 中使用数字格式 #.##0,00 的数据标签,这是具有两位小数的默认十进制数字格式。