Многоуровневые метки категорий невозможны при использовании 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);
}
}
}
}