【问题标题】:Pie Chart Apache POI (4.1.1) - How to get the number format of data labels to 0,00Pie Chart Apache POI (4.1.1) - 如何将数据标签的数字格式设置为0,00
【发布时间】:2020-10-13 08:40:58
【问题描述】:

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

我的工作: 我正在一个工作正常的 Excel 中创建一个饼图,除了百分比值显示为小数点后很多位:

我在生成的 Excel 中进行了一些操作,如果我可以通过编程方式访问“类别”- Numbers 属性会有所帮助:

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

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);
}

我什至在寻找正确的东西吗?任何帮助表示赞赏 - 谢谢!

【问题讨论】:

    标签: java apache-poi pie-chart


    【解决方案1】:

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

    但是如果你想让数据标签为特殊的其他数字格式,你需要在DLbls元素中添加一个NumFmt元素。你已经这样做了。但是这个NumFmt 不能是源链接。它必须有自己的FormatCode,在XML 中始终是en_US。本地化由ExcelGUI 完成,而不是在源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,这是具有两位十进制数字的默认十进制数字格式。

    【讨论】:

    • 谢谢!像魅力一样工作=) 嗯,是的,基础数据的格式是我要处理的另一个“项目”^^ 我也有我的问题:/(将发表另一篇文章,所以主题不会弄乱上...)
    【解决方案2】:

    总是很难找出与 Excel 相关的问题,因为文档不清晰,还有很多 XML 标记的名称毫无意义。

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

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

    <c:numFmt formatCode="0.00"/>
    

    使用 MS Excel 编辑后

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

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

    来自the document of sourceLinked,我猜设置为true时格式会跟随源(单元格原始格式),所以我们需要设置为false才能使我们的格式生效。我们可以通过使用 false 调用 CTNumFmt#setSourceLinked(boolean) 来做到这一点。

    以下程序演示了如何生成具有自定义数字格式的饼图。(基于Axel Richter answer),在 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);
                }
            }
        }
    }
    

    【讨论】:

    • 感谢您对调试的建议 =) 我不知道。对于您的示例,我必须更改 // XDDFPieChartData data = new XDDFPieChartData(chart.getCTChart().getPlotArea().addNewPieChart()); TO:XDDFChartData 数据 = chart.createData(ChartTypes.PIE, null, null);而且我没有看到您设置的 cellStyle 的任何用法,所以我猜它只是在图表中工作,因为您的源双打最终在 excel 中“正确”?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多