如何在POI 4.0.1的XDDFChart中添加带有SECOND AXIS的第二行? [英] How do I add a second line with a SECOND AXIS to an XDDFChart in POI 4.0.1?

查看:244
本文介绍了如何在POI 4.0.1的XDDFChart中添加带有SECOND AXIS的第二行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在现有图表的第二个轴(右轴)上添加一条线.是否可以通过POI 4.0.0/1中的图表的新实现来做到这一点?

I am unable to add a line on a second axis (right axis) on an existing chart. Is there a way to do this with the new implementation of Charts in POI 4.0.0/1?

所需的输出将如下所示(带有2轴的简单excel图表): .以该图表为例的关联数据:

Desired output will look like this (A simple excel chart with 2 axes): . The associated data to that chart as an example:

第1系列/Axis1 = [1、2、3、4、5、6、7、8、9]

Series 1/Axis1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

Series 2/Axis2 = [200,300,400,500,600,700,800,900,1000]

Series 2/Axis2 = [200,300,400,500,600,700,800,900,1000]

这是我到目前为止在Java中尝试的代码,大部分都是从LineChart.java复制的.

Here is the code that I am trying so far in Java, it is mostly replicated from the LineChart.java example

//Initial code instantiates a document
XWPFDocument doc = new XWPFDocument();
...


//  Generate Chart
//  This was taken from the example https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java
XWPFChart prChart = doc.createChart();

//Values 1 on the Left Axis
//Values 2 on the Right Axis
String[] categories = dates.toArray(new String[dates.size()]);
BigDecimal[] values1 = prices1.toArray(new BigDecimal[prices1.size()]);
BigDecimal[] values2 = prices2.toArray(new BigDecimal[prices2.size()]);

XDDFChartAxis bottomAxis = prChart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setMajorTickMark(AxisTickMark.NONE);

XDDFValueAxis leftAxis = prChart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
leftAxis.setMajorTickMark(AxisTickMark.OUT);

/*
 * Is this made correctly?  
 */
XDDFValueAxis rightAxis = prChart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosses(AxisCrosses.MAX);
rightAxis.setMajorTickMark(AxisTickMark.IN);


final int numOfPoints = categories.length;
final String categoryDataRange = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
final String valuesDataRange = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
final String valuesDataRange2 = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));

final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);

XDDFLineChartData line = (XDDFLineChartData) prChart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) line.addSeries(categoriesData, valuesData);            
series1.setTitle("Price", null);
series1.setSmooth(true);
series1.setMarkerStyle(MarkerStyle.NONE);
solidLineSeries(series1, PresetColor.BLUE_VIOLET);

// Am I adding the rightAxis correctly here?
XDDFLineChartData line2 = (XDDFLineChartData) prChart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) line2.addSeries(categoriesData, valuesData2);
series2.setTitle("Index", null);
series2.setSmooth(true);
series2.setMarkerStyle(MarkerStyle.NONE);
solidLineSeries(series2, PresetColor.BLACK);


prChart.plot(line);
prChart.plot(line2);        ///     <- Does this add to the same plot correctly?
prChart.displayBlanksAs(DisplayBlanks.GAP);

运行此代码不会产生任何编译错误.但是打开文档其内容有问题"时,我确实得到了错误.

Running this code doesn't produce any compile errors. But I do get errors when opening the document "Problem with its' contents."

我想我没有正确添加第二条线和第二条轴.

I suppose I am not adding the 2nd line and 2nd axes correctly.

有没有办法做到这一点?

Is there a way to accomplish this?

更新w.解决方案 下面的Axel解决方案可以完美地工作.要了解的其他信息正是问题所在.

Update w. Solution Axel's solution below works perfectly. The additional info to know is exactly what was the issue.

我还想知道您添加到地块的顺序,希望对其他人有帮助

I would also like to recognize the order in which you add to the plot, this will hopefully help others

  1. 创建第一组轴
  2. 创建第一行
  3. 绘制第一行
  4. 创建新轴
  5. 创建第二行
  6. 绘制第二行
  7. 更新轴ID!

推荐答案

在一张图表中涉及多个不同的值轴时,到目前为止,这在XDDF中尚未完全实现.因此,我们需要使用低级ooxml-schemas-1.4类进行更正.

When it comes to multiple different value axes in one chart, this is not fully implemented in XDDF until now. So we need correcting something using the low level ooxml-schemas-1.4 classes.

所需知识:

原则上,应在第二个值轴上显示的序列在同一绘图区域的单独图表中.因此,应在第二个值轴上显示的序列也需要它自己的底轴.但是此底轴必须是不可见的.

In principle the series which shall be shown on second value axis are in a separate chart in the same plot area. So the series which shall be shown on second value axis needs it's own bottom axis too. But this bottom axis must be invisible.

两个轴(第二个底轴和新的右轴)必须正确地相互交叉.直到现在,此交叉apache poi都无法正确显示.所以我们必须在这里纠正.

Both the axes, the second bottom and the new right axis, must cross each other properly. This crossing apache poi does not properly until now. So we must correct here.

因为添加到图表中时,添加第二个折线图的apache poi代码对已知的折线图一无所知,它的ID再次从0开始.但这对于组合图表是错误的.因此,我们需要正确的ID和顺序.它不能再从0开始,因为在相同的绘图区域中已经有一个线系列.

Because while adding to the chart, the apache poi code which adds the second line chart does not knows something about the already present line chart, it's IDs starts with 0 again. But this is wrong for an combined chart. So we need correct the id and order. It must not start with 0 again because there is a line series already in same plot area.

完整的示例也可以复制给他人:

Complete example to be reproducible for others too:

import java.io.*;

import org.apache.poi.xwpf.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;

import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;

public class CreateWordXDDFChart {

 public static void main(String[] args) throws Exception {
  try (XWPFDocument document = new XWPFDocument()) {

   // create the data
   String[] categories = new String[]{"1","2","3","4","5","6","7","8","9"};
   Double[] values1 = new Double[]{1d,2d,3d,4d,5d,6d,7d,8d,9d};
   Double[] values2 = new Double[]{200d,300d,400d,500d,600d,700d,800d,900d,1000d};

   // create the chart
   XWPFChart chart = document.createChart(15*Units.EMU_PER_CENTIMETER, 10*Units.EMU_PER_CENTIMETER);

   // create data sources
   int numOfPoints = categories.length;
   String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
   String valuesDataRange1 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
   String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
   XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
   XDDFNumericalDataSource<Double> valuesData1 = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange1, 1);
   XDDFNumericalDataSource<Double> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);

   // first line chart
   XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
   XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
   leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
   XDDFChartData data = chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
   XDDFChartData.Series series = data.addSeries(categoriesData, valuesData1);
   chart.plot(data);

   solidLineSeries(data, 0, PresetColor.BLUE);

   // second line chart
   // bottom axis must be there but must not be visible
   bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
   bottomAxis.setVisible(false);

   XDDFValueAxis rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
   rightAxis.setCrosses(AxisCrosses.MAX);

   // set correct cross axis
   bottomAxis.crossAxis(rightAxis);
   rightAxis.crossAxis(bottomAxis);

   data = chart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
   series = data.addSeries(categoriesData, valuesData2);
   chart.plot(data);

   // correct the id and order, must not be 0 again because there is one line series already
   chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getIdx().setVal(1);
   chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getOrder().setVal(1);

   solidLineSeries(data, 0, PresetColor.RED);

   // Write the output to a file
   try (FileOutputStream fileOut = new FileOutputStream("CreateWordXDDFChart.docx")) {
    document.write(fileOut);
   }
  }
 }

 private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
  XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
  XDDFLineProperties line = new XDDFLineProperties();
  line.setFillProperties(fill);
  XDDFChartData.Series series = data.getSeries().get(index);
  XDDFShapeProperties properties = series.getShapeProperties();
  if (properties == null) {
   properties = new XDDFShapeProperties();
  }
  properties.setLineProperties(line);
  series.setShapeProperties(properties);
 }
}

这篇关于如何在POI 4.0.1的XDDFChart中添加带有SECOND AXIS的第二行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆