我有一个docx文件,其中仅包含两个图表,一个是饼图,另一个是甜甜圈图,如下所示:

java - 获取甜甜圈图系列在可用时给出零结果-LMLPHP

我将按照以下answer中的说明修改那些图表数据:

问题是:

pieChart.getChartSeries ().size (); // give me 1
doughnutChart.getChartSeries ().size (); // give me 0


我认为oughnutChart系列应该可用,因为我已经检查了doughnutChart工作簿(doughnutChart.getWorkbook ();)是否有效(显示正确的数据),并且甜甜圈图表也正确显示在Word应用程序上。

问题是为什么doughnutChart.getChartSeries ().size ();在我期望给我1时给我零。是一个错误,还是我应该区别对待饼图和甜甜圈图?如果是这样,如何从甜甜圈图中获取序列并对其进行修改?

===更新===
我放弃获得甜甜圈图系列,因为它没有得到图书馆的直接支持。
我试图使用一段代码将环形数据全部替换为一个新的代码:

private void replacePiasChartData (
            String title,
            XWPFChart chart, // the doughnut chart get from XWPFDocument
            SourceData data)
{
    XSSFWorkbook workbook = new XSSFWorkbook ();
    XSSFSheet sheet = workbook.createSheet ("sheet");
    chart.setWorkbook (workbook);

    chart.setTitleText (title);
    int rowNum = 1;
    sheet.createRow (rowNum).createCell (0).setCellValue ("1st Qtr");
    sheet.getRow (rowNum).createCell (1).setCellValue (data.getChartValue ());

    rowNum++;
    sheet.createRow (rowNum).createCell (0).setCellValue ("2nd Qtr");
    sheet.getRow (rowNum).createCell (1).setCellValue (100d - data.getChartValue ());

    XDDFDataSource<String> category = XDDFDataSourcesFactory
                .fromStringCellRange (sheet, new CellRangeAddress (1, 2, 0, 0));

    XDDFNumericalDataSource<Double> value = XDDFDataSourcesFactory
                .fromNumericCellRange (sheet, new CellRangeAddress (1, 2, 1, 1));

    XDDFChartData chartData =
                new XDDFPieChartData (chart.getCTChart ().getPlotArea ().addNewPieChart ());

    chartData.addSeries (category, value);
    chart.plot (chartData);
}


该图表将使用新数据进行更新,但是初始图表仍然存在(作为内部甜甜圈图),是否有任何方法可以删除它,从而使替换过程正确完成?我认为我应该删除初始图表数据,但是我找不到任何方法。

当前的图表如下所示:
java - 获取甜甜圈图系列在可用时给出零结果-LMLPHP

===更新II ===
通过使用行为与饼图非常相似的其他类来获取甜甜圈图系列,可以解决该问题。

最佳答案

明确的方法是提供XDDFDoughnutChartData。这很简单,因为它与XDDFPieChartData并没有太大区别。唯一的区别是使用CTDoughnutChart而不是CTPieChart

以下是从https://svn.apache.org/viewvc/poi/tags/REL_4_1_0/src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFPieChartData.java?view=markup派生的实现:

import org.apache.poi.xddf.usermodel.chart.*;

import org.apache.poi.util.Beta;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTSerTx;

@Beta
public class XDDFDoughnutChartData extends XDDFChartData {
    private CTDoughnutChart chart;

    public XDDFDoughnutChartData(CTDoughnutChart chart) {
        this.chart = chart;
        for (CTPieSer series : chart.getSerList()) {
            this.series.add(new Series(series, series.getCat(), series.getVal()));
        }
    }

    @Override
    public void setVaryColors(boolean varyColors) {
        if (chart.isSetVaryColors()) {
            chart.getVaryColors().setVal(varyColors);
        } else {
            chart.addNewVaryColors().setVal(varyColors);
        }
    }

    @Override
    public XDDFChartData.Series addSeries(XDDFDataSource<?> category,
            XDDFNumericalDataSource<? extends Number> values) {
        final int index = this.series.size();
        final CTPieSer ctSer = this.chart.addNewSer();
        ctSer.addNewCat();
        ctSer.addNewVal();
        ctSer.addNewIdx().setVal(index);
        ctSer.addNewOrder().setVal(index);
        final Series added = new Series(ctSer, category, values);
        this.series.add(added);
        return added;
    }

    public class Series extends XDDFChartData.Series {
        private CTPieSer series;

        protected Series(CTPieSer series, XDDFDataSource<?> category,
                XDDFNumericalDataSource<? extends Number> values) {
            super(category, values);
            this.series = series;
        }

        protected Series(CTPieSer series, CTAxDataSource category, CTNumDataSource values) {
            super(XDDFDataSourcesFactory.fromDataSource(category), XDDFDataSourcesFactory.fromDataSource(values));
            this.series = series;
        }

        @Override
        protected CTSerTx getSeriesText() {
            if (series.isSetTx()) {
                return series.getTx();
            } else {
                return series.addNewTx();
            }
        }

        @Override
        public void setShowLeaderLines(boolean showLeaderLines) {
            if (!series.isSetDLbls()) {
                series.addNewDLbls();
            }
            if (series.getDLbls().isSetShowLeaderLines()) {
                series.getDLbls().getShowLeaderLines().setVal(showLeaderLines);
            } else {
                series.getDLbls().addNewShowLeaderLines().setVal(showLeaderLines);
            }
        }

        @Override
        public XDDFShapeProperties getShapeProperties() {
            if (series.isSetSpPr()) {
                return new XDDFShapeProperties(series.getSpPr());
            } else {
                return null;
            }
        }

        @Override
        public void setShapeProperties(XDDFShapeProperties properties) {
            if (properties == null) {
                if (series.isSetSpPr()) {
                    series.unsetSpPr();
                }
            } else {
                if (series.isSetSpPr()) {
                    series.setSpPr(properties.getXmlObject());
                } else {
                    series.addNewSpPr().set(properties.getXmlObject());
                }
            }
        }

        public long getExplosion() {
            if (series.isSetExplosion()) {
                return series.getExplosion().getVal();
            } else {
                return 0;
            }
        }

        public void setExplosion(long explosion) {
            if (series.isSetExplosion()) {
                series.getExplosion().setVal(explosion);
            } else {
                series.addNewExplosion().setVal(explosion);
            }
        }

        @Override
        protected CTAxDataSource getAxDS() {
            return series.getCat();
        }

        @Override
        protected CTNumDataSource getNumDS() {
            return series.getVal();
        }
    }
}


现在,在代码中使用以下代码将适用于饼图和fpr甜甜圈图:

Word模板:

java - 获取甜甜圈图系列在可用时给出零结果-LMLPHP

码:

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellRangeAddress;

public class WordChangeChartDataPieOrDoughnut {

 public static void main(String[] args) throws Exception {

  String filePath = "TEMP_Chart_Simple.docx"; // has template chart having 1 series, 4 categories
  String filePathNew = "New_Chart_Simple.docx";

  Object[][] data = new Object[][] { // 1 series, 4 categories
   {"", "Clothing sales"}, // series titles
   {"Trousers", 123d}, // category 1
   {"Shirt", 345d}, // category 2
   {"Skirt", 180d}, // category 3
   {"Blouse", 180d} // category 4
  };

  XWPFDocument document = new XWPFDocument(new FileInputStream(filePath));

  XWPFChart chart = document.getCharts().get(0);
  XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
  String sheetName = chartDataWorkbook.getSheetName(0);
  XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);

  XDDFChartData chartData = null;
  if (chart.getChartSeries().size() == 1) { // only one chart data
   chartData = chart.getChartSeries().get(0); // pie chart or other supported chart
  } else if (chart.getCTChart().getPlotArea().getDoughnutChartList().size() == 1) { // only one doughnut chart data
   chartData = new XDDFDoughnutChartData(chart.getCTChart().getPlotArea().getDoughnutChartList().get(0)); //doughnut chart
  }

  if (chartData != null) {
   if (chartData.getSeries().size() == 1) { // exact one series

    int rMin = 1;
    int rMax = 4;

    // set new category data
    XDDFCategoryDataSource category = null;
    int c = 0;
    for (int r = rMin; r < rMax+1; r++) {
     chartDataSheet.getRow(r).getCell(c).setCellValue((String)data[r][c]); // in sheet
    }
    category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart

    // series 1
    XDDFChartData.Series series1 = chartData.getSeries().get(0);
    c = 1;
    // set new title
    String series1Title = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
    chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series1Title);
    if (chartDataSheet.getTables().size() > 0) {
     if (chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().size() > c)
      chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series1Title);
    }
    series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart

    // set new values
    XDDFNumericalDataSource<Double> values = null;
    for (int r = rMin; r < rMax+1; r++) {
     chartDataSheet.getRow(r).getCell(c).setCellValue((Double)data[r][c]); // in sheet
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c));
    series1.replaceData(category, values);
    series1.plot(); //in chart

   }
  }

  FileOutputStream out = new FileOutputStream(filePathNew);
  document.write(out);
  out.close();
  document.close();
 }

}


结果:

java - 获取甜甜圈图系列在可用时给出零结果-LMLPHP

关于java - 获取甜甜圈图系列在可用时给出零结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57783332/

10-11 22:16