Как добавить вторую строку с ВТОРОЙ ОСЬ в XDDFChart в POI 4.0.1? - PullRequest
1 голос
/ 16 марта 2019

Я не могу добавить линию на второй оси (правая ось) на существующем графике.Есть ли способ сделать это с новой реализацией диаграмм в POI 4.0.0 / 1?

Желаемый результат будет выглядеть следующим образом (Простая диаграмма Excel с 2 осями): Simple excel chart with 2 axes.Данные, связанные с этой диаграммой в качестве примера:

Серия 1 / Axis1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

Серия 2 / Axis2= [200,300,400,500,600,700,800,900,1000]

Вот код, который я пытаюсь до сих пор в Java, он в основном реплицируется из LineChart.java пример

//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);

Запуск этого кода не приводит к ошибкам компиляции.Но я получаю ошибки при открытии документа «Проблема с его содержимым».

Полагаю, я неправильно добавляю 2-ю строку и 2-ю ось.

Есть ли способ сделать это?

Обновление w.Решение Решение Акселя ниже работает отлично.Дополнительная информация, которую нужно знать, это именно то, в чем заключалась проблема.

Я также хотел бы узнать порядок, в котором вы добавляете сюжет, надеюсь, это поможет другим

  1. Создать первымнабор осей
  2. Создание первой линии
  3. Создание первой линии
  4. Создание новой оси
  5. Создание 2-й линии
  6. Создание 2-й линии
  7. Обновление идентификаторов осей!

1 Ответ

1 голос
/ 16 марта 2019

Когда речь идет о нескольких разных осях значений на одном графике, это не полностью реализовано в XDDF до сих пор.Поэтому нам нужно что-то исправить, используя классы ooxml-schemas-1.4 низкого уровня.

Необходимые знания:

В принципе, серии, которые должны быть показаны на второй оси значений, находятся в отдельной диаграмме на том же графике.площадь.Таким образом, ряд, который должен быть показан на второй оси значений, также нуждается в собственной нижней оси.Но эта нижняя ось должна быть невидимой.

Обе оси, вторая нижняя и новая правая оси должны правильно пересекаться.Это пересечение apache poi не правильно до сих пор.Поэтому мы должны исправить здесь.

Поскольку при добавлении к диаграмме код apache poi, который добавляет вторую линейную диаграмму, ничего не знает о уже существующей линейной диаграмме, его идентификаторы начинаются с 0 снова.Но это неправильно для комбинированного графика.Поэтому нам нужно исправить идентификатор и порядок.Он не должен начинаться с 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);
 }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...