我正在尝试更新具有自己的颜色和样式的现有饼图。然后我想更新饼图但保留饼图的格式和样式。目前我可以更新饼图,但丢失格式/样式并且无法更新第一个值。
为了填充我正在这样做:
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);
}
这就是我得到的结果 正如您所看到的,图例和饼图的切片是不同的(第一个行与添加的其他行),工作表中的行也丢失了第一个行的格式,甚至第一行也没有被删除/更新,以便仅显示自“凯特行”以来。
我真的很感激一些帮助。谢谢。
您的代码遇到以下问题:
首先,您应该并行而不是单独更新
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
: