Java 如何在POI 4.0.1中向XDDFChart添加第二条带有第二个轴的线?

Java 如何在POI 4.0.1中向XDDFChart添加第二条带有第二个轴的线?,java,apache,charts,apache-poi,Java,Apache,Charts,Apache Poi,我无法在现有图表的第二个轴(右轴)上添加线条。POI 4.0.0/1中图表的新实现是否有办法做到这一点 所需的输出如下所示(带有两个轴的简单excel图表): . 以该图表的关联数据为例: 系列1/Axis1=[1,2,3,4,5,6,7,8,9] 系列2/Axis2=[2003004005006007008009001000] 这是我目前正在Java中尝试的代码,它大部分是从LineChart.Java复制的 //初始代码实例化文档 XWPFDocument doc=新XWPFDocument

我无法在现有图表的第二个轴(右轴)上添加线条。POI 4.0.0/1中图表的新实现是否有办法做到这一点

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

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

系列2/Axis2=[2003004005006007008009001000]

这是我目前正在Java中尝试的代码,它大部分是从LineChart.Java复制的

//初始代码实例化文档
XWPFDocument doc=新XWPFDocument();
...
//生成图表
//这是从示例中提取的https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java
XWPFChart prChart=doc.createChart();
//左轴上的值为1
//右轴上的值为2
String[]categories=dates.toArray(新字符串[dates.size()]);
BigDecimal[]values1=prices1.toArray(新的BigDecimal[prices1.size()]);
BigDecimal[]values2=prices2.toArray(新的BigDecimal[prices2.size()]);
XDDFChartAxis bottomAxis=prChart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setMajorTickMark(AxisTickMark.NONE);
XDDFValueAxis leftAxis=prChart.createValueAxis(AxisPosition.LEFT);
leftAxis.setcrosss(axiscrosss.AUTO_ZERO);
leftAxis.setMajorTickMark(AxisTickMark.OUT);
/*
*这个做得对吗?
*/
XDDFValueAxis rightAxis=prChart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosss(axisCrosss.MAX);
rightAxis.setMajorTickMark(AxisTickMark.IN);
最终整数=categories.length;
最终字符串categoryDataRange=prChart.formatRange(新的CellRangeAddress(1,numOfPoints,0,0));
最终字符串值datarange=prChart.formatRange(新的CellRangeAddress(1,numOfPoints,1,1));
最终字符串值daTarange2=prChart.formatRange(新的CellRangeAddress(1,numOfPoints,2,2));
最终XDDFDataSource categoriesData=XDDFDataSourcesFactory.fromArray(categories,CategorityDataRange,0);

最终XDDFNumericalDataSource当涉及到一个图表中的多个不同值轴时,这在
XDDF
中尚未完全实现。因此,我们需要使用低级的
ooxml-schemas-1.4
类来纠正一些问题

所需知识:

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

两个轴(第二个底部轴和新的右轴)必须正确地相互交叉。到目前为止,此交叉
apache poi
还不能正常进行。所以我们必须在这里纠正

因为当添加到图表中时,添加第二个折线图的
apache poi
代码并不了解已经存在的折线图,它的id再次以0开始。但这对于组合图表来说是错误的。所以我们需要更正id和顺序。它不能再次以0开头,因为同一绘图区域中已存在一个直线系列

其他人也可复制完整示例:

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);
 }
}
import java.io.*;
导入org.apache.poi.xwpf.usermodel.*;
导入org.apache.poi.ss.util.CellRangeAddress;
导入org.apache.poi.util.Units;
导入org.apache.poi.xddf.usermodel.*;
导入org.apache.poi.xddf.usermodel.chart.*;
公共类CreateWordXDDFChart{
公共静态void main(字符串[]args)引发异常{
try(XWPFDocument document=newxwpfdocument()){
//创建数据
字符串[]类别=新字符串[]{“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”};
Double[]值1=新的Double[]{1d、2d、3d、4d、5d、6d、7d、8d、9d};
双[]值2=新的双[]值{200d、300d、400d、500d、600d、700d、800d、900d、1000d};
//创建图表
XWPFChart chart=document.createChart(每厘米15*Units.EMU,每厘米10*Units.EMU);
//创建数据源
int numOfPoints=categories.length;
String categoryDataRange=chart.formatRange(新的CellRangeAddress(1,numOfPoints,0,0));
String valuesDataRange1=chart.formatRange(新的CellRangeAddress(1,numOfPoints,1,1));
String valuesDataRange2=chart.formatRange(新的CellRangeAddress(1,numOfPoints,2,2));
XDDFDataSource categoriesData=XDDFDataSourcesFactory.fromArray(categories,CategorityDataRange,0);
XDDFNumericalDataSource valuesData1=XDDFDataSourcesFactory.fromArray(值1,值sDataRange1,1);
XDDFNumericalDataSource valuesData2=XDDFDataSourcesFactory.fromArray(values2,valuesDataRange2,2);
//第一折线图
XDDFCategoryAxis bottomAxis=chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis=chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setcrosss(axiscrosss.AUTO_ZERO);
XDDFChartData data=chart.createData(ChartTypes.LINE、bottomAxis、leftAxis);
XDDFChartData.Series系列=data.addSeries(categoriesData,valuesData1);
图表、绘图(数据);
solidLineSeries(数据,0,预设颜色。蓝色);
//第二折线图
//底部轴必须在那里,但不能可见
bottomAxis=chart.createCategoryAxis(AxisPosition.BOTTOM);
底部轴设置可见(假);
XDDFValueAxis rightAxis=chart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosss(axisCrosss.MAX);
//设置正确的横轴
下轴。横轴(右轴);
右轴。横轴(下轴);
数据=chart.createData(ChartTypes.LINE、bottomAxis、rightAxis);
series=data.addSeries(categoriesData,valuesData2);
图表、绘图(数据);
//请更正id和顺序,不能再次为0,因为已经有一个行序列
chart.getCTChart().getPlotArea().getLineChartArray(1.GetSerray(0.getIdx().setVal(1);
chart.getCTChart().getPlotArea().getLineChartArray(1.GetSerray(0.getOrder().setVal(1);
solidLineSeries(数据,0,预设颜色,红色);
//将输出写入文件
try(FileOutputStream fileOut=newfileoutputst
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);
 }
}