POI条形图生成一个系列有问题 [英] POI bar chart generate one series has question

查看:274
本文介绍了POI条形图生成一个系列有问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用JDK8和POI-4.1.0在此处使用它们的示例

I use JDK8 and POI-4.1.0 use they example here a link

将图表导出到Word.创建两个系列时可以两个系列img ,但我只创建一个系列.系列一个系列img 的图表错误类别>"lang1","lang2","lang3"是类别名称,但它们成为系列名称.我没有理想.我也发现使用折线图也有同样的问题我的代码

export chart to Word .when create two series is ok two series img, but I only create one series .the chart mistake category for series one series img

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

            List<String> listLanguages = new ArrayList<>(3);
            listLanguages.add("lang1");listLanguages.add("lang2");listLanguages.add("lang3");

            List<Double> listCountries = new ArrayList<>(3);            
            listCountries.add(10d);listCountries.add(20d);listCountries.add(30d);

            List<Double> listSpeakers = new ArrayList<>(3);
            listSpeakers.add(14d);listSpeakers.add(25d);listSpeakers.add(33d);

            String[] categories = listLanguages.toArray(new String[listLanguages.size()]);
            Double[] values1 = listCountries.toArray(new Double[listCountries.size()]);
            Double[] values2 = listSpeakers.toArray(new Double[listSpeakers.size()]);

            try (XWPFDocument doc = new XWPFDocument()) {
                XWPFChart chart = doc.createChart(5000000, 4000000);
                XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);

                XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);

                leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
                leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
                final int numOfPoints = categories.length;
                final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
                final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
                final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
                final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
                final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);               
                final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
                XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
                XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
                series1.setTitle("a",chart.setSheetTitle("a", 1));

                 //XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
                //series2.setTitle("b",chart.setSheetTitle("b", 2)); 

                bar.setVaryColors(true);
                bar.setBarDirection(BarDirection.COL);
                chart.plot(bar);

                XDDFChartLegend legend = chart.getOrAddLegend();
                legend.setPosition(LegendPosition.LEFT);
               // legend.setOverlay(false);
               try (OutputStream out = new FileOutputStream("C:/Users/lyf/Desktop/barExample.docx")) {
                    doc.write(out);
                }
            }
            catch(Exception e)
            {  
            }   
    }

推荐答案

主要问题是将 setVaryColors 设置为 true 意味着:

The main problem is that setting setVaryColors to true means the following:

如果仅一个系列,则为该系列的每个数据点改变颜色.然后,图例显示了变化的数据点,而不是序列.如果不止一个系列,请为每个系列改变颜色.然后,图例显示了变化的序列.

If only one series, then do varying the colors for each data point of the series. Then the legend shows the varying data points instead of the series. If more than one series, then do varying the colors for each series. Then the legend shows the varying series.

因此,如果仅存在一个系列,则需要将 setVaryColors 设置为 false .

So we need set setVaryColors to false if only one series is present.

但是另外,我们需要设置 AxisCrossBetween ,因此左轴与类别之间的类别轴交叉.其他的第一个和最后一个类别恰好在交叉点上,条形图只有一半可见.

But additional we need 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.

最后, XDDF 目前仅准备就绪一半,并且存在许多错误.例如, XDDFChart.setSheetTitle 是越野车.它创建一个表,但只有一半且不完整.创建该不完整的表后,Excel无法打开工作簿.因此无法在Word中更新图表数据.

And at last, XDDF is only half ready at the moment and there are many bugs. For example XDDFChart.setSheetTitle is buggy. It creates a Table but only half way and incomplete. Excel cannot opening the workbook after creating that incomplete Table. So updating the chart data in Word is not possible.

以下代码对我有用,并且可以创建只有一个系列以及两个系列的图表.另外,我尝试通过一步来使代码更加结构化.每个步骤都对其操作进行评论.

The following code works for me and can create a chart with only one series as well as with two. Additional I have tried making the code more structured in single steps. Each step is commented on what it is doing.

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);
   }
  }
 }
}

这篇关于POI条形图生成一个系列有问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆