添加更多标签时,Apache POI 图表位置垂直变化

Apache POI chart position vertically changed when more labels are added

提问人:raymax 提问时间:11/10/2023 更新时间:11/11/2023 访问量:30

问:

我正在编写一个代码,用于在 excel 文件中创建两个甜甜圈图。第一个图表有 10 个标签,第二个图表有 2 个标签。

我的问题是第二个图表。我想在锚点中同时将两个图表垂直对齐。但是由于标签和价值很少,它在锚地的地位发生了垂直变化。

enter image description here

从上面的图片可以看出。我把两个图表并排。但是第二个图表的位置垂直发生了变化,因为它只有两个标签。如何固定第二个图表位置与第一个图表位置对齐。

public String picChart9() throws IOException {

    try (XSSFWorkbook wb = new XSSFWorkbook()) {
        XSSFSheet sheet = wb.createSheet("doughnutChart");
        sheet.setDisplayGridlines(false);
        final int NUM_OF_ROWS = 2;
        final int NUM_OF_COLUMNS = 10;

        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        XSSFClientAnchor anchor1 = drawing.createAnchor(0, 0, 0, 0, 1, 5, 4, 28);
       // anchor1.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);
        XSSFClientAnchor anchor2 = drawing.createAnchor(0, 0, 0, 0, 4, 5, 7, 28);
       // anchor2.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);

        XSSFChart chart1 = drawing.createChart(anchor1);
        chart1.setTitleText("chart1");
        chart1.setTitleOverlay(false);
        //chart1.createValueAxis(AxisPosition.TOP);

        XSSFChart chart2 = drawing.createChart(anchor2);
        chart2.setTitleText("chart2");
        chart2.setTitleOverlay(false);
        //chart2.createValueAxis(AxisPosition.LEFT);
        /**/
        System.out.println("chart1.getCTChart() --:"+chart1.getCTChart());
        System.out.println("chart1.getAxes() --:"+chart1.getAxes());
        System.out.println("chart2.getAxes() --:"+chart2.getAxes());
        /**/
        XDDFChartLegend legend1 = chart1.getOrAddLegend();
        legend1.setPosition(LegendPosition.BOTTOM);

        XDDFChartLegend legend2 = chart2.getOrAddLegend();
        legend2.setPosition(LegendPosition.BOTTOM);

        String[] stringArray1 = new String[]{"one","two","three","four","five","six","seven","eight","nine","ten"};
        XDDFDataSource<String> stringValue1 = XDDFDataSourcesFactory.fromArray(stringArray1);
        Long[] longArray1 = new Long[]{ 11L,2L,3L,4L,5L,6L,7L,8L,9L,10L };
        XDDFNumericalDataSource<Long> longValue1 = XDDFDataSourcesFactory.fromArray(longArray1);

        String[] stringArray2 = new String[]{"one","two"};
        XDDFDataSource<String> stringValue2 = XDDFDataSourcesFactory.fromArray(stringArray2);
        Long[] longArray2 = new Long[]{ 60L,40L };
        XDDFNumericalDataSource<Long> longValue2 = XDDFDataSourcesFactory.fromArray(longArray2);

        XDDFDoughnutChartData data1 = new XDDFDoughnutChartData(chart1, chart1.getCTChart().getPlotArea().addNewDoughnutChart());
        data1.setVaryColors(true);
        data1.setHoleSize((short) 50);
        data1.setFirstSliceAngle(10);

        XDDFDoughnutChartData data2 = new XDDFDoughnutChartData(chart2, chart2.getCTChart().getPlotArea().addNewDoughnutChart());
        data2.setVaryColors(true);
        data2.setHoleSize((short) 50);
        data2.setFirstSliceAngle(10);

        XDDFChartData.Series series1 = data1.addSeries(stringValue1, longValue1);
        XDDFChartData.Series series2 = data2.addSeries(stringValue2, longValue2);

        // Remove the Anchore border line
        (chart1).getCTChartSpace().addNewSpPr().addNewLn().addNewNoFill();
        (chart2).getCTChartSpace().addNewSpPr().addNewLn().addNewNoFill();

        // Data point colors; is necessary for showing data points in Calc

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

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

        //plot chart
        chart1.plot(data1);
        chart2.plot(data2);

        // Write the output to a file
        try (FileOutputStream fileOut = new FileOutputStream("picChart9.xlsx")) {
            wb.write(fileOut);
        }
    }
    return null;
}

我正在使用上面的代码。 谢谢。如果我的问题不清楚,请告诉我。

java spring-boot apache-poi

评论


答:

1赞 Axel Richter 11/11/2023 #1

默认情况下,Excel 图表的绘图区域在标题和图例之间使用尽可能多的图表空间。如果不需要,则必须手动调整绘图区域的大小。

要了解如何操作,可以使用默认设置创建图表。之后,解压缩并查看 .它的 XML 如下所示:*.xlsx/xl/charts/chart*.xml

...
<c:plotArea>
 <c:layout/>
...

未定义打印区域的布局 - 默认值。

然后使用 Excel GUI 调整绘图区域的大小并保存。再次解压缩并查看 .然后,它的 XML 如下所示:*.xlsx/xl/charts/chart*.xml

...
<c:plotArea>
 <c:layout>
  <c:manualLayout>
   <c:layoutTarget val="inner"/>
   <c:xMode val="edge"/>
   <c:yMode val="edge"/>
   <c:x val="0.1"/>
   <c:y val="0.1"/>
   <c:w val="0.8"/>
   <c:h val="0.6"/>
  </c:manualLayout>
 </c:layout>
...

绘图区域的布局是针对图表空间内部空间的手动布局。它的 x 和 y 模式是边缘模式,意味着 x 和 y 坐标定向在周围空间的边缘。从周围空间左边缘开始的 x 位置为 0.1(周围空间宽度的 10%)。从周围空间的上边缘开始的 y 位置为 0.1(周围空间高度的 10%)。宽度(w)为0.8(周围空间宽度的80%)。高度(h)为0.6(周围空间高度的60%)。

使用 java 代码如下所示:

让它成为 ,那么:XSSFChart chart

// set plot area size
if (!chart.getCTChart().getPlotArea().isSetLayout()) {
    chart.getCTChart().getPlotArea().addNewLayout();
}
if (chart.getCTChart().getPlotArea().getLayout().isSetManualLayout()) {
    chart.getCTChart().getPlotArea().getLayout().unsetManualLayout();
}
chart.getCTChart().getPlotArea().getLayout().addNewManualLayout();
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewLayoutTarget().setVal(
 org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutTarget.INNER);
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewXMode().setVal(
 org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutMode.EDGE);
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewYMode().setVal(
 org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutMode.EDGE);
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewX().setVal(0.10); //10% from left
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewY().setVal(0.10); //10% from top
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewW().setVal(0.80); //80% width
chart.getCTChart().getPlotArea().getLayout().getManualLayout().addNewH().setVal(0.60); //60% height