简体   繁体   中英

I'm trying to change the values of a line graph in a slide but it is not working using POI

I'm using Apache POI 4.01 and trying to use a powerpoint slide with a single line chart as template and then using that to generate a new slide with some different values in the chart but I'm getting the same slide copied without any value change. Kindly help.

I'm trying the below code using a simple line chart in a powerpoint slide.

public static void main(String[] args) throws IOException {
        // creating presentation
        XMLSlideShow ppt = new XMLSlideShow();

        File file1 = new File("MyDrive://LineSample.pptx");
        FileInputStream inputstream;
        try {
            inputstream = new FileInputStream(file1);

            XMLSlideShow template = new XMLSlideShow(inputstream);
            XMLSlideShow testReport = new XMLSlideShow();
            XSLFSlide xslfSlide = template.getSlides().get(0);

            // TODO Auto-generated method stub

            // adding slides to the slideshow

            XSLFSlide slide1 = testReport.createSlide();

            XSLFSlideLayout src_sl = xslfSlide.getSlideLayout();
            XSLFSlideMaster src_sm = xslfSlide.getSlideMaster();

            XSLFSlideLayout new_sl = slide1.getSlideLayout();
            XSLFSlideMaster new_sm = slide1.getSlideMaster();

            // copy source layout to the new layout
            new_sl.importContent(src_sl);
            // copy source master to the new master
            new_sm.importContent(src_sm);

            slide1.importContent(xslfSlide);
            XSLFSlide slide = xslfSlide;

            // find chart in the slide
            XSLFChart chart = null;
            for (POIXMLDocumentPart part : slide.getRelations()) {
                if (part instanceof XSLFChart) {
                    chart = (XSLFChart) part;
                    break;

                }
            }

            if (chart == null) {
                throw new IllegalStateException("chart not found in the template");
            } else {
                System.out.println("Chart Found");
            }
            // Series Text
            List<XDDFChartData> series = chart.getChartSeries();
            XDDFLineChartData linechart = (XDDFLineChartData) series.get(0);

            // Category
            List<String> listCategories = new ArrayList<>(3);
            listCategories.add("Test1");
            listCategories.add("Test2");
            listCategories.add("Test3");
            // Values
            List<Double> listValues = new ArrayList<>(3);
            listValues.add(10.00);
            listValues.add(20.00);
            listValues.add(30.00);

            String[] categories = listCategories.toArray(new String[listCategories.size()]);
            Double[] values = listValues.toArray(new Double[listValues.size()]);

            final int numOfPoints = categories.length;
            final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
            final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
            final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange);
            final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values,
                    valuesDataRange);

            XDDFLineChartData.Series firstSeries = (XDDFLineChartData.Series) linechart.getSeries().get(0);
            firstSeries.replaceData(categoriesData, valuesData);
            // firstSeries.setTitle("chartTitle",
            // chart.setSheetTitle("chartTitle", 0));
            firstSeries.setMarkerSize((short) 70);
            firstSeries.setMarkerStyle(MarkerStyle.DASH);
            firstSeries.setShowLeaderLines(true);
            firstSeries.setSmooth(true);
            // firstSeries.setShapeProperties(XDDFShapeProperties);

            chart.plot(linechart);

            FileOutputStream out = new FileOutputStream("MyDrive");
            testReport.write(out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

No errors but chart values remain the same, actual result needed is a line chart with different values.

Main problem is that the data source of a PowerPoint chart is a embedded Excel worksheet. And this worksheet needs changed too additional to the cached data in the chart. That means we need get the chart's data source which is a Excel sheet. And then we need set all new category data, new series titles and new data values always in that sheet as well as in the chart.

Complete example:

Lets start with that LineSample.pptx template:

在此输入图像描述

Code:

import java.io.FileInputStream;
import java.io.FileOutputStream;

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

import org.apache.poi.ooxml.POIXMLDocumentPart;

public class PowerPointCopySlideChangeChartData {

 public static void main(String[] args) throws Exception {

  String filePath = "LineSample.pptx"; // has template line chart
  String filePathNew = "LineSample_New.pptx";

  Object[][] data = new Object[][] { // new data 1 series, 4 categories
   {"", "Amount"}, // series title
   {"Jan", 123d}, // category 1
   {"Feb", 345d}, // category 2
   {"Mar", 180d}, // category 3
   {"Apr", 180d} // category 4
  };

  XMLSlideShow slideShowTemplate = new XMLSlideShow(new FileInputStream(filePath));
  XSLFSlide slideTemplate = slideShowTemplate.getSlides().get(0);
  XSLFSlideLayout slideLayoutTemplate = slideTemplate.getSlideLayout();
  XSLFSlideMaster slideMasterTemplate = slideTemplate.getSlideMaster();

  XMLSlideShow slideShowNew = new XMLSlideShow();
  XSLFSlide slideNew = slideShowNew.createSlide();
  XSLFSlideLayout slideLayoutNew = slideNew.getSlideLayout();
  XSLFSlideMaster slideMasterNew = slideNew.getSlideMaster();

  slideLayoutNew.importContent(slideLayoutTemplate);
  slideMasterNew.importContent(slideMasterTemplate);

  slideNew.importContent(slideTemplate);

  slideShowTemplate.close();

  XSLFChart chart = null;
  for (POIXMLDocumentPart part : slideNew.getRelations()) {
   if (part instanceof XSLFChart) {
    chart = (XSLFChart) part;
    break;
   }
  }
  if (chart == null) {
   throw new Exception("chart not found in the template");
  } else {
   System.out.println("Chart Found");
  }

  XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
  String sheetName = chartDataWorkbook.getSheetName(0);
  XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);

  if (chart.getChartSeries().size() == 1) { // we will process only one chart data
   XDDFChartData chartData = chart.getChartSeries().get(0);
   if (chartData.getSeries().size() == 1) { // we will process exact one series

    int rMin = 1;
    int rMax = data.length - 1;

    // set new category data
    XDDFCategoryDataSource category = null;
    int c = 0;
    for (int r = rMin; r < rMax+1; r++) {
     XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
     XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
     cell.setCellValue((String)data[r][c]); // in sheet
    }
    category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart

    // series 1
    XDDFChartData.Series series1 = chartData.getSeries().get(0);
    c = 1;
    // set new title
    String series1Title = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
    series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart

    // set new values
    XDDFNumericalDataSource<Double> values = null;
    for (int r = rMin; r < rMax+1; r++) {
     XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
     XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
     cell.setCellValue((Double)data[r][c]); // in sheet
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    series1.replaceData(category, values);
    series1.plot(); //in chart

    series1.setShowLeaderLines(true);
    if (series1 instanceof XDDFLineChartData.Series) {
     ((XDDFLineChartData.Series)series1).setMarkerSize((short) 70);
     ((XDDFLineChartData.Series)series1).setMarkerStyle(MarkerStyle.DASH);
     ((XDDFLineChartData.Series)series1).setSmooth(true);
    }
   }
  }

  FileOutputStream out = new FileOutputStream(filePathNew); 
  slideShowNew.write(out);
  out.close();
  slideShowNew.close();
 }

}

Result:

在此输入图像描述

The question is whether the copying of the slide from the template to a new created slide show is really necessary since this leads to formatting issues as you see. In my opinion simply opening the whole template, changing the needed things and then saving that changed template as a new file will be better.

Start with same template.

Code:

import java.io.FileInputStream;
import java.io.FileOutputStream;

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

public class PowerPointChangeChartData {

 public static void main(String[] args) throws Exception {

  String filePath = "LineSample.pptx"; // has template line chart
  String filePathNew = "LineSample_New.pptx";

  Object[][] data = new Object[][] { // new data 1 series, 4 categories
   {"", "Amount"}, // series title
   {"Jan", 123d}, // category 1
   {"Feb", 345d}, // category 2
   {"Mar", 180d}, // category 3
   {"Apr", 180d} // category 4
  };

  XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream(filePath));

  XSLFChart chart = slideShow.getCharts().get(0);

  // get chart's data source which is a Excel sheet
  XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
  String sheetName = chartDataWorkbook.getSheetName(0);
  XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);

  if (chart.getChartSeries().size() == 1) { // we will process only one chart data
   XDDFChartData chartData = chart.getChartSeries().get(0);
   if (chartData.getSeries().size() == 1) { // we will process exact one series

    int rMin = 1;
    int rMax = data.length - 1;

    // set new category data
    XDDFCategoryDataSource category = null;
    int c = 0;
    for (int r = rMin; r < rMax+1; r++) {
     XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
     XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
     cell.setCellValue((String)data[r][c]); // in sheet
    }
    category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart

    // series 1
    XDDFChartData.Series series1 = chartData.getSeries().get(0);
    c = 1;
    // set new title
    String series1Title = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
    series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart

    // set new values
    XDDFNumericalDataSource<Double> values = null;
    for (int r = rMin; r < rMax+1; r++) {
     XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
     XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
     cell.setCellValue((Double)data[r][c]); // in sheet
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    series1.replaceData(category, values);
    series1.plot(); //in chart

    series1.setShowLeaderLines(true);
    if (series1 instanceof XDDFLineChartData.Series) {
     ((XDDFLineChartData.Series)series1).setMarkerSize((short) 70);
     ((XDDFLineChartData.Series)series1).setMarkerStyle(MarkerStyle.DASH);
     ((XDDFLineChartData.Series)series1).setSmooth(true);
    }

   }
  }

  FileOutputStream out = new FileOutputStream(filePathNew); 
  slideShow.write(out);
  out.close();
  slideShow.close();
 }

}

Result:

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM