【问题标题】:How to get series labels to show using apache poi when importing into Google Sheets导入 Google 表格时如何使用 apache poi 显示系列标签
【发布时间】:2020-05-16 06:41:05
【问题描述】:

我正在使用 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);

但这些似乎都不起作用。

【问题讨论】:

  • 无法复制。对我来说setMarkerStyle 有效。因此,为了能够重现您的问题,我们需要a Minimal, Reproducible Examplesvn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/… 中有一个创建折线图的示例。这个可以作为依据。
  • SetMarkerStyle 有效,但我遇到的问题是 setTitle。出于某种原因,我无法让 setTitle 工作。我会看看你引用的例子。
  • 对我来说setTitle 也可以。所以同样的要求。我们需要一个最小的、可重现的例子来重现这个问题。您是否尝试过链接的LineChart.javaexample?还有setTitle 也被使用和工作。那你有什么不同呢?
  • 这原来是我这边的问题,或者更确切地说是 Google 表格方面的问题。我有一个 Excel 查看器,它正确地显示了图表。导入 Google 表格时,标签丢失。感谢您的快速回复。
  • 请在您的问题中提及,该问题仅在使用Google Sheets 时才会出现,以便其他读者了解。

标签: java apache-poi label series linegraph


【解决方案1】:

Apache POI 用于创建Microsoft Office 文件以在@​​987654326@ 应用程序中使用。因此,如果需要使文件在Microsoft Office 以外的应用程序中可用,那么我们需要考虑这些应用程序的要求。尤其是Google Sheets(还有DocsSlides)有时在解析Microsoft Office 文件和Microsoft Office 本身时会有很大不同。因此,使Microsoft Office 文件可用于Google SheetsDocsSlides 会变得非常乏味。

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

例子:

假设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://stackoverflow.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://stackoverflow.com/questions/21855842
            series1.setTitle("Series 1", new CellReference(sheet.getSheetName(), 1, 0, true, true));

            series1.setSmooth(false); // https://stackoverflow.com/questions/29014848
            series1.setMarkerStyle(MarkerStyle.CIRCLE); // https://stackoverflow.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://stackoverflow.com/questions/39636138
            series2.setMarkerSize((short) 10);
            chart.plot(data);

            // if your series have missing values like https://stackoverflow.com/questions/29014848
            // chart.displayBlanksAs(DisplayBlanks.GAP);

            // https://stackoverflow.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 会变得非常乏味。

【讨论】:

  • 感谢您的帮助。同样重要的是要再次强调sheet.getSheetName() 必须存在才能使其工作,因此必须使用完整的 CellReference 构造函数。对于任何试图将 POI 生成的输出导入 Google 表格的人,在 chart.plot(data) 之后使用 chart.getCTChart().getPlotArea().getValAxArray(0).addNewMajorGridlines() 也会显示“一些”网格线,但这并不完美。一般来说,我在将 Excel 图表导入 Google 表格方面的成功有限。正如 Axel 提到的,存在多个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 2014-01-01
  • 1970-01-01
相关资源
最近更新 更多