Как создать LineChart, который содержит две CategoryAxis, используя Apache POI? - PullRequest
1 голос
/ 11 мая 2019

Я пытаюсь создать Excel LineChart для сравнения обеих зависимостей с разным количеством узловых точек (как на скриншоте). Я пытался просто добавить дополнительную ось к графику, но этот способ не дает результата. Как можно решить проблему?

это должно выглядеть так: it should look like this

ChartLegend legend2 = chart2.getOrCreateLegend();
legend2.setPosition(LegendPosition.RIGHT);
LineChartData data2 = chart2.getChartDataFactory().createLineChartData();
ChartAxis bottomAxis = chart2.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
ChartAxis topAxis = chart2.getChartAxisFactory().createCategoryAxis(AxisPosition.TOP);
ValueAxis leftAxis = chart2.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
ChartDataSource<String> xs = DataSources.fromStringCellRange(sheet, new CellRangeAddress(1, 350, 4, 4));
ChartDataSource<String> xs1 = DataSources.fromStringCellRange(sheet, new CellRangeAddress(1, 10, 7, 7));
ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(1, 350, 5, 5));
ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(sheet, new CellRangeAddress(1, 10, 8, 8));
LineChartSeries series1 = data2.addSeries(xs, ys1);
series1.setTitle("1");
LineChartSeries series2 = data2.addSeries(xs1, ys2);
series2.setTitle("2");
chart2.plot(data2, topAxis, bottomAxis, leftAxis);

XSSFChart xssfChart = (XSSFChart) chart2;
CTPlotArea plotArea = xssfChart.getCTChart().getPlotArea();
plotArea.getLineChartArray()[0].getSmooth();
CTBoolean ctBool = CTBoolean.Factory.newInstance();
ctBool.setVal(false);
plotArea.getLineChartArray()[0].setSmooth(ctBool);
for (CTLineSer ser : plotArea.getLineChartArray()[0].getSerArray()) {
    ser.setSmooth(ctBool);
}
CTMarker ctMarker = CTMarker.Factory.newInstance();
ctMarker.setSymbol(CTMarkerStyle.Factory.newInstance());
for (CTLineSer ser : plotArea.getLineChartArray()[0].getSerArray()) {
    ser.setMarker(ctMarker);

1 Ответ

1 голос
/ 11 мая 2019

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

В вашем коде используются старые apache poi классы, которые устарели и будут удалены в следующей версии.Вот полный пример использования текущей apache poi версии 4.1.0.

import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;

public class XSSFLineChartTwoCatAxes {

 public static void main(String[] args) throws IOException {
  try (XSSFWorkbook wb = new XSSFWorkbook()) {
   XSSFSheet sheet = wb.createSheet("linechart");

   // create data
   Row row;
   Cell cell;
   for (int rowIndex = 0; rowIndex < 4; rowIndex++) {
    row = sheet.createRow((short) rowIndex);
    if (rowIndex == 0) {
     cell = row.createCell(0);
     cell.setCellValue("CatA");
     for (int colIndex = 1; colIndex < 32; colIndex++) {
      cell = row.createCell((short) colIndex);
      cell.setCellValue(colIndex + (colIndex-1)*11);
     }
    } else if (rowIndex == 1) {
     cell = row.createCell(0);
     cell.setCellValue("ValA");
     for (int colIndex = 1; colIndex < 32; colIndex++) {
      cell = row.createCell((short) colIndex);
      cell.setCellValue(new java.util.Random().nextDouble() * 8 + 1);
     }
    } else if (rowIndex == 2) {
     cell = row.createCell(0);
     cell.setCellValue("CatB");
     for (int colIndex = 1; colIndex < 14; colIndex++) {
      cell = row.createCell((short) colIndex);
      cell.setCellValue(colIndex);
     }
    } else if (rowIndex == 3) {
     cell = row.createCell(0);
     cell.setCellValue("ValB");
     for (int colIndex = 1; colIndex < 14; colIndex++) {
      cell = row.createCell((short) colIndex);
      cell.setCellValue(new java.util.Random().nextDouble() * 8 + 1);
     }
    }
   }

   // creata anchor
   XSSFDrawing drawing = sheet.createDrawingPatriarch();
   XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 15, 25);

   // create chart
   XSSFChart chart = drawing.createChart(anchor);

   // create data sources
   XDDFDataSource<Double> cat1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 1, 31));
   XDDFNumericalDataSource<Double> val1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 1, 31));
   XDDFDataSource<Double> cat2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 1, 13));
   XDDFNumericalDataSource<Double> val2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(3, 3, 1, 13));

   // first line chart

   // create axis
   XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
   XDDFValueAxis rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
   rightAxis.setCrosses(AxisCrosses.MAX);

   // create data and series
   XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
   XDDFLineChartData.Series series = (XDDFLineChartData.Series) data.addSeries(cat1, val1);
   series.setTitle("CatA", new CellReference(sheet.getSheetName(), 0, 0, true, true));
   series.setSmooth(false);
   series.setMarkerStyle(MarkerStyle.NONE);

   chart.plot(data);

   solidLineSeries(data, 0, PresetColor.BLUE);

   // second line chart

   // create axis
   XDDFCategoryAxis topAxis = chart.createCategoryAxis(AxisPosition.TOP);
   topAxis.setCrosses(AxisCrosses.MAX);
   rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
   rightAxis.setVisible(false); // right axis must be there but can be invisible
   rightAxis.setCrosses(AxisCrosses.MAX);

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

   // create data and series
   data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, topAxis, rightAxis);
   series = (XDDFLineChartData.Series) data.addSeries(cat2, val2);
   series.setTitle("CatB", new CellReference(sheet.getSheetName(), 2, 0, true, true));
   series.setSmooth(false);
   series.setMarkerStyle(MarkerStyle.NONE);

   chart.plot(data);

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

   solidLineSeries(data, 0, PresetColor.GREEN);

   // create legend
   XDDFChartLegend legend = chart.getOrAddLegend();
   legend.setPosition(LegendPosition.BOTTOM);
   legend.setOverlay(false);

   // Write the output to a file
   try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
    wb.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, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...