Issue
I am creating multiple doughnut charts using Apache POI. I face problems when the label String size is big and when more labels are added. In the Apache POI documentation, I found no method in XDDFChartLegend where the margin can be adjusted. I also want those labels to fit in the space allocated for the Legends, regardless of size.
In the above picture, one can observe
When the legend's string size is big, then it overlays on the chart. Also, there are 10 legends. But only 8 are being displayed.
When The legends are small in string size, then all the legends are displayed.
public static XSSFChart createDoughnutChart(XSSFSheet sheet, String[] categories,Number[] values, String titleText, int col1, int row1, int col2, int row2) { XSSFDrawing drawing = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, col1, row1, col2, row2); XSSFChart chart = drawing.createChart(anchor); chart.setTitleText(titleText); chart.setTitleOverlay(false); XDDFChartLegend legend = chart.getOrAddLegend(); legend.setPosition(LegendPosition.BOTTOM); legend.setOverlay(true); //setting legend size XDDFTextBody legendTextBody = new XDDFTextBody(legend); legendTextBody.getXmlObject().addNewBodyPr(); legendTextBody.addNewParagraph().addDefaultRunProperties().setFontSize(6d); legend.setTextBody(legendTextBody); XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromArray(categories); XDDFNumericalDataSource<Number> val = XDDFDataSourcesFactory.fromArray(values); XDDFDoughnutChartData data = (XDDFDoughnutChartData)chart.createData(ChartTypes.DOUGHNUT, null, null); data.setVaryColors(false); data.setHoleSize(50); XDDFChartData.Series series = data.addSeries(cat, val); chart.plot(data); // Do not auto delete the title; is necessary for showing title in Calc if (chart.getCTChart().getAutoTitleDeleted() == null) chart.getCTChart().addNewAutoTitleDeleted(); chart.getCTChart().getAutoTitleDeleted().setVal(false); // Data point colors; is necessary for showing data points in Calc int pointCount = series.getCategoryData().getPointCount(); for (int p = 0; p < pointCount; p++) { chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(p); chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDPtArray(p) .addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(XlsxService.getColor(p)); } // Add data labels if (!chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).isSetDLbls()) { chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDLbls(); } chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDLbls().addNewShowVal().setVal(true); chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false); chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(false); chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(false); chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false); // chart area (chartspace) without border line chart.getCTChartSpace().addNewSpPr().addNewLn().addNewNoFill(); // changing background color if (chart.getCTChartSpace().getSpPr() == null) chart.getCTChartSpace().addNewSpPr(); if (chart.getCTChartSpace().getSpPr().isSetSolidFill()) chart.getCTChartSpace().getSpPr().unsetSolidFill(); chart.getCTChartSpace().getSpPr().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{(byte)242, (byte)242, (byte)242}); // 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 return chart;}
Solution
This has nothing to do with positioning the legend. This is done via legend.setPosition(LegendPosition.BOTTOM); which means legend is positioned at bottom of chart space and grows up to top.
But as often, there never is enough space. And so legend grows into the plot area to fit content in.
To avoid this, only possibility is to shrink the legend area size. That is similar to set plot area size, what you already do.
XSSFChart chart = ...
// set legend area size
if (!chart.getCTChart().getLegend().isSetLayout()) {
chart.getCTChart().getLegend().addNewLayout();
}
if (chart.getCTChart().getLegend().getLayout().isSetManualLayout()) {
chart.getCTChart().getLegend().getLayout().unsetManualLayout();
}
chart.getCTChart().getLegend().getLayout().addNewManualLayout();
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewXMode().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutMode.EDGE);
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewYMode().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STLayoutMode.EDGE);
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewX().setVal(0.0); //0% from left
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewY().setVal(0.70); //70% from top
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewW().setVal(1.00); //100% width
chart.getCTChart().getLegend().getLayout().getManualLayout().addNewH().setVal(0.30); //30% height
But now the legend content will not more fit into the legend size.
One could set smaller font size for legend content, like so:
//set legend default font size
if (chart.getCTChart().getLegend().isSetTxPr()) {
chart.getCTChart().getLegend().unsetTxPr();
}
chart.getCTChart().getLegend().addNewTxPr();
chart.getCTChart().getLegend().getTxPr().addNewBodyPr();
chart.getCTChart().getLegend().getTxPr().addNewP();
chart.getCTChart().getLegend().getTxPr().getPArray(0).addNewPPr();
chart.getCTChart().getLegend().getTxPr().getPArray(0).getPPr().addNewDefRPr().setSz(600); // default font size 6pt
But this quickly leads to be the legend text impossible to read.
Then the chart space must be set bigger by making anchor's row2 bigger.
Answered By - Axel Richter

0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.