导入 Google 表格时如何使用 apache poi 显示系列标签
How to get series labels to show using apache poi when importing into Google Sheets
我正在使用 Apache POI 生成折线图并导入到 Google 表格中。无论我尝试什么,我似乎都无法显示系列标签。
这是我尝试过的:
XDDFLineChartData.Series
todoSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, todoDataSource),
doneSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, doneDataSource),
deltaSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, deltaDataSource);
todoSeries.setTitle("Todo", null);
todoSeries.setSmooth(true);
todoSeries.setMarkerStyle(MarkerStyle.CIRCLE);
doneSeries.setTitle("Done", new CellReference(countsRowStart-1, 10, true, true));
doneSeries.setSmooth(true);
doneSeries.setMarkerStyle(MarkerStyle.CIRCLE);
deltaSeries.setTitle("Delta", new CellReference(countsRowStart-1, 11, true, true));
deltaSeries.setSmooth(true);
deltaSeries.setMarkerStyle(MarkerStyle.CIRCLE);
但其中 none 似乎有效。
Apache POI
用于创建 Microsoft Office
文件以供在 Microsoft Office
应用程序中使用。因此,如果需要使文件在 Microsoft Office
以外的应用程序中可用,那么我们需要考虑这些应用程序的要求。特别是 Google Sheets
(还有 Docs
和 Slides
)在从 Microsoft Office
本身解析 Microsoft Office
文件时有时会非常不同。因此,使 Microsoft Office
文件可用于 Google Sheets
、Docs
和 Slides
.
会变得非常繁琐
您发现 Microsoft Office
个文件的图表中未显示图表系列标题。当标题不是取自图表数据 sheet 的单元格而是被设置为文字时,就会发生这种情况。所以这个问题可以通过将系列标题放入图表数据 sheet 然后使用 XDDFChartData.Series.setTitle giving the correct CellReference 而不是 null
来解决。但是 CellReference
也必须包含 sheet 名称。
示例:
鉴于 sheet
是图表的数据 sheet 在 A2
中具有第一个系列的标题并且 series1
是 XDDFChartData.Series
:
series1.setTitle("Series 1", new CellReference(sheet.getSheetName(), 1, 0, true, true));
使用这个,Google Sheets
也会显示系列标题。
完整示例基于 https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/examples/xssf/usermodel/ -> LineChart.java.
import org.apache.poi.xssf.usermodel.examples.*;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xddf.usermodel.PresetColor;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFLineProperties;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* Line chart example.
*/
public final class LineChart {
private LineChart() {}
public static void main(String[] args) throws IOException {
try (XSSFWorkbook wb = new XSSFWorkbook()) {
XSSFSheet sheet = wb.createSheet("linechart");
// Create data for the chart
Object[][] sheetData = new Object[][] {
new Object[] {"Categories", 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d, 10d},
new Object[] {"Series 1", 0d, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d},
new Object[] {"Series 2", 0.5d, 2.5d, 4.5d, 6.5d, 8.5d, 10.5d, 12.5d, 14.5d, 16.5d, 18.5d}
};
// Put data for the chart into the sheet
Row row;
Cell cell;
int rowIndex = 0;
for (Object[] rowData : sheetData) {
row = sheet.createRow(rowIndex++);
int colIndex = 0;
for (Object cellData : rowData) {
cell = row.createCell(colIndex++);
if (cellData instanceof String) {
cell.setCellValue((String)cellData);
} else if (cellData instanceof Double) {
cell.setCellValue((Double)cellData);
}
}
}
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
XSSFChart chart = drawing.createChart(anchor);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
// Use a category axis for the bottom axis.
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("x"); // https://whosebug.com/questions/32010765
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setTitle("f(x)");
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 1, 10));
XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 1, 10));
XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 1, 10));
XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
//series1.setTitle("2x", null); // https://whosebug.com/questions/21855842
series1.setTitle("Series 1", new CellReference(sheet.getSheetName(), 1, 0, true, true));
series1.setSmooth(false); // https://whosebug.com/questions/29014848
series1.setMarkerStyle(MarkerStyle.CIRCLE); // https://whosebug.com/questions/39636138
series1.setMarkerSize((short) 10);
XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
//series2.setTitle("3x", null);
series2.setTitle("Series 2", new CellReference(sheet.getSheetName(), 2, 0, true, true));
series2.setSmooth(true);
series2.setMarkerStyle(MarkerStyle.CIRCLE); // https://whosebug.com/questions/39636138
series2.setMarkerSize((short) 10);
chart.plot(data);
// if your series have missing values like https://whosebug.com/questions/29014848
// chart.displayBlanksAs(DisplayBlanks.GAP);
// https://whosebug.com/questions/24676460
solidLineSeries(series1, PresetColor.CHARTREUSE);
solidLineSeries(series2, PresetColor.TURQUOISE);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
wb.write(fileOut);
}
}
}
private static void solidLineSeries(XDDFChartData.Series series, PresetColor color) {
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
//XDDFChartData.Series series = data.getSeries().get(index);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setLineProperties(line);
series.setShapeProperties(properties);
}
}
但是 Google Sheets
也存在其他问题。例如使标记和轴可见。如前所述,使 Microsoft Office
文件可用于 Google Sheets
、Docs
和 Slides
.
可能会变得非常乏味
我正在使用 Apache POI 生成折线图并导入到 Google 表格中。无论我尝试什么,我似乎都无法显示系列标签。
这是我尝试过的:
XDDFLineChartData.Series
todoSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, todoDataSource),
doneSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, doneDataSource),
deltaSeries =
(XDDFLineChartData.Series) data.addSeries(dateDataSource, deltaDataSource);
todoSeries.setTitle("Todo", null);
todoSeries.setSmooth(true);
todoSeries.setMarkerStyle(MarkerStyle.CIRCLE);
doneSeries.setTitle("Done", new CellReference(countsRowStart-1, 10, true, true));
doneSeries.setSmooth(true);
doneSeries.setMarkerStyle(MarkerStyle.CIRCLE);
deltaSeries.setTitle("Delta", new CellReference(countsRowStart-1, 11, true, true));
deltaSeries.setSmooth(true);
deltaSeries.setMarkerStyle(MarkerStyle.CIRCLE);
但其中 none 似乎有效。
Apache POI
用于创建 Microsoft Office
文件以供在 Microsoft Office
应用程序中使用。因此,如果需要使文件在 Microsoft Office
以外的应用程序中可用,那么我们需要考虑这些应用程序的要求。特别是 Google Sheets
(还有 Docs
和 Slides
)在从 Microsoft Office
本身解析 Microsoft Office
文件时有时会非常不同。因此,使 Microsoft Office
文件可用于 Google Sheets
、Docs
和 Slides
.
您发现 Microsoft Office
个文件的图表中未显示图表系列标题。当标题不是取自图表数据 sheet 的单元格而是被设置为文字时,就会发生这种情况。所以这个问题可以通过将系列标题放入图表数据 sheet 然后使用 XDDFChartData.Series.setTitle giving the correct CellReference 而不是 null
来解决。但是 CellReference
也必须包含 sheet 名称。
示例:
鉴于 sheet
是图表的数据 sheet 在 A2
中具有第一个系列的标题并且 series1
是 XDDFChartData.Series
:
series1.setTitle("Series 1", new CellReference(sheet.getSheetName(), 1, 0, true, true));
使用这个,Google Sheets
也会显示系列标题。
完整示例基于 https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/examples/xssf/usermodel/ -> LineChart.java.
import org.apache.poi.xssf.usermodel.examples.*;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xddf.usermodel.PresetColor;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFLineProperties;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* Line chart example.
*/
public final class LineChart {
private LineChart() {}
public static void main(String[] args) throws IOException {
try (XSSFWorkbook wb = new XSSFWorkbook()) {
XSSFSheet sheet = wb.createSheet("linechart");
// Create data for the chart
Object[][] sheetData = new Object[][] {
new Object[] {"Categories", 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d, 10d},
new Object[] {"Series 1", 0d, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d},
new Object[] {"Series 2", 0.5d, 2.5d, 4.5d, 6.5d, 8.5d, 10.5d, 12.5d, 14.5d, 16.5d, 18.5d}
};
// Put data for the chart into the sheet
Row row;
Cell cell;
int rowIndex = 0;
for (Object[] rowData : sheetData) {
row = sheet.createRow(rowIndex++);
int colIndex = 0;
for (Object cellData : rowData) {
cell = row.createCell(colIndex++);
if (cellData instanceof String) {
cell.setCellValue((String)cellData);
} else if (cellData instanceof Double) {
cell.setCellValue((Double)cellData);
}
}
}
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
XSSFChart chart = drawing.createChart(anchor);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
// Use a category axis for the bottom axis.
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("x"); // https://whosebug.com/questions/32010765
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setTitle("f(x)");
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 1, 10));
XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 1, 10));
XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 1, 10));
XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
//series1.setTitle("2x", null); // https://whosebug.com/questions/21855842
series1.setTitle("Series 1", new CellReference(sheet.getSheetName(), 1, 0, true, true));
series1.setSmooth(false); // https://whosebug.com/questions/29014848
series1.setMarkerStyle(MarkerStyle.CIRCLE); // https://whosebug.com/questions/39636138
series1.setMarkerSize((short) 10);
XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
//series2.setTitle("3x", null);
series2.setTitle("Series 2", new CellReference(sheet.getSheetName(), 2, 0, true, true));
series2.setSmooth(true);
series2.setMarkerStyle(MarkerStyle.CIRCLE); // https://whosebug.com/questions/39636138
series2.setMarkerSize((short) 10);
chart.plot(data);
// if your series have missing values like https://whosebug.com/questions/29014848
// chart.displayBlanksAs(DisplayBlanks.GAP);
// https://whosebug.com/questions/24676460
solidLineSeries(series1, PresetColor.CHARTREUSE);
solidLineSeries(series2, PresetColor.TURQUOISE);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
wb.write(fileOut);
}
}
}
private static void solidLineSeries(XDDFChartData.Series series, PresetColor color) {
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
//XDDFChartData.Series series = data.getSeries().get(index);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setLineProperties(line);
series.setShapeProperties(properties);
}
}
但是 Google Sheets
也存在其他问题。例如使标记和轴可见。如前所述,使 Microsoft Office
文件可用于 Google Sheets
、Docs
和 Slides
.