我使用apache poi绘制了一个3D堆叠条形图,但在处理左轴标题的字体大小和图表的图例时遇到了麻烦。我查看了ooxml文档,发现了 here ,但无法确定是哪个对象造成了这种情况。我已经添加了我的代码和结果图表的一部分,我感谢任何帮助指导我在正确的道路上。
XSSFSheet sheet = wb.getSheetAt(0); // Bar chart coordinates XSSFDrawing drawing = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 37, 16, 47); XSSFChart chart = drawing.createChart(anchor); // configure axis properties XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); leftAxis.setTitle("Call Duration"); // font size for left axis labels (ticks) leftAxis.getOrAddTextProperties().setFontSize(8d); leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); XDDFChartData data = chart.createData(ChartTypes.BAR3D, bottomAxis, leftAxis); // create legend XDDFChartLegend legend = chart.getOrAddLegend(); legend.setPosition(LegendPosition.BOTTOM); /*DATA ADDITION HERE*/
output bar chart
发布于 2021-08-25 11:41:15
我已经找到了哪个xml对象解决了条形图、轴和图例的字体样式。我基本上是通过比较我的java代码生成的底层 xl/charts/chart1.xml 和我用ms excel手工绘制的另一个条形图来完成的。我之所以必须这样做,是因为对于值轴,apache poi的 XDDFValueAxis 对象没有实现轴标题操作方法,需要 org.openxmlformats.schemas.drawingml.x2006 应用程序接口。正如我在问题中提到的,文档可以在 here 中找到。文档的问题是不是每个对象的功能都很明显(至少对我来说是这样),因此,比较和分析xml对象可以深入了解某些对象实际上负责什么。这是我的代码片段,它有 apache poi 4.1.2 和 poi-ooxml-schemas-4.1.2 依赖项。希望它能对有类似问题的人有所帮助。
xl/charts/chart1.xml
XDDFValueAxis
org.openxmlformats.schemas.drawingml.x2006
apache poi 4.1.2
poi-ooxml-schemas-4.1.2
XSSFSheet sheet = wb.getSheetAt(0); // Bar chart coordinates XSSFDrawing drawing = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 38, 16, 47); XSSFChart chart = drawing.createChart(anchor); // configure axis properties XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); bottomAxis.getOrAddTextProperties().setFontSize(6d); XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); leftAxis.setTitle("Call Duration"); leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); // font size for left axis labels (ticks) leftAxis.getOrAddTextProperties().setFontSize(6d); // create legend XDDFChartLegend legend = chart.getOrAddLegend(); legend.setPosition(LegendPosition.BOTTOM); // reflect the underlying the xml objects in order to access fields that are not implemented in apache poi org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx ctValAx = null; org.openxmlformats.schemas.drawingml.x2006.chart.CTLegend ctLegend = null; java.lang.reflect.Field ctValRef; java.lang.reflect.Field chartLegendRef; try { ctValRef = XDDFValueAxis.class.getDeclaredField("ctValAx"); ctValRef.setAccessible(true); ctValAx = (org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx) ctValRef.get(leftAxis); chartLegendRef = XDDFChartLegend.class.getDeclaredField("legend"); chartLegendRef.setAccessible(true); ctLegend = (org.openxmlformats.schemas.drawingml.x2006.chart.CTLegend) chartLegendRef.get(legend); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); // set title properties for left axis CTTitle ctTitle = ctValAx.getTitle(); ctTitle.getTx().getRich().getPArray(0).getRArray(0).getRPr().setSz(600); // adjust the font size of the legend ctLegend.addNewTxPr(); ctLegend.getTxPr().addNewBodyPr(); ctLegend.getTxPr().addNewLstStyle(); // font size in hundreds format (6*100) ctLegend.getTxPr().addNewP().addNewPPr().addNewDefRPr().setSz(600); /*DATA ADDITION HERE*/
发布于 2021-08-27 05:56:04
至少对于图例的字体大小设置,使用 org.apache.poi.xddf.usermodel.text.XDDFTextBody 是可能的。这样做的好处是,这是一个可以进一步开发的高级 apache poi 类。因此,如果你有 XDDFChartLegend legend ,那么用它来构造一个 XDDFTextBody ,并用它来设置字体。
org.apache.poi.xddf.usermodel.text.XDDFTextBody
apache poi
XDDFChartLegend legend
XDDFTextBody
示例:
... XDDFChartLegend legend = chart.getOrAddLegend(); legend.setPosition(LegendPosition.BOTTOM); XDDFTextBody legendTextBody = new XDDFTextBody(legend); legendTextBody.getXmlObject().addNewBodyPr(); legendTextBody.addNewParagraph().addDefaultRunProperties().setFontSize(8d); legend.setTextBody(legendTextBody); ...
对于轴字体设置,需要使用低级 org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx 或 org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx 。但也有 org.apache.poi.xddf.usermodel.chart.XDDFTitle ,它是 CTValAx -title或 CTCatAx -title的高级包装器。所以我们应该使用它,而不是直接使用 CT* 类。
org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx
org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx
org.apache.poi.xddf.usermodel.chart.XDDFTitle
CTValAx
CTCatAx
CT*
使用 XDDFTitle getOrSetAxisTitle 方法:
XDDFTitle getOrSetAxisTitle
private static XDDFTitle getOrSetAxisTitle(XDDFValueAxis axis) { try { java.lang.reflect.Field _ctValAx = XDDFValueAxis.class.getDeclaredField("ctValAx"); _ctValAx.setAccessible(true); org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx ctValAx = (org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx)_ctValAx.get(axis); if (!ctValAx.isSetTitle()) { ctValAx.addNewTitle(); XDDFTitle title = new XDDFTitle(null, ctValAx.getTitle()); return title; } catch (Exception ex) { ex.printStackTrace(); return null; private static XDDFTitle getOrSetAxisTitle(XDDFCategoryAxis axis) { try { java.lang.reflect.Field _ctCatAx = XDDFCategoryAxis.class.getDeclaredField("ctCatAx"); _ctCatAx.setAccessible(true); org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx ctCatAx = (org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx)_ctCatAx.get(axis); if (!ctCatAx.isSetTitle()) { ctCatAx.addNewTitle(); XDDFTitle title = new XDDFTitle(null, ctCatAx.getTitle()); return title; } catch (Exception ex) { ex.printStackTrace(); return null; }
然后按如下方式使用它们:
... XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); //bottomAxis.setTitle("..."); XDDFTitle title = getOrSetAxisTitle(bottomAxis); title.setOverlay(false); title.setText("..."); title.getBody().getParagraph(0).addDefaultRunProperties().setFontSize(8d); bottomAxis.getOrAddTextProperties().setFontSize(8d); XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); //leftAxis.setTitle("..."); title = getOrSetAxisTitle(leftAxis); title.setOverlay(false); title.setText("..."); title.getBody().getParagraph(0).addDefaultRunProperties().setFontSize(8d);