更新现有饼图apache poi ppt

问题描述 投票:0回答:1

我正在尝试更新具有自己的颜色和样式的现有饼图。然后我想更新饼图但保留饼图的格式和样式。目前我可以更新饼图,但丢失格式/样式并且无法更新第一个值。

enter image description here

为了填充我正在这样做:

    static void updatePieChart(XSLFChart chart, List<User> users) throws Exception {

        XSSFWorkbook workbook = chart.getWorkbook();
        XSSFSheet sheet = workbook.getSheetAt(0);
        users.stream()
                .forEach(value -> addMonthDataToChart(sheet, chart, user.getName(), user.getSavings()));
    }
    
    static void addDataToChart(XSSFSheet sheet, XSLFChart chart, String month, Double value) {
        Row row;
        Cell cell;

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

        List<XDDFChartData.Series> seriesList = chartData.getSeries();
        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);

                    cell.setCellValue(value);

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

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

这就是我得到的结果 enter image description here 正如您所看到的,图例和饼图的切片是不同的(第一个行与添加的其他行),工作表中的行也丢失了第一个行的格式,甚至第一行也没有被删除/更新,以便仅显示自“凯特行”以来。

我真的很感激一些帮助。谢谢。

java apache-poi backend
1个回答
0
投票

您的代码遇到以下问题:

首先,您应该并行而不是单独更新

XDDF
(图表图)和
XSSF
(数据表源)的图表数据。正如您所看到的,单独的更新可能会导致失去同步性。

我已经在 PPT 中的 Java 编辑条形图中展示了这一点,已经使用 poi 作为条形图。

其次,如果您想保留可能的单元格样式,例如货币数字样式,那么您也需要对其进行编码。当您创建新单元格时,它不会自动保留。

以下完整示例采用我的条形图示例来更新饼图。

模板

PieChartSample.pptx

代码:

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.ss.util.AreaReference;

public class PowerPointChangeChartDataPieChart  {

 static void updateChart(XSLFChart chart, Object[][] data) throws Exception {
  // get chart's data source which is a Excel sheet
  XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
  String sheetName = chartDataWorkbook.getSheetName(0);
  XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);
  // current Office uses a table as data source
  // so get that table if present
  XSSFTable chartDataTable = null;
  if (chartDataSheet.getTables().size() > 0) {
   chartDataTable = chartDataSheet.getTables().get(0);
  }

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

    int rMin = 1; // first row (0) is headers row
    int rMax = data.length - 1;

    // set new category data
    XDDFCategoryDataSource category = null;
    int c = 0;
    for (int r = rMin; r <= rMax; 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, is present already and a pie chart only has one series
    c = 1;

    // set new values in sheet and in chart
    XDDFNumericalDataSource<Double> values = null;
    // to remain possible cell styles
    XSSFCellStyle cellStyle = 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
     // remain possible cell styles
     if (cellStyle == null) cellStyle = cell.getCellStyle();
     cell.setCellStyle(cellStyle);
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    XDDFChartData.Series series1 = chartData.getSeries(0);
    series1.replaceData(category, values); // in chart

    // set new title in sheet and in chart
    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

    series1.plot(); 

    //no further series as a pie chart only has one series
    
    // update the table if present
    if (chartDataTable != null) {
     CellReference topLeft = new CellReference(chartDataSheet.getRow(0).getCell(0));
     CellReference bottomRight = new CellReference(chartDataSheet.getRow(rMax).getCell(c));
     AreaReference tableArea = chartDataWorkbook.getCreationHelper().createAreaReference(topLeft, bottomRight);
     chartDataTable.setArea(tableArea);
     chartDataTable.updateHeaders();
    }

   }
  }
 }  

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

  String filePath = "./PieChartSample.pptx"; // has template pie chart
  String filePathNew = "./PieChartSample_New.pptx";

  Object[][] data = new Object[][] { // new data 1 series, 6 categories
   {"User", "Savings"}, // series title
   {"Kate", 200d}, // category 1
   {"Michael", 500d}, // category 2
   {"Charles", 452.54d}, // category 3
   {"Franklin", 864.1d}, // category 4
   {"Dina", 422.9d}, // category 5
   {"Peter", 7458.4} // category 6
  };

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

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

  updateChart(chart, data);

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

}

结果

PieChartSample_New.pptx
:

© www.soinside.com 2019 - 2024. All rights reserved.