【问题标题】:How to modify a graph label in apache poi?如何修改apache poi中的图形标签?
【发布时间】:2020-01-17 10:16:26
【问题描述】:

现在,我正在尝试从现有的 .xlsx

修改以下标签

图表图像:

图表已经根据我想要的值修改了它们的公式和值,但是这些数字仍然从图表中的先前值中获取它们的值。我怎样才能改变它们?我一直在寻找以前的问题,据推测用于获取当前标签值(在修改它们之前)的方法如下:

drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(2).getVal().getNumRef().getNumCache()

获得的图纸是我的工作表中的以下一张:

 XSSFDrawing drawing = sheet.createDrawingPatriarch();

但我得到一个包含 107 个值的列表...所以我不确定它是否正确。我不知道我需要修改什么。我会很感激一些帮助。

关于我如何修改图表的最小示例:

此 excel 表有五个系列列表,其中一个公式基于其他 excel 表。所以我做了以下代码:

 drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(0).getVal().getNumRef().setF("PERD_POLICY!$S$15:$S$" + lineasPerdPolicy + "");
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(0).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(1).getVal().getNumRef().setF("PERD_POLICY!$T$15:$T$" + lineasPerdPolicy);      
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(1).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(2).getVal().getNumRef().setF("PERD_POLICY!$U$15:$U$" + lineasPerdPolicy);
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(2).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(3).getVal().getNumRef().setF("PERD_POLICY!$V$15:$V$" + lineasPerdPolicy);
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(3).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(4).getVal().getNumRef().setF("PERD_POLICY!$W$15:$W$" + lineasPerdPolicy);
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(4).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(5).getVal().getNumRef().setF("PERD_POLICY!$R$15:$R$" + lineasPerdPolicy);
    drawing.getCharts().get(0).getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(5).getCat().getNumRef().setF("PERD_POLICY!$Q$15:$Q$" + lineasPerdPolicy);

lineasPerdPolicy 是一个变量,我用来计算我们从中获取值的工作表中的最后一行。工作表 "PERD_POLICY" 。该图表基于年份中的月份。我现在向当前的 serList 添加了一个新值,直到 2019 年 12 月。但绿色图表的最后一个标签显示为 9,66。该值来自 2019 年 10 月。

我认为使用以下图片会更好。这个显示最后一个标签的值是什么:

The current label value

而另一张图片中选择的值是我想在标签中显示的值,9,75

The graph value I want to show in the label

如果您不懂任何单词,请告诉我,因为我的 excel 是西班牙语。 价值 --> 价值 Punto --> 点

【问题讨论】:

  • 图表数据标签显示图表数据基础的值。因此,如果您说“图表已经修改了我想要的公式和值”。那么这没有正确完成,并且数据基础没有正确更改。请在minimal reproducible example 中展示你是如何做到这一点的。
  • 嗨!我修改了我的问题。如果您需要更多信息,请告诉我。谢谢!

标签: java excel apache-poi


【解决方案1】:

您使用低级ooxml-schemas 类的代码仅更新该系列的参考公式。它不会更新图表中的缓存值。

由于当前的apache poi 4.1.1 提供XDDFChartData.Series.replaceData 来更新图表的数据,我们应该使用它而不是低级别的ooxml-schemas 类。

让我们有一个完整的例子来展示如何做到这一点。

我们开始有一个 ExcelWithChartMar.xlsx 看起来像这样:

如您所见,A1:D4 中已有 1 月至 3 月的图表数据以及显示这些数据的图表。

我们需要知道:第一个数据行是1(第0行是标题行),当前最后一个数据行是3。最后一个数据行会增加。类别列是 0 (A),系列列是 1 (B)、2 (C) 和 3 (D)。请注意,所有索引都是从 0 开始的。

现在我们可以使用apache poi 4.1.1 运行以下代码:

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

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

class ExcelChangeChartData {

 static void updateChartData(XSSFChart chart, XSSFSheet dataSheet, 
  int firstDataRow, int lastDataRow, int categoryColumn, int[] seriesColumns) {

  for (XDDFChartData chartData : chart.getChartSeries()) {
   for (int s = 0; s < chartData.getSeriesCount() ; s++) {
    XDDFChartData.Series series = chartData.getSeries(s);
    if (seriesColumns.length > s) {
     XDDFCategoryDataSource category = XDDFDataSourcesFactory.fromStringCellRange(
      dataSheet, new CellRangeAddress(firstDataRow, lastDataRow, categoryColumn, categoryColumn));
     int seriesColumn = seriesColumns[s];
     XDDFNumericalDataSource<Double> values = XDDFDataSourcesFactory.fromNumericCellRange(
      dataSheet, new CellRangeAddress(firstDataRow, lastDataRow, seriesColumn, seriesColumn));
     series.replaceData(category, values);  
     series.plot();
    }
   }
  }
 }

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

  String[] months = new String[]{"Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  int firstDataRow = 1;
  int lastDataRow = 3;
  int categoryColumn = 0;
  int[] seriesColumns = new int[]{1,2,3};

  for (int m = 0; m < months.length - 1; m++) {
   String monthSource = months[m];
   String monthResult = months[m+1];
   String filePath = "./ExcelWithChart" + monthSource + ".xlsx";
   java.util.Random random = new java.util.Random();
   XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream(filePath));
   XSSFSheet sheet = workbook.getSheetAt(0);
   XSSFRow row = sheet.createRow(lastDataRow + 1);
   XSSFCell cell = row.createCell(categoryColumn);
   cell.setCellValue(monthResult);
   for (int i = 0; i < seriesColumns.length; i++) {
    cell = row.createCell(seriesColumns[i]);
    cell.setCellValue(random.nextDouble() / 10 + 0.02);
    cell.setCellStyle(sheet.getRow(lastDataRow).getCell(seriesColumns[i]).getCellStyle());
   }
   lastDataRow++;

   XSSFDrawing drawing = sheet.createDrawingPatriarch();
   XSSFChart chart = drawing.getCharts().get(0);
   updateChartData(chart, sheet, firstDataRow, lastDataRow, categoryColumn, seriesColumns);

   filePath = "./ExcelWithChart" + monthResult + ".xlsx";
   FileOutputStream out = new FileOutputStream(filePath);
   workbook.write(out);
   out.close();
   workbook.close();
  }
 }
}

这会创建 9 个额外的 Excel 文件 ExcelWithChartApr.xlsx ... ExcelWithChartDec.xlsx,每个文件都添加了新月份的数据。

updateChartData 方法使用XDDFChartData.Series.replaceData 方法更新图表数据。

【讨论】:

  • 嗨阿克塞尔!首先,感谢您提供这样一个扩展示例。当我尝试访问这样的 chartSeries 时出现 nullPointerException:drawing.getCharts().get(0).getChartSeries() 这是因为我试图阅读的 Excel 还是我正在读错了...?并且没有其他方法可以使用低级别的 ooxl-´schemas 来更改它?顺便说一句,打印 drawing.getCharts().get(0) 显示:名称:/xl/charts/chart1.xml - 内容类型:application/vnd.openxmlformats-officedocument.drawingml.chart+xml(Drawing.getCharts 大小是 1)
  • @Sergio García:您对NPE 的评论没有多大意义。如果drawing.getCharts().get(0) 像你说的那样返回一个图表并打印Name: /xl/charts/chart1.xml...,那么drawing.getCharts().get(0).getChartSeries() 不能抛出NPE。当然,这一切也只能使用低级别的ooxml-schemas 类。但这很繁琐,需要很多代码在这里详细展示。
  • 我知道这听起来可能很奇怪......但它正在发生,我不知道是因为它是如何创建我正在阅读的 .xlsx 还是......?这是错误(由 JUNit 测试运行):imgur.com/a/SseaFeG
  • @Sergio García:根据链接图片中的堆栈跟踪,它无法从其数据源获取图表数据。如果图表的数据源中没有类别源,则会发生这种情况。在我的示例中,如果范围 A1:A4(月份名称)不在图表的数据范围内,则会发生这种情况。只需相应地更改您的模板。必须有可用于类别轴的数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-23
  • 2020-03-09
  • 1970-01-01
  • 2021-12-07
相关资源
最近更新 更多