【问题标题】:Second Line in an Apache-POI chart with seperate axisApache-POI 图表中的第二行,带有单独的轴
【发布时间】:2020-08-04 20:55:48
【问题描述】:

嗨,这个取自答案 here 的代码按预期工作,但我想要完全相同的图表,但在 Excel 表中

package eu.flexsolution.task.excel;

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 TEst {

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

所以我修改了这样的代码以获取 XLSX 文档,但图表不一样

package eu.flexsolution.task.excel;


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.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class TEst {


public static void main(String[] args) throws Exception {
    try (XSSFWorkbook document = new XSSFWorkbook()) {
        XSSFSheet chartSheet = document.createSheet("chart");
        
        // 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
        XSSFDrawing drawing = chartSheet.createDrawingPatriarch();
        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 26, 40);
        XDDFChart chart = drawing.createChart(anchor);
        
        // 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.xlsx")) {
            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);
}
}

【问题讨论】:

    标签: java charts apache-poi


    【解决方案1】:

    问题在于,对于Word (XWPF) 图表,数据存储在嵌入在Word 文件中的Excel 工作簿中。在那里,数据可以作为数组给出并通过XDDFDataSourcesFactory.fromArray 处理。然后填充嵌入的Excel 数据表。

    但对于Excel(XSSF) 图表,数据需要在Excel 数据表中。当然Excel 不会在其文件中嵌入Excel 工作表,因为它已经有工作表。因此对于Excel,数据需要在工作表中,然后需要通过XDDFDataSourcesFactory.fromStringCellRangeXDDFDataSourcesFactory.fromNumericCellRange 处理。

    创建ExcelXSSFChart的完整示例:

    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.*;
    import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
    import org.apache.poi.xssf.usermodel.XSSFDrawing;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    
    public class CreateExcelXDDFChart {
    
     public static void main(String[] args) throws Exception {
      try (XSSFWorkbook document = new XSSFWorkbook()) {
       XSSFSheet chartSheet = document.createSheet("chart");
       XSSFSheet dataSheet = document.createSheet("data");
            
       // create the data
       String[] categories = new String[] { "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9" };
       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 };
       int r = 0;
       for (String cat : categories) {
        dataSheet.createRow(r).createCell(0).setCellValue(cat);
        dataSheet.getRow(r).createCell(1).setCellValue(values1[r]);
        dataSheet.getRow(r).createCell(2).setCellValue(values2[r]);
        r++;
       }
            
       // create the chart
       XSSFDrawing drawing = chartSheet.createDrawingPatriarch();
       XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 26, 40);
       XDDFChart chart = drawing.createChart(anchor);
            
       // create data sources
       int numOfPoints = categories.length;
       XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromStringCellRange(dataSheet, new CellRangeAddress(0, numOfPoints-1, 0, 0));
       XDDFNumericalDataSource<Double> valuesData1 = XDDFDataSourcesFactory.fromNumericCellRange(dataSheet, new CellRangeAddress(0, numOfPoints-1, 1, 1));
       XDDFNumericalDataSource<Double> valuesData2 = XDDFDataSourcesFactory.fromNumericCellRange(dataSheet, new CellRangeAddress(0, numOfPoints-1, 2, 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("CreateExcelXDDFChart.xlsx")) {
        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);
      XDDFChartData.Series series = data.getSeries(index);
      XDDFShapeProperties properties = series.getShapeProperties();
      if (properties == null) {
       properties = new XDDFShapeProperties();
      }
      properties.setLineProperties(line);
      series.setShapeProperties(properties);
     }
    }
    

    使用当前的apache poi 4.1.2 工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多