导入 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(还有 DocsSlides)在从 Microsoft Office 本身解析 Microsoft Office 文件时有时会非常不同。因此,使 Microsoft Office 文件可用于 Google SheetsDocsSlides.

会变得非常繁琐

您发现 Microsoft Office 个文件的图表中未显示图表系列标题。当标题不是取自图表数据 sheet 的单元格而是被设置为文字时,就会发生这种情况。所以这个问题可以通过将系列标题放入图表数据 sheet 然后使用 XDDFChartData.Series.setTitle giving the correct CellReference 而不是 null 来解决。但是 CellReference 也必须包含 sheet 名称。

示例:

鉴于 sheet 是图表的数据 sheet 在 A2 中具有第一个系列的标题并且 series1XDDFChartData.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 SheetsDocsSlides.

可能会变得非常乏味