主要问题是设置setVaryColors
to true
含义如下:
如果只有一个系列,则改变该系列中每个数据点的颜色。然后图例显示不同的数据点而不是系列。如果有多个系列,则为每个系列改变颜色。然后图例显示了不同的系列。
所以我们需要设置setVaryColors
to false
如果只有一个系列存在。
但我们还需要额外设置AxisCrossBetween
,因此左轴与类别之间的类别轴交叉。否则,第一个和最后一个类别正好位于交叉点上,并且条形图只有一半可见。
最后,XDDF
目前只准备了一半,还有很多错误。例如XDDFChart.setSheetTitle
是越野车。它创建了一个表,但只完成了一半且不完整。创建不完整的表后,Excel 无法打开工作簿。所以在Word中更新图表数据是不可能的。
以下代码适用于我,可以创建仅包含一个系列以及两个系列的图表。另外,我尝试通过单个步骤使代码更加结构化。每个步骤都对其正在执行的操作进行了评论。
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
public class CreateWordXDDFChart {
// Methode to set title in the data sheet without creating a Table but using the sheet data only.
// Creating a Table is not really necessary.
static CellReference setTitleInDataSheet(XWPFChart chart, String title, int column) throws Exception {
XSSFWorkbook workbook = chart.getWorkbook();
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFRow row = sheet.getRow(0); if (row == null) row = sheet.createRow(0);
XSSFCell cell = row.getCell(column); if (cell == null) cell = row.createCell(column);
cell.setCellValue(title);
return new CellReference(sheet.getSheetName(), 0, column, true, true);
}
public static void main(String[] args) throws Exception {
try (XWPFDocument document = new XWPFDocument()) {
// create the data
String[] categories = new String[]{"Lang 1", "Lang 2", "Lang 3"};
Double[] valuesA = new Double[]{10d, 20d, 30d};
Double[] valuesB = new Double[]{15d, 25d, 35d};
// create the chart
XWPFChart chart = document.createChart(15*Units.EMU_PER_CENTIMETER, 10*Units.EMU_PER_CENTIMETER);
// create data sources
int numOfPoints = categories.length;
String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
String valuesDataRangeA = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
String valuesDataRangeB = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
XDDFNumericalDataSource<Double> valuesDataA = XDDFDataSourcesFactory.fromArray(valuesA, valuesDataRangeA, 1);
XDDFNumericalDataSource<Double> valuesDataB = XDDFDataSourcesFactory.fromArray(valuesB, valuesDataRangeB, 2);
// create axis
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
// Set AxisCrossBetween, so the left axis crosses the category axis between the categories.
// Else first and last category is exactly on cross points and the bars are only half visible.
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
// create chart data
XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
((XDDFBarChartData)data).setBarDirection(BarDirection.COL);
// create series
// if only one series do not vary colors for each bar
((XDDFBarChartData)data).setVaryColors(false);
XDDFChartData.Series series = data.addSeries(categoriesData, valuesDataA);
// XDDFChart.setSheetTitle is buggy. It creates a Table but only half way and incomplete.
// Excel cannot opening the workbook after creatingg that incomplete Table.
// So updating the chart data in Word is not possible.
//series.setTitle("a", chart.setSheetTitle("a", 1));
series.setTitle("a", setTitleInDataSheet(chart, "a", 1));
/*
// if more than one series do vary colors of the series
((XDDFBarChartData)data).setVaryColors(true);
series = data.addSeries(categoriesData, valuesDataB);
//series.setTitle("b", chart.setSheetTitle("b", 2));
series.setTitle("b", setTitleInDataSheet(chart, "b", 2));
*/
// plot chart data
chart.plot(data);
// create legend
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.LEFT);
legend.setOverlay(false);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("CreateWordXDDFChart.docx")) {
document.write(fileOut);
}
}
}
}