javams-wordapache-poibar-chart

I am trying to create bar chart on the word document using Apache POI. I am unable to open the word document even though file was successful


I have successfully able to create a word document using the below code but i am unable to open the created word document. I am new to Apache poi, java and web development and any help would be appreciated.

import java.io.FileOutputStream;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;

public class BarChart {
public static void main(String[] args) throws Exception {
     XWPFDocument doc = new XWPFDocument();

    // Create a paragraph
            XWPFParagraph paragraph = doc.createParagraph();
            XWPFRun run = paragraph.createRun();
            run.setText("Bar Chart Example:");

    // Create a severitychart
            XWPFChart categoryChart = doc.createChart(10 * Units.EMU_PER_CENTIMETER, 5 * 
    Units.EMU_PER_CENTIMETER);

    // Create chart data source
            String[] categories = new String[]{"Critical", "High", "Medium","Low","Best Practice"};
            Double[] values = new Double[]{(double) 1,(double) 2,(double) 3,(double) 4,(double) 5};
            XDDFDataSource<String> categoryDataSource = 
    XDDFDataSourcesFactory.fromArray(categories);
            XDDFNumericalDataSource<Double> valueDataSource = 
    XDDFDataSourcesFactory.fromArray(values);
         
 // Create the category axis
         XDDFCategoryAxis categoryAxis = categoryChart.createCategoryAxis(AxisPosition.BOTTOM);
         XDDFValueAxis valueAxis = categoryChart.createValueAxis(AxisPosition.TOP);
 
         XDDFChartData data = categoryChart.createData(ChartTypes.BAR,  categoryAxis, valueAxis);
    
    //categoryChart.setTitleText("Evoke");
    XDDFChartData.Series series = data.addSeries(categoryDataSource, valueDataSource);
    //series.setTitle("Fruit Sales", null);

    // Plot the chart
    categoryChart.plot(data);
    
    // Save the document
    FileOutputStream out = new FileOutputStream("bar_chart_document.docx");
    doc.write(out);
    out.close();
    doc.close();

    System.out.println("chart created successfully!");
}

}


Solution

  • Main issue is that series title of charts is not optional. Each series needs a title to prepare legends.

    So if you uncomment:

    ...
    //series.setTitle("Fruit Sales", null);
    ...
    

    a series title will be set and you should be able to open the file in Microsoft Word.

    But a few more hints:

    Set how the axis cross - for example at zero point of value axis: valueAxis.setCrosses(AxisCrosses.AUTO_ZERO).

    Set AxisCrossBetween, so the value 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: valueAxis.setCrossBetween(AxisCrossBetween.BETWEEN).

    Set bar direction to either BarDirection.BAR or BarDirection.COL.

    Set series fill color - necessary for LibreOffice as this will not use default colors.

    Minimal complete example for a bar chart in Word:

    import java.io.FileOutputStream;
    import org.apache.poi.util.Units;
    import org.apache.poi.xddf.usermodel.*;
    import org.apache.poi.xddf.usermodel.chart.*;
    import org.apache.poi.xwpf.usermodel.*;
    
    public class BarChartWordMinimal {
        
     public static void main(String[] args) throws Exception {
      XWPFDocument doc = new XWPFDocument();
    
      // Create some normal XWPF content 
      XWPFParagraph paragraph = doc.createParagraph();
      XWPFRun run = paragraph.createRun();
      run.setText("Bar Chart Example:");
     
      // Create the chart
      XWPFChart categoryChart = doc.createChart(10 * Units.EMU_PER_CENTIMETER, 5 * Units.EMU_PER_CENTIMETER);
    
      // Create chart data sources
      String[] categories = new String[]{"Critical", "High", "Medium","Low","Best Practice"};
      Double[] values = new Double[]{(double) 1,(double) 2,(double) 3,(double) 4,(double) 5};
      XDDFDataSource<String> categoryDataSource = XDDFDataSourcesFactory.fromArray(categories);
      XDDFNumericalDataSource<Double> valueDataSource = XDDFDataSourcesFactory.fromArray(values);
             
      // Create the category axis
      XDDFCategoryAxis categoryAxis = categoryChart.createCategoryAxis(AxisPosition.BOTTOM);
      
      // Create the value axis  - axis position top is illogical for value axis but will not lead to error
      //XDDFValueAxis valueAxis = categoryChart.createValueAxis(AxisPosition.TOP);
      XDDFValueAxis valueAxis = categoryChart.createValueAxis(AxisPosition.LEFT);
      
      // Set how the axis cross - for example at zero point of value axis
      valueAxis.setCrosses(AxisCrosses.AUTO_ZERO);
      
      // Set AxisCrossBetween, so the value 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.
      valueAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
    
      XDDFChartData data = categoryChart.createData(ChartTypes.BAR,  categoryAxis, valueAxis);
      // Set bar direction
      //((XDDFBarChartData)data).setBarDirection(BarDirection.BAR);   
      ((XDDFBarChartData)data).setBarDirection(BarDirection.COL);   
      
      // Set chart title - optinal
      categoryChart.setTitleText("Evoke");
      
      // Add series
      XDDFChartData.Series series = data.addSeries(categoryDataSource, valueDataSource);
      
      // Set series title - not optional 
      series.setTitle("Fruit Sales", null);
    
      // Set series fill color - necessary for LibreOffice as this will not use default colors
      solidFillSeries(series, PresetColor.BLUE);
    
      // Plot the chart
      categoryChart.plot(data);
        
      // Save the document
      FileOutputStream out = new FileOutputStream("bar_chart_document.docx");
      doc.write(out);
      out.close();
      doc.close();
    
      System.out.println("chart created successfully!");
     }
     
     private static void solidFillSeries(XDDFChartData.Series series, PresetColor color) {
      XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
      XDDFShapeProperties properties = series.getShapeProperties();
      if (properties == null) {
       properties = new XDDFShapeProperties();
      }
      properties.setFillProperties(fill);
      series.setShapeProperties(properties);
     }
    }