Гистограмма POI генерировать одну серию имеет вопрос - PullRequest
1 голос
/ 09 мая 2019

Я использую JDK8 и POI-4.1.0, используйте их пример здесь ссылка

экспортируйте диаграмму в Word. Когда создать две серии в порядке две серии img , но я создаю только одну серию. Категория ошибки диаграммы для серии одна серия img

"lang1" "lang2" "lang3" - это имя категории, но они становятся именами серий.У меня нет идеала.Я также нахожу, что у графика использования есть та же самая проблема, мой код
    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)
            {  
            }   
    }

1 Ответ

0 голосов
/ 10 мая 2019

Основная проблема в том, что установка setVaryColors в true означает следующее:

Если только одна серия, то меняйте цвета для каждой точки данных серии. Тогда легенда показывает различные точки данных вместо ряда. Если более одной серии, то делайте разные цвета для каждой серии. Тогда легенда показывает различные серии.

Поэтому нам нужно установить setVaryColors в false, если присутствует только одна серия.

Но дополнительно нам нужно установить AxisCrossBetween, чтобы левая ось пересекала ось категорий между категориями. Еще одна первая и последняя категории находятся точно в точках пересечения, а столбцы видны только наполовину.

И, наконец, XDDF на данный момент готов только наполовину, и есть много ошибок. Например XDDFChart.setSheetTitle глючит. Это создает Таблицу, но только наполовину и неполно. Excel не может открыть книгу после создания этой неполной таблицы. Поэтому обновление данных диаграммы в Word невозможно.

Следующий код работает для меня и может создать диаграмму только с одной серией, а также с двумя. Дополнительно я попытался сделать код более структурированным за один шаг. Каждый шаг комментируется тем, что он делает.

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);
   }
  }
 }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...