Поколение Excel [Java] - BarChart - Включить метку нескольких категорий - PullRequest
0 голосов
/ 18 апреля 2020

У меня генерация Excel с использованием библиотеки org. apache .poi. Здесь мне нужно сгенерировать гистограмму, которая должна выглядеть следующим образом:

enter image description here И мой Excel выглядит так:

enter image description here

Код:

    //CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol)
    XDDFDataSource<String> department = XDDFDataSourcesFactory.fromStringCellRange(sheet,
            new CellRangeAddress(7, 17, 1, 1));

Если я установил CellRangeAddress firstCol - 0 и lastCol - 1, он не работает?

Есть ли возможность включить это в java:

enter image description here

1 Ответ

0 голосов
/ 18 апреля 2020

Многоуровневые метки категорий невозможны при использовании XDDF poi apache poi. XDDF всегда использует StrRef в качестве ссылок для источников данных диаграммы. Для создания многоуровневых меток категорий необходимо использовать MultiLvlStrRef. Таким образом, задача может быть решена только с использованием низкоуровневых классов org.openxmlformats.schemas.drawingml.x2006.chart.*.

Именно поэтому для следующего кода требуется полный jar всех ooxml-schemas, то есть ooxml-schemas-1.4.jar для текущего apache poi 4.1.2 в путь к классу. poi-ooxml-schemas-4.1.2.jar не содержит org.openxmlformats.schemas.drawingml.x2006.chart.CTMultiLvlStrRef.

И из-за грубых логик c из Microsoft, который использует настройку NoMultiLvlLbl - true в качестве значения по умолчанию для осей категорий, один Теперь необходимо сообщить оси категорий, что она не не имеет многоуровневых меток. Таким образом, если ось имеет многоуровневые метки категорий, NoMultiLvlLbl должно быть установлено false. Похоже, Microsoft хочет проверить, хорошо ли программисты усвоили свои логи c уроки; -).

Полный пример:

import java.io.FileOutputStream;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xssf.usermodel.*;

import org.openxmlformats.schemas.drawingml.x2006.chart.*;

public class BarChartMultiLevelCategories {

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

  String[] series = new String[]{"January","February","March"};
  String[] charges = new String[]{"Charges not Tally","Deposit","High Charges", "Quotation"};
  String[] treatment = new String[]{"Diagnosis","Explanation","Procedure"};
  String[] behaviour = new String[]{"Miscommunication","Not Attentive","Not Friendly", "Rude"};
  Double[][] values = new Double[][]{
   new Double[]{1d, 2d, 3d},
   new Double[]{1d, 3d, 2d},
   new Double[]{2d, 1d, 3d},
   new Double[]{2d, 3d, 1d},
   new Double[]{3d, 1d, 2d},
   new Double[]{3d, 2d, 1d},
   new Double[]{1d, 2d, 3d},
   new Double[]{1d, 3d, 2d},
   new Double[]{2d, 1d, 3d},
   new Double[]{2d, 3d, 1d},
   new Double[]{3d, 1d, 2d},
  };

  try (XSSFWorkbook wb = new XSSFWorkbook()) {
   //the sheet for the chart
   XSSFSheet chartSheet = wb.createSheet("barchart");
   //the sheet for the data
   XSSFSheet dataSheet = wb.createSheet("data");

   Row row;
   Cell cell;
   row = dataSheet.createRow(0);
   for (int i = 0; i < series.length; i++) {
    cell = row.createCell(i+2); cell.setCellValue(series[i]);
   }
   for (int i = 0; i < charges.length; i++) {
    row = dataSheet.createRow(i+1);
    if (i == 0) { cell = row.createCell(0); cell.setCellValue("Charges"); }
    cell = row.createCell(1); cell.setCellValue(charges[i]);
   }
   dataSheet.addMergedRegion(new CellRangeAddress(1, charges.length, 0, 0));
   for (int i = 0; i < treatment.length; i++) {
    row = dataSheet.createRow(i+1+charges.length);
    if (i == 0) { cell = row.createCell(0); cell.setCellValue("Treatment"); }
    cell = row.createCell(1); cell.setCellValue(treatment[i]);
   }
   dataSheet.addMergedRegion(new CellRangeAddress(1+charges.length, charges.length+treatment.length, 0, 0));
   for (int i = 0; i < behaviour.length; i++) {
    row = dataSheet.createRow(i+1+charges.length+treatment.length);
    if (i == 0) { cell = row.createCell(0); cell.setCellValue("Behaviour"); }
    cell = row.createCell(1); cell.setCellValue(behaviour[i]);
   }
   dataSheet.addMergedRegion(
   new CellRangeAddress(1+charges.length+treatment.length, charges.length+treatment.length+behaviour.length, 0, 0));
   for (int i = 0; i < values.length; i++) {
    Double[] valuesRow = values[i];
    row = dataSheet.getRow(i+1);
    for (int j = 0; j < valuesRow.length; j++) {
     cell = row.createCell(j+2); cell.setCellValue(valuesRow[j]);
    }
   }

   XSSFDrawing drawing = chartSheet.createDrawingPatriarch();
   XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 10, 20);

   XSSFChart chart = drawing.createChart(anchor);
   chart.setTitleText("Chart title");
   chart.setTitleOverlay(false);
   //do not auto delete the title; is necessary for showing title in Calc
   if (chart.getCTChart().getAutoTitleDeleted() == null) chart.getCTChart().addNewAutoTitleDeleted();
   chart.getCTChart().getAutoTitleDeleted().setVal(false);

   XDDFChartLegend legend = chart.getOrAddLegend();
   legend.setPosition(LegendPosition.RIGHT);

   CTChart ctChart = chart.getCTChart();
   CTPlotArea ctPlotArea = ctChart.getPlotArea();
   CTBarChart ctBarChart = ctPlotArea.addNewBarChart();
   CTBoolean ctBoolean = ctBarChart.addNewVaryColors();
   ctBoolean.setVal(true);
   ctBarChart.addNewBarDir().setVal(STBarDir.COL);

   //telling the BarChart that it has axes and giving them Ids
   ctBarChart.addNewAxId().setVal(123456);
   ctBarChart.addNewAxId().setVal(123457);

   //cat axis
   CTCatAx ctCatAx = ctPlotArea.addNewCatAx(); 
   ctCatAx.addNewAxId().setVal(123456); //id of the cat axis
   CTScaling ctScaling = ctCatAx.addNewScaling();
   ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
   ctCatAx.addNewDelete().setVal(false);
   ctCatAx.addNewAxPos().setVal(STAxPos.B);
   ctCatAx.addNewCrossAx().setVal(123457); //id of the val axis
   ctCatAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);

   //telling the category axis that it not has no multi level labels ;-)
   ctCatAx.addNewNoMultiLvlLbl().setVal(false);

   //val axis
   CTValAx ctValAx = ctPlotArea.addNewValAx(); 
   ctValAx.addNewAxId().setVal(123457); //id of the val axis
   ctScaling = ctValAx.addNewScaling();
   ctScaling.addNewOrientation().setVal(STOrientation.MIN_MAX);
   ctValAx.addNewDelete().setVal(false);
   ctValAx.addNewAxPos().setVal(STAxPos.L);
   ctValAx.addNewCrossAx().setVal(123456); //id of the cat axis
   ctValAx.addNewTickLblPos().setVal(STTickLblPos.NEXT_TO);

   //series
   byte[][] seriesColors = new byte[][] {
    new byte[]{(byte)255, 0, 0}, //red
    new byte[]{0, (byte)255, 0}, //green
    new byte[]{0, 0, (byte)255}  //blue
   };
   for (int i = 0; i < series.length; i++) {
    CTBarSer ctBarSer = ctBarChart.addNewSer();
    CTSerTx ctSerTx = ctBarSer.addNewTx();
    CTStrRef ctStrRef = ctSerTx.addNewStrRef();
    ctStrRef.setF(
     new CellRangeAddress(0, 0, i+2, i+2)
          .formatAsString(dataSheet.getSheetName(), true)); //data!R1C(i+2)
    ctBarSer.addNewIdx().setVal(i);  

    CTAxDataSource cttAxDataSource = ctBarSer.addNewCat();
    //do using MultiLvlStrRef instead of StrRef 
    CTMultiLvlStrRef ctMultiLvlStrRef = cttAxDataSource.addNewMultiLvlStrRef();
    ctMultiLvlStrRef.setF(
     new CellRangeAddress(1, charges.length+treatment.length+behaviour.length, 0, 1)
          .formatAsString(dataSheet.getSheetName(), true)); //data!$A$2:$B$12

    CTNumDataSource ctNumDataSource = ctBarSer.addNewVal();
    CTNumRef ctNumRef = ctNumDataSource.addNewNumRef();
    ctNumRef.setF(
     new CellRangeAddress(1, charges.length+treatment.length+behaviour.length, i+2, i+2)
          .formatAsString(dataSheet.getSheetName(), true)); //data!R2C(i+2):R12C(i+2)

    ctBarSer.addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(seriesColors[i]);   

   } 

   try (FileOutputStream fileOut = new FileOutputStream("ooxml-bar-chart.xlsx")) {
    wb.write(fileOut);
   }
  }
 }
}
...