java - 具有多个图表的 Apache POI 绘图区
java - Apache POI plot area with multiple charts
我正在尝试使用 PowerPoint 文件作为模板来生成另一个 powerpoint 来替换购物车数据。为了使模板看起来尽可能相似,我只是尝试替换我需要替换的数据,复制图表第一个 CT*Ser
中的所有其他数据。当绘图区域只有一个图表时,大多数图表(目前我对饼图、条形图和折线图感兴趣)一切正常。
当绘图区域有多个图表时(在我的例子中,一个包含多个系列的条形图和一个只有一个系列的折线图),看起来有些不对劲,Microsoft PowerPoint 可以'不要打开文件或其中的一部分,因为它似乎是被管理的。
为此,我正在为每个图表和图表类型执行以下代码(图表是我用来在模板文件中保留引用的对象)。
if (graph.getType().equals(CTArea3DChart.class.getName())) {
CTArea3DChart c = plot.getArea3DChartArray()[graph.getIndex()];
int removeSeries = c.getSerArray().length;
for (int s = 0; s < graph.getSeries().size(); s++) {
CTAreaSer ser = (CTAreaSer) c.getSerArray(0).copy();
ser.getIdx().setVal(s);
ser.getOrder().setVal(s);
//ser.unsetSpPr();
Serie serie = graph.getSeries().get(s);
boolean delete = ser.isSetDLbls() && ser.getDLbls().getDLblArray().length > 0;
if (delete) {
int cntDlbls = ser.getDLbls().getDLblArray().length;
for (int d = 0; d < cntDlbls; d++) {
ser.getDLbls().removeDLbl(0);
}
}
ser.unsetTx();
CTStrRef serTitle = ser.addNewTx().addNewStrRef();
serTitle.setF(graph.getSheetName() + "!$" + (char) ('B' + s) + "");
CTStrData serTitleData = serTitle.addNewStrCache();
serTitleData.addNewPtCount().setVal(1);
CTStrVal serTitleDataVal = serTitleData.addNewPt();
serTitleDataVal.setIdx(0);
serTitleDataVal.setV(serie.getTitle());
// Cat
CTAxDataSource cat = ser.getCat();
if (cat.isSetNumRef()) {
cat.unsetNumRef();
}
if (cat.isSetStrRef()) {
cat.unsetStrRef();
}
if (serie.isNumericCategories()) {
CTNumRef numRef = cat.addNewNumRef();
numRef.setF(graph.getSheetName() + "!$A:$A$" + (serie.getCategories().size() + 1));
CTNumData data = numRef.addNewNumCache();
data.setFormatCode("General");
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getCategories().size());
int r = 0;
for (String v : serie.getCategories()) {
CTNumVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(StringUtils.isBlank(v) ? "0" : v);
if (delete) {
CTDLbl dlbl = ser.getDLbls().addNewDLbl();
dlbl.addNewIdx().setVal(r - 1);
dlbl.addNewDelete().setVal(true);
}
}
}
else {
CTStrRef strRef = cat.addNewStrRef();
strRef.setF(graph.getSheetName() + "!$A:$A$" + (serie.getCategories().size() + 1));
CTStrData data = strRef.addNewStrCache();
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getCategories().size());
int r = 0;
for (String v : serie.getCategories()) {
CTStrVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(v);
if (delete) {
CTDLbl dlbl = ser.getDLbls().addNewDLbl();
dlbl.addNewIdx().setVal(r - 1);
dlbl.addNewDelete().setVal(true);
}
}
}
// Values
CTNumDataSource val = ser.getVal();
val.unsetNumRef();
CTNumRef numRef = val.addNewNumRef();
char letter = (char) ('B' + s);
numRef.setF(graph.getSheetName() + "!$" + letter + ":$" + letter + "$" + (serie.getValues().size() + 1));
CTNumData data = numRef.addNewNumCache();
data.setFormatCode("General");
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getValues().size());
int r = 0;
for (String v : serie.getValues()) {
CTNumVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(StringUtils.isBlank(v) ? "0" : v);
}
c.addNewSer().set(ser);
}
for (int s = 0; s < removeSeries; s++) {
c.removeSer(0);
}
}
总结:
- 克隆第一个 CT*Ser;
- 正在替换 idx、订单和 tx;
- 如果 CT*Ser 有 DLbls,里面有 DLbl 标签,我删除 DLbl,然后添加它们,并将 delete 设置为 true;
- 修改猫;
- 如果类别都是数值,我使用 NumRefs,否则使用 StrRefs;
- 修改值;
- 删除之前的系列
我也更改了支持 Excel 资源,仅使用构建图表的数据(绘图区域中每个图表有一个 sheet)。我也检查了对单元格和单元格范围的引用,它们没问题。
我用以下软件检查了生成的文件,报告结果:
- Libre Office(如我所愿)
- Onlyoffice(可以,但似乎不支持每个绘图区域有多个图表?)
- Microsoft Powerpoint 桌面(打开文件时出错,尝试恢复,但失败并且无法从错误的幻灯片加载幻灯片内容)
- Microsoft Powerpoint 在线(不打开文件)
是否有相对简单的方法来验证 powerpoint 文件并找出阻止文件与 powerpoint 一起工作的错误?有什么方法可以可靠地诊断这些问题吗?正在处理 linux?
已使用 Powerpoint 创建模板文件。很抱歉,如果我没有报告软件版本,但我不记得它们(Powerpoint 不在我的电脑上)。
请帮助我了解问题所在,因为我实际上开始觉得自己很愚蠢。任何建议将不胜感激。非常感谢。
我终于找到了问题所在(或者至少看起来是这样):如发布的代码中所示,对于每个图表,我将渐进式 ID 设置为 idx 并为元素设置顺序,但我从每个图表的 0 开始在绘图区。使每个绘图区域内的元素的 idx 和顺序保持唯一,它起作用了。
希望这对以后的人有所帮助。
我正在尝试使用 PowerPoint 文件作为模板来生成另一个 powerpoint 来替换购物车数据。为了使模板看起来尽可能相似,我只是尝试替换我需要替换的数据,复制图表第一个 CT*Ser
中的所有其他数据。当绘图区域只有一个图表时,大多数图表(目前我对饼图、条形图和折线图感兴趣)一切正常。
当绘图区域有多个图表时(在我的例子中,一个包含多个系列的条形图和一个只有一个系列的折线图),看起来有些不对劲,Microsoft PowerPoint 可以'不要打开文件或其中的一部分,因为它似乎是被管理的。
为此,我正在为每个图表和图表类型执行以下代码(图表是我用来在模板文件中保留引用的对象)。
if (graph.getType().equals(CTArea3DChart.class.getName())) {
CTArea3DChart c = plot.getArea3DChartArray()[graph.getIndex()];
int removeSeries = c.getSerArray().length;
for (int s = 0; s < graph.getSeries().size(); s++) {
CTAreaSer ser = (CTAreaSer) c.getSerArray(0).copy();
ser.getIdx().setVal(s);
ser.getOrder().setVal(s);
//ser.unsetSpPr();
Serie serie = graph.getSeries().get(s);
boolean delete = ser.isSetDLbls() && ser.getDLbls().getDLblArray().length > 0;
if (delete) {
int cntDlbls = ser.getDLbls().getDLblArray().length;
for (int d = 0; d < cntDlbls; d++) {
ser.getDLbls().removeDLbl(0);
}
}
ser.unsetTx();
CTStrRef serTitle = ser.addNewTx().addNewStrRef();
serTitle.setF(graph.getSheetName() + "!$" + (char) ('B' + s) + "");
CTStrData serTitleData = serTitle.addNewStrCache();
serTitleData.addNewPtCount().setVal(1);
CTStrVal serTitleDataVal = serTitleData.addNewPt();
serTitleDataVal.setIdx(0);
serTitleDataVal.setV(serie.getTitle());
// Cat
CTAxDataSource cat = ser.getCat();
if (cat.isSetNumRef()) {
cat.unsetNumRef();
}
if (cat.isSetStrRef()) {
cat.unsetStrRef();
}
if (serie.isNumericCategories()) {
CTNumRef numRef = cat.addNewNumRef();
numRef.setF(graph.getSheetName() + "!$A:$A$" + (serie.getCategories().size() + 1));
CTNumData data = numRef.addNewNumCache();
data.setFormatCode("General");
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getCategories().size());
int r = 0;
for (String v : serie.getCategories()) {
CTNumVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(StringUtils.isBlank(v) ? "0" : v);
if (delete) {
CTDLbl dlbl = ser.getDLbls().addNewDLbl();
dlbl.addNewIdx().setVal(r - 1);
dlbl.addNewDelete().setVal(true);
}
}
}
else {
CTStrRef strRef = cat.addNewStrRef();
strRef.setF(graph.getSheetName() + "!$A:$A$" + (serie.getCategories().size() + 1));
CTStrData data = strRef.addNewStrCache();
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getCategories().size());
int r = 0;
for (String v : serie.getCategories()) {
CTStrVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(v);
if (delete) {
CTDLbl dlbl = ser.getDLbls().addNewDLbl();
dlbl.addNewIdx().setVal(r - 1);
dlbl.addNewDelete().setVal(true);
}
}
}
// Values
CTNumDataSource val = ser.getVal();
val.unsetNumRef();
CTNumRef numRef = val.addNewNumRef();
char letter = (char) ('B' + s);
numRef.setF(graph.getSheetName() + "!$" + letter + ":$" + letter + "$" + (serie.getValues().size() + 1));
CTNumData data = numRef.addNewNumCache();
data.setFormatCode("General");
CTUnsignedInt cnt = data.addNewPtCount();
cnt.setVal(serie.getValues().size());
int r = 0;
for (String v : serie.getValues()) {
CTNumVal pt = data.addNewPt();
pt.setIdx(r++);
pt.setV(StringUtils.isBlank(v) ? "0" : v);
}
c.addNewSer().set(ser);
}
for (int s = 0; s < removeSeries; s++) {
c.removeSer(0);
}
}
总结:
- 克隆第一个 CT*Ser;
- 正在替换 idx、订单和 tx;
- 如果 CT*Ser 有 DLbls,里面有 DLbl 标签,我删除 DLbl,然后添加它们,并将 delete 设置为 true;
- 修改猫;
- 如果类别都是数值,我使用 NumRefs,否则使用 StrRefs;
- 修改值;
- 删除之前的系列
我也更改了支持 Excel 资源,仅使用构建图表的数据(绘图区域中每个图表有一个 sheet)。我也检查了对单元格和单元格范围的引用,它们没问题。
我用以下软件检查了生成的文件,报告结果:
- Libre Office(如我所愿)
- Onlyoffice(可以,但似乎不支持每个绘图区域有多个图表?)
- Microsoft Powerpoint 桌面(打开文件时出错,尝试恢复,但失败并且无法从错误的幻灯片加载幻灯片内容)
- Microsoft Powerpoint 在线(不打开文件)
是否有相对简单的方法来验证 powerpoint 文件并找出阻止文件与 powerpoint 一起工作的错误?有什么方法可以可靠地诊断这些问题吗?正在处理 linux?
已使用 Powerpoint 创建模板文件。很抱歉,如果我没有报告软件版本,但我不记得它们(Powerpoint 不在我的电脑上)。
请帮助我了解问题所在,因为我实际上开始觉得自己很愚蠢。任何建议将不胜感激。非常感谢。
我终于找到了问题所在(或者至少看起来是这样):如发布的代码中所示,对于每个图表,我将渐进式 ID 设置为 idx 并为元素设置顺序,但我从每个图表的 0 开始在绘图区。使每个绘图区域内的元素的 idx 和顺序保持唯一,它起作用了。
希望这对以后的人有所帮助。