Change Data Range in Excel Line Chart using Apache POI

Pyro :

I am trying to see if it is possible to change the data range of a series in a line chart using Apache POI.

I am able to pull the series from the chart itself, but cannot find a method that allows me to change the data range.

XSSFWorkbook workbook = new XSSFWorkbook("C:\\Workbook.xlsx");
Sheet worksheet = workbook.getSheetAt(0);
XSSFDrawing drawing = (XSSFDrawing) worksheet.createDrawingPatriarch();
List<XSSFChart> charts = drawing.getCharts();
for (XSSFChart chart : charts) {
    String title = chart.getTitleText().toString();
    if (title.equals("Z-Acceleration")) {
        CTChart cc = chart.getCTChart();
        CTPlotArea plotArea = cc.getPlotArea();
        CTLineSer[] ccc = plotArea.getLineChartArray()[0].getSerArray();
        for (CTLineSer s : ccc) {
            System.out.println(s.xmlText());
        }
        System.out.println(ccc.length);
    }
}

I printed out the XML text to see if it was indeed able to pull the series from the chart correctly and was able to find its title and data range, but no way to change it.

Axel Richter :

OK, since this is a good question at all, let's have a concrete example of how to change data range in Excel line chart using apache poi.

Let's start with following sheet:

enter image description here

Then the following code:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.SpreadsheetVersion;

import org.openxmlformats.schemas.drawingml.x2006.chart.*;

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

import java.util.List;

class ExcelChangeChartDataSource {

 static XSSFChart getChartWithTitle(XSSFSheet sheet, String wantedTitle) {
  if (sheet == null || wantedTitle == null) return null;
  XSSFDrawing drawing = sheet.createDrawingPatriarch();
  List<XSSFChart> charts = drawing.getCharts();
  for (XSSFChart chart : charts) {
   String title = chart.getTitleText().toString();
   if (wantedTitle.equals(title)) return chart;
  }
  return null;
 }

 static void addMonthDataToChart(XSSFSheet sheet, XSSFChart chart, String month, Double[] seriesData) {
  CTChart ctChart = chart.getCTChart();
  CTPlotArea ctPlotArea = ctChart.getPlotArea();
  List<CTLineSer> ctLineSerList = ctPlotArea.getLineChartArray(0).getSerList();

  Row row;
  Cell cell;
  int ser = 0;
  for (CTLineSer ctLineSer : ctLineSerList) {

   CTAxDataSource cttAxDataSource = ctLineSer.getCat();
   CTStrRef ctStrRef = cttAxDataSource.getStrRef();

   AreaReference catReference = new AreaReference(ctStrRef.getF(), SpreadsheetVersion.EXCEL2007);
   CellReference firstCatCell = catReference.getFirstCell();
   CellReference lastCatCell = catReference.getLastCell();
   if (firstCatCell.getCol() == lastCatCell.getCol()) {
    int col = firstCatCell.getCol();
    int lastRow = lastCatCell.getRow();
    row = sheet.getRow(lastRow+1); if (row == null) row = sheet.createRow(lastRow+1);
    cell = row.getCell(col); if (cell == null) cell = row.createCell(col);
    cell.setCellValue(month);

    ctStrRef.setF(new AreaReference(
                  firstCatCell, 
                  new CellReference(lastCatCell.getSheetName(), lastRow+1, col, true, true), 
                  SpreadsheetVersion.EXCEL2007).formatAsString()
                 );

    CTNumDataSource ctNumDataSource = ctLineSer.getVal();
    CTNumRef ctNumRef = ctNumDataSource.getNumRef();

    AreaReference numReference = new AreaReference(ctNumRef.getF(), SpreadsheetVersion.EXCEL2007);
    CellReference firstNumCell = numReference.getFirstCell();
    CellReference lastNumCell = numReference.getLastCell();
    if (lastNumCell.getRow() == lastRow && firstNumCell.getCol() == lastNumCell.getCol()) {
     col = firstNumCell.getCol();
     row = sheet.getRow(lastRow+1); if (row == null) row = sheet.createRow(lastRow+1);
     cell = row.getCell(col); if (cell == null) cell = row.createCell(col);
     if (ser < seriesData.length) cell.setCellValue(seriesData[ser]);

     ctNumRef.setF(new AreaReference(
                   firstNumCell, 
                   new CellReference(lastNumCell.getSheetName(), lastRow+1, col, true, true), 
                   SpreadsheetVersion.EXCEL2007).formatAsString()
                  );
    }
   }
   ser++;
  }
 }

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

  XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("WorkbookWithChart.xlsx"));

  XSSFSheet sheet = workbook.getSheetAt(0);

  XSSFChart chart = getChartWithTitle(sheet, "Z-Acceleration"); 

  if (chart != null) {
   addMonthDataToChart(sheet, chart, "Apr", new Double[]{7d,3d,5d});
   addMonthDataToChart(sheet, chart, "Mai", new Double[]{2d,6d,8d});
   addMonthDataToChart(sheet, chart, "Jun", new Double[]{1d,9d,4d});
   addMonthDataToChart(sheet, chart, "Jul", new Double[]{5d,6d});
  }

  FileOutputStream out = new FileOutputStream("WorkbookWithChartNew.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();
 }
}

produces following result:

enter image description here

This code uses org.openxmlformats.schemas.drawingml.x2006.chart.* classes and can be used with apache poi 3.17 as well as with apache poi 4.1.0.

Unfortunately there is not any API documentation of org.openxmlformats.schemas.drawingml.x2006.chart.* public available. So if we need it, we need to download ooxml-schemas-1.3-sources.jar from central.maven.org/maven2/org/apache/poi/ooxml-schemas/1.3. Then unzip that. Then go to directory ooxml-schemas-1.3 and do javadoc -d javadoc -sourcepath ./ -subpackages org. After that we find the API docs in ooxml-schemas-1.3/javadoc. Start reading with overview-tree.html.

For apache poi 4.1.0 we need ooxml-schemas-1.4.

I have tried the same using the new XDDF stuff in apache poi 4.1.0 too. But at first the code is not really much less expensive and at second this has the disadvantage that XDDFChart.plot fails when some data in XDDFNumericalDataSource<Double> values are not present. Then we would must set those data points 0. But this is not the same as not present. So using the new XDDFstuff in this case is not really a progress. But nevertheless, here is the code, i have tried:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.SpreadsheetVersion;

import org.apache.poi.xddf.usermodel.chart.*;

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

import java.util.List;

class ExcelChangeChartDataSource {

 static XSSFChart getChartWithTitle(XSSFSheet sheet, String wantedTitle) {
  if (sheet == null || wantedTitle == null) return null;
  XSSFDrawing drawing = sheet.createDrawingPatriarch();
  List<XSSFChart> charts = drawing.getCharts();
  for (XSSFChart chart : charts) {
   String title = chart.getTitleText().toString();
   if (wantedTitle.equals(title)) return chart;
  }
  return null;
 }

 static void addMonthDataToChart(XSSFSheet sheet, XSSFChart chart, String month, Double[] seriesData) {
  Row row;
  Cell cell;

  List<XDDFChartData> chartDataList = chart.getChartSeries();
  XDDFChartData chartData = chartDataList.get(0);

  List<XDDFChartData.Series> seriesList = chartData.getSeries();
  int ser = 0;
  for (XDDFChartData.Series series : seriesList) {
   XDDFDataSource categoryData = series.getCategoryData();
   AreaReference catReference = new AreaReference(categoryData.getDataRangeReference(), SpreadsheetVersion.EXCEL2007);
   CellReference firstCatCell = catReference.getFirstCell();
   CellReference lastCatCell = catReference.getLastCell();
   if (firstCatCell.getCol() == lastCatCell.getCol()) {
    int col = firstCatCell.getCol();
    int lastRow = lastCatCell.getRow();
    row = sheet.getRow(lastRow+1); if (row == null) row = sheet.createRow(lastRow+1);
    cell = row.getCell(col); if (cell == null) cell = row.createCell(col);
    cell.setCellValue(month);

    XDDFDataSource<String> category = XDDFDataSourcesFactory.fromStringCellRange(
                                       sheet, 
                                       new CellRangeAddress(firstCatCell.getRow(), lastRow+1, col, col));

    XDDFNumericalDataSource valuesData = series.getValuesData();
    AreaReference numReference = new AreaReference(valuesData.getDataRangeReference(), SpreadsheetVersion.EXCEL2007);
    CellReference firstNumCell = numReference.getFirstCell();
    CellReference lastNumCell = numReference.getLastCell();
    if (lastNumCell.getRow() == lastRow && firstNumCell.getCol() == lastNumCell.getCol()) {
     col = firstNumCell.getCol();
     row = sheet.getRow(lastRow+1); if (row == null) row = sheet.createRow(lastRow+1);
     cell = row.getCell(col); if (cell == null) cell = row.createCell(col);
     if (ser < seriesData.length) cell.setCellValue(seriesData[ser]);
     else cell.setCellValue(0); // Here we need set 0 where it not should be needed.

     XDDFNumericalDataSource<Double> values = XDDFDataSourcesFactory.fromNumericCellRange(
                                               sheet, 
                                               new CellRangeAddress(firstNumCell.getRow(), lastRow+1, col, col));

     series.replaceData(category, values);
    }
   }
   ser++;
  }
  chart.plot(chartData);
 }

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

  XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("WorkbookWithChart.xlsx"));

  XSSFSheet sheet = workbook.getSheetAt(0);

  XSSFChart chart = getChartWithTitle(sheet, "Z-Acceleration"); 

  if (chart != null) {
   addMonthDataToChart(sheet, chart, "Apr", new Double[]{7d,3d,5d});
   addMonthDataToChart(sheet, chart, "Mai", new Double[]{2d,6d,8d});
   addMonthDataToChart(sheet, chart, "Jun", new Double[]{1d,9d,4d});
   addMonthDataToChart(sheet, chart, "Jul", new Double[]{5d,6d});
  }

  FileOutputStream out = new FileOutputStream("WorkbookWithChartNew.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();

 }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

line chart design in excel using Apache poi

Change colors of line chart Apache POI

Apache poi Excel line chart points

Create excel chart using Apache POI

Change data range in a chart using VBA

Create Bar Chart in Excel with Apache POI

Apache poi add label in excel chart

Inserting data from arraylist in chunks in excel file using apache poi

Read write data in excel using java and apache POI

selenium webdriver not writing data into excel sheet using apache poi

how to read & search excel data using Apache POI

How to create Excel data model relationships using Apache POI?

How to write column by column data in Excel using Apache POI?

Using Excel templates with Apache POI

Excel 2013 VBA change a chart object source using dynamic range

How to change the graphical attributes of a point in an Excel sunburst chart through Apache POI

java create a chart in a powerpoint using APACHE POI

How to set the text attributes of the individual data labels in an Excel Sunburst Chart through Apache POI?

Apache POI: change page format for Excel worksheet

Change Author in excel generated by Apache poi

Is it possible to create Pivot Chart with source data as Pivot Table using Apache POI?

Second Line in an Apache-POI chart with seperate axis

Apache POI - Cant get Line Chart Values to appear in the Secondary Axis

Apache POI. Setup data filters in Excel

getting data by column name apache poi excel

Merging cells in Excel using Apache POI

Need to test apache poi excel using mockito

Unable to read Excel using Apache POI

Delete an excel sheet using Apache POI