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

huangapple go评论61阅读模式
英文:

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

问题

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

我在做什么:
我正在Excel中创建一个饼图,它可以正常工作,除了百分比值显示了太多的小数位:

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

我在生成的Excel中尝试了一些操作,如果我可以以编程方式访问"Category" - Numbers属性将会有所帮助:
饼图 Apache POI(4.1.1)- 如何将数据标签的数字格式设置为0,00

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

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

    // 添加数据标签
    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);
}

我甚至在寻找正确的东西吗?任何帮助都将不胜感激 - 谢谢!

英文:

I did some searching around the internet (and the code inspection), but it seems I cannot find what im looking for...

What I do:
I´m creating a pie chart in an excel which works fine, EXCEPT that the percent values are shown with top many decimal places:

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

I played a bit around in the generated Excel and it would help if I could access the "Category" - Numbers property programmatically:
饼图 Apache POI(4.1.1)- 如何将数据标签的数字格式设置为0,00

In my code I already tried to set the number format, which doesn´t change anything for me:

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

    XDDFDataSource&lt;String&gt; cat = chartSeries.get(0).getMiddle();
    XDDFNumericalDataSource&lt;Double&gt; 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(&quot;0,00&quot;);

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

Am I even searching for the right thing? Any help appreciated - thank you!

答案1

得分: 4

以下是翻译好的内容:

一个 Excel 图表会从存储值的单元格的数字格式中获取其数据标签的数字格式。这被称为“源链接”并且是默认设置。所以只需使用你想要的数字格式对这些单元格进行格式化。

但是,如果你想要数据标签具有特殊的其他数字格式,你需要向 DLbls 元素添加一个 NumFmt 元素。你已经做到了。但是这个 NumFmt 不能与源链接。它必须有它自己的 FormatCode,在 XML 中始终是 en_US。本地化是由 ExcelGUI 完成的,而不是在源 XML 中完成的。所以在你的情况下,它必须是 0.00,因为点号是小数分隔符,而逗号是千位分隔符在 en_US 中。但是,如果你想要默认的小数数字格式,保留两位小数,它必须是 #,##0.00

将你的代码更改如下:

...
// 添加数据标签
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(&quot;0,00&quot;);
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(&quot;#,##0.00&quot;);
...

对我来说,这是有效的,并且导致了在我的德国版 Excel 中具有数字格式 #.##0,00 的数据标签,这是默认的小数数字格式,保留两位小数。

英文:

An Excel chart get it's data label number format from the number format of the cells where the values are stored. That's called "source linked" and is the default. So simply do formatting those cells using the number format you want.

But if you want to have the data labels a special other number format, you need add a NumFmt element to the DLbls element. You have done tis alrady. But this NumFmt must not be source linked then. And it must have it's own FormatCode, which is always en_US in the XML. The localizing is done by the Excel GUI and not in the source XML. So it would must be 0.00 in your case since dot is decimal separator while comma is thousands separator in en_US. But if you want have it the default decimal number format having two decimal digits, it would must be #,##0.00.

Change your code as follows:

...
// 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(&quot;0,00&quot;);
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(&quot;#,##0.00&quot;);
...

This works for me and leads to have data labels the number format #.##0,00 in my German Excel, which is the default decimal number format having two decimal digits.

答案2

得分: 3

以下是您要翻译的内容:

"在解决与Excel相关的问题时,通常很难弄清楚,因为文档不够清晰,而且有很多带有无意义名称的XML标记。

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

因此,我使用程序创建了一个不工作的Excel文件,然后使用MS Excel进行编辑,以应用格式设置以创建一个工作的Excel文件。
然后,通过解压缩Excel后比较 xl\charts\chart1.xml
找到了问题,原因是以下行
来自程序

&lt;c:numFmt formatCode=&quot;0.00&quot;/&gt;

使用MS Excel编辑后

&lt;c:numFmt formatCode=&quot;0.00&quot; sourceLinked=&quot;0&quot;/&gt;

"0"是假的,默认值是"1"(真)。

根据源链接文档,我猜测当设置为true时,格式将遵循源(单元格的原始格式),因此我们需要将其设置为false才能使我们的格式生效。我们可以通过调用CTNumFmt#setSourceLinked(boolean)并将其设置为false来实现这一点。

以下程序演示了如何使用自定义数字格式生成饼图(基于Axel Richter的答案),在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(&quot;piechart&quot;);
            final int NUM_OF_ROWS = 2;
            final int NUM_OF_COLUMNS = 10;

            // 创建一行并放入一些单元格。行从0开始。
            Row row;
            Cell cell;
            for (int rowIndex = 0; rowIndex &lt; NUM_OF_ROWS; rowIndex++) {
                row = sheet.createRow((short) rowIndex);
                for (int colIndex = 0; colIndex &lt; NUM_OF_COLUMNS; colIndex++) {
                    cell = row.createCell((short) colIndex);
                    if (rowIndex == 0) {
                        cell.setCellValue(&quot;Cat &quot; + (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(&quot;饼图&quot;);
            chart.setTitleOverlay(false);
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.TOP_RIGHT);

            XDDFDataSource&lt;String&gt; cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                    new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
            XDDFNumericalDataSource&lt;Double&gt; 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(&quot;0.00&quot;);
            // 设置为false以不跟随源格式
            addNewNumFmt.setSourceLinked(false);
            // 将输出写入文件
            try (FileOutputStream fileOut = new FileOutputStream(&quot;ooxml-pie-chart.xlsx&quot;)) {
                wb.write(fileOut);
            }
        }
    }
}
英文:

It is always difficult to figure out problem related to Excel, as documentation is not clear and there are so many XML tag with meaningless name.

One way I find useful is to compare the actual xml of working and not working excel file.

So I created a not working excel using program, and then edit using MS Excel to apply formatting to create a working excel.
Then by comparing xl\charts\chart1.xml after unzip the excel,
The problem is found and due to the following line
From program

&lt;c:numFmt formatCode=&quot;0.00&quot;/&gt;

After edit with MS Excel

&lt;c:numFmt formatCode=&quot;0.00&quot; sourceLinked=&quot;0&quot;/&gt;

"0" is false and the default value is "1"(true).

From 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) with false.

Following program demonstrate how to generate Pie chart with custom number format.(Base on Axel Richter answer), running 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(&quot;piechart&quot;);
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 &lt; NUM_OF_ROWS; rowIndex++) {
row = sheet.createRow((short) rowIndex);
for (int colIndex = 0; colIndex &lt; NUM_OF_COLUMNS; colIndex++) {
cell = row.createCell((short) colIndex);
if (rowIndex == 0) {
cell.setCellValue(&quot;Cat &quot; + (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(&quot;Pie Chart&quot;);
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
XDDFDataSource&lt;String&gt; cat = XDDFDataSourcesFactory.fromStringCellRange(sheet,
new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
XDDFNumericalDataSource&lt;Double&gt; 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(&quot;0.00&quot;);
// Set false to not follow source format
addNewNumFmt.setSourceLinked(false);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream(&quot;ooxml-pie-chart.xlsx&quot;)) {
wb.write(fileOut);
}
}
}
}

huangapple
  • 本文由 发表于 2020年10月13日 16:40:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/64331671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定