当前位置: 首页 > 知识库问答 >
问题:

如何更新pptx散点图的ext列表值

姬浩渺
2023-03-14

关联的excel数据

xVal和yVal可以成功替换,但如何替换C列(extList)?

xVal和yVal替换为以下方式

final CTScatterSer ser = serList.get(0);
final CTAxDataSource xVal = ser.getXVal();
final CTNumDataSource yVal = ser.getYVal();
final CTExtension ctExtension = ser.getExtLst().getExtList().get(0);
final long ptCount = xVal.getNumRef().getNumCache().getPtCount().getVal();
for (int i = 0; i < scData.size(); i++) {
    SCNameDouble data = scData.get(i);

    CTNumVal xNumVal = ptCount > i ? xVal.getNumRef().getNumCache().getPtArray(i)
            : xVal.getNumRef().getNumCache().addNewPt();
    xNumVal.setIdx(i);
    xNumVal.setV(String.format("%.2f", data.xValue));

    CTNumVal yNumVal = ptCount > i ? yVal.getNumRef().getNumCache().getPtArray(i)
            : yVal.getNumRef().getNumCache().addNewPt();
    yNumVal.setIdx(i);
    yNumVal.setV(String.format("%.2f", data.yValue));

}

final int newSize = scData.size();
xVal.getNumRef().setF(
        replaceRowEnd(xVal.getNumRef().getF(),
                ptCount,
                newSize));
yVal.getNumRef().setF(
        replaceRowEnd(yVal.getNumRef().getF(),
                ptCount,
                newSize));

xVal.getNumRef().getNumCache().getPtCount().setVal(newSize);
yVal.getNumRef().getNumCache().getPtCount().setVal(newSize);

共有1个答案

越学文
2023-03-14

使用当前的apache poi版本,人们不应该尝试使用低级别的CT来操作图表 类。对于这种情况,现在有XDDF。

如果涉及PowerPoint图表,则需要始终更新嵌入工作簿中的数据并更新图表中的数据。有关使用条形图的示例,请参阅ppt中的Java edit bar chart by using poi。

当然散点图是另一种情况,因为它没有类别轴,但有两个值轴。但这也可以使用XDDF更新。

最大的问题是数据标签。到目前为止,XDDF中还不完全支持图表数据标签。由于您正在谈论extLst,并且您的Excel表显示了单元格范围内的数据标签,我怀疑您设置了来自单元格范围的数据标签。这是Microsoft发布Office Open XML时没有的一项新功能。因此,即使是低水平的CT 类能够支持该功能。

唯一的方法是使用基于组织的纯XML操作来操作XML。阿帕奇。xmlbeans。XmlObject。

下面在一个模板示例上显示了这一点,您似乎根据您的问题使用了该模板。

ScatterChartSample。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.usermodel.DataFormatter;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.AreaReference;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;

public class PowerPointChangeScatterChartData {

 //patched version of XSSFTable.updateHeaders, see https://stackoverflow.com/questions/55532006/renaming-headers-of-xssftable-with-apache-poi-leads-to-corrupt-xlsx-file/55539181#55539181
 static void updateHeaders(XSSFTable table) {
  XSSFSheet sheet = (XSSFSheet)table.getParent();
  CellReference ref = table.getStartCellReference();

  if (ref == null) return;

  int headerRow = ref.getRow();
  int firstHeaderColumn = ref.getCol();
  XSSFRow row = sheet.getRow(headerRow);
  DataFormatter formatter = new DataFormatter();

  if (row != null /*&& row.getCTRow().validate()*/) {
   int cellnum = firstHeaderColumn;
   CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
   if(ctTableColumns != null) {
    for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
     XSSFCell cell = row.getCell(cellnum);
     if (cell != null) {
      col.setName(formatter.formatCellValue(cell));
     }
     cellnum++;
    }
   }
  }
 }

 static void updateScatterChart(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;

    // column 0 is X-Values
    int c = 0;
    // set new x data
    XDDFDataSource xs = null;
    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((Double)data[r][c]); // in sheet
    }
    xs = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart
    
    // set new x-title in sheet
    String xTitle = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(xTitle); // in sheet

    // column 1 is Y-Values 
    c = 1;
    // set new y data in sheet and in chart
    XDDFNumericalDataSource<Double> ys = null;
    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((Double)data[r][c]); // in sheet
    }
    ys = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    XDDFChartData.Series series1 = chartData.getSeries(0);
    series1.replaceData(xs, ys); // in chart

    // set new y-title in sheet and in chart
    String yTitle = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(yTitle); // in sheet
    series1.setTitle(yTitle, new CellReference(sheetName, 0, c, true, true)); // in chart

    series1.plot(); 
    
    // column 2 is data-labels-range
    c = 2;
    // set new data labels data in sheet and in chart
    XDDFDataSource dataLabelsRangeSource = null;
    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
    }
    dataLabelsRangeSource = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart
    updateDataLabelsRange(chart, dataLabelsRangeSource); // in chart

    // set new data-labels-title in sheet
    String descrTitle = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(descrTitle); // in sheet
    
    // 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);
     updateHeaders(chartDataTable);
    }

   }
  }
 }  
 
 static void updateDataLabelsRange(XDDFChart chart, XDDFDataSource dataLabelsRangeSource) {
  String declareNameSpaces = "declare namespace c='http://schemas.openxmlformats.org/drawingml/2006/chart'; " 
                           + "declare namespace c15='http://schemas.microsoft.com/office/drawing/2012/chart' ";
  org.apache.xmlbeans.XmlObject[] selectedObjects = chart.getCTChart().selectPath(
   declareNameSpaces 
   + ".//c:ext[c15:datalabelsRange]"); // needs net.sf.saxon - Saxon-HE (Saxon-HE-10.6.jar)
 
  if (selectedObjects.length > 0) { // we have at least one ext containing datalabelsRange
   org.apache.xmlbeans.XmlObject ext = selectedObjects[0]; // get first ext containing datalabelsRange
   // get dataLabelsRange
   org.apache.xmlbeans.XmlObject[] datalabelsRanges = ext.selectChildren(new javax.xml.namespace.QName("http://schemas.microsoft.com/office/drawing/2012/chart", "datalabelsRange", "c15"));
   org.apache.xmlbeans.XmlObject dataLabelsRange = datalabelsRanges[0];
   // set formula
   org.apache.xmlbeans.XmlObject[] formulas = dataLabelsRange.selectChildren(new javax.xml.namespace.QName("http://schemas.microsoft.com/office/drawing/2012/chart", "f", "c15"));
   org.apache.xmlbeans.XmlObject formula = formulas[0];
   ((org.apache.xmlbeans.impl.values.XmlObjectBase)formula).setStringValue(dataLabelsRangeSource.getFormula());
   // get dlblRangeCache
   org.apache.xmlbeans.XmlObject[] dlblRangeCaches = dataLabelsRange.selectChildren(new javax.xml.namespace.QName("http://schemas.microsoft.com/office/drawing/2012/chart", "dlblRangeCache", "c15"));
   org.apache.xmlbeans.XmlObject dlblRangeCache = dlblRangeCaches[0];
   // empty the cache
   dlblRangeCache.newCursor().removeXmlContents();
   // create new cache from dataLabelsRangeSource
   org.openxmlformats.schemas.drawingml.x2006.chart.CTStrData cache = org.openxmlformats.schemas.drawingml.x2006.chart.CTStrData.Factory.newInstance();
   dataLabelsRangeSource.fillStringCache(cache);
   // set new cache
   dlblRangeCache.set(cache);   
  }
 }

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

  String filePath = "ScatterChartSample.pptx"; // has template scatter chart
  String filePathNew = "ScatterChartSample_New.pptx";

  Object[][] data = new Object[][] { // new data 1 series, 6 x-y-values and data labels
   {"X-Values", "Y-Values", "DataLabels"}, // series title
   {0.7d, 1.7d, "aa"}, // x1
   {1.8d, 3.2d, "bb"}, // x2
   {2.6d, 2.8d, "cc"}, // x3
   {1.7d, 3.7d, "dd"}, // x4
   {2.8d, 4.2d, "ee"}, // x5
   {3.6d, 1.8d, "ff"} // x6
  };

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

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

  updateScatterChart(chart, data);

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

}

结果<代码>散点图Sample\u New。pptx:

注意:使用当前的apache poi 5.2.0测试并工作。

能够将XPath作为使用//c: 扩展[c15:datalabelsRange]它需要net。旧金山。萨克森-saxon-HEsaxon-HE-10.6.jar在我的例子中)。

它需要poi-ooxml-full-5.2.0。jar,而不仅仅是ooxml模式的精简版本。

 类似资料:
  • 我正试图用Plotly编写散点图,并使其具有交互式trhough Dash回调,问题是当我更改下拉列表时,我的图形没有更新。数据结构如下所示: 报告修订周期202002年第29/02/2020号第16793 3 202001年第31/01/2020号第18933 1 202101年第31/01/2021 6246 132 202001年第17/01/2020 13 1号第

  • 我正在做仪表板。这是我的密码: 仪表板中有一个散点图()和一个表()。散点图的每个点对应于表中的特定行,我从excel文件中读取这些数据 excel文件中的数据采用以下格式: 我想实现这个功能:当用户选择散点图中的某个点时,代码会突出显示表中相应的行(例如将这些行中的单元格的背景颜色更改为,除了列,保持其颜色)。 检查以下来源: 使用样式数据条件的dash datatable单个高亮显示效果异常

  • 我有一个有大约200张幻灯片的PowerPoint演示文稿。每张幻灯片都有一个图表,其中的数据通过到主xlsx文件的链接每月更新一次。 为了不在图表中显示空值(未来月份),我打开数据编辑器(图表右键单击>Edit data...)并选择直到当前月份的范围。 我在PowerPoint中为它写了一个宏:

  • 散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对

  • 散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对齐方式。 数据 颜色 设置数据系列的

  • 散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对