如何在Java应用程序中动态地在excel报告中包含仪表图
我打算从我的应用程序下载excel报告 单击excel上的下载按钮,将生成报告。这项措施的实施没有引起太多关注。然而,下一个要求是我正在努力寻找答案。我的要求是在excel文档中包括仪表图表,如下所示。我无法在ApachePOI中看到同样的规定。这将有助于获得一些指针如何在Java应用程序中动态地在excel报告中包含仪表图,java,excel,graph,charts,apache-poi,Java,Excel,Graph,Charts,Apache Poi,我打算从我的应用程序下载excel报告 单击excel上的下载按钮,将生成报告。这项措施的实施没有引起太多关注。然而,下一个要求是我正在努力寻找答案。我的要求是在excel文档中包括仪表图表,如下所示。我无法在ApachePOI中看到同样的规定。这将有助于获得一些指针 Microsoft Excel不提供仪表图表。您的屏幕截图显示的是甜甜圈图和饼图的组合 在图中,甜甜圈图有每个仪表段的数据点(段),最后一段的数据点(段)填满整圈。第一段根据需要着色(例如红色、黄色、绿色),而最后一段不可见(隐
Microsoft Excel
不提供仪表图表。您的屏幕截图显示的是甜甜圈图和饼图的组合
在图中,甜甜圈图有每个仪表段的数据点(段),最后一段的数据点(段)填满整圈。第一段根据需要着色(例如红色、黄色、绿色),而最后一段不可见(隐藏)。所以它看起来像一个半圆的油炸圈饼
饼图包含指针位置、指针厚度和最后一个填充到整圈的数据点(段)。第一个数据点的值决定指针位置。第一段和最后一段不可见(隐藏)。只有指针厚度的部分是可见的,并且指针的显示方式是彩色的
Apache-poi
在当前版本Apache-poi 5.0.0
中提供了甜甜圈图和饼图。不幸的是,XDDFDoughnutChartData
到目前为止还不完整。它缺乏设置孔尺寸和第一层角度的方法。因此,虽然可以使用默认的XDDF
方法创建圆环图,但需要额外的方法来设置孔大小和第一个切片角度。在这种情况下,设置第一个切片角度是必要的,因为它需要270度才能在正确的位置显示半圆图
下面是一个完整的示例,显示了上述内容
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.XDDFNoFillProperties;
import org.apache.poi.xddf.usermodel.XDDFLineProperties;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class DoughnutAndPieChart {
//method to get shape properties from XDDFChart
private static XDDFShapeProperties getOrAddChartSpaceShapeProperties(XDDFChart chart) {
if (chart.getCTChartSpace().getSpPr() == null) chart.getCTChartSpace().addNewSpPr();
return new XDDFShapeProperties(chart.getCTChartSpace().getSpPr());
}
//XDDFDoughnutChartData lacks method setHoleSize. This provides such method for CTDoughnutChart.
private static void setHoleSize(org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart chart, Short size) {
if (size == null) {
if (chart.isSetHoleSize()) {
chart.unsetHoleSize();
}
} else {
if (size < 0 || 100 < size) {
throw new IllegalArgumentException("size must be between 0 and 100");
}
if (chart.isSetHoleSize()) {
chart.getHoleSize().setVal(size);
} else {
chart.addNewHoleSize().setVal(size);
}
}
}
//XDDFDoughnutChartData lacks method setFirstSliceAngle. This provides such method for CTDoughnutChart
private static void setFirstSliceAngle(org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart chart, Integer angle) {
if (angle == null) {
if (chart.isSetFirstSliceAng()) {
chart.unsetFirstSliceAng();
}
} else {
if (angle < 0 || 360 < angle) {
throw new IllegalArgumentException("angle must be between 0 and 360");
}
if (chart.isSetFirstSliceAng()) {
chart.getFirstSliceAng().setVal(angle);
} else {
chart.addNewFirstSliceAng().setVal(angle);
}
}
}
public static void main(String[] args) throws IOException {
try (XSSFWorkbook wb = new XSSFWorkbook()) {
XSSFSheet sheet = wb.createSheet("gauge chart");
//set data
Row row;
row = sheet.createRow(0);
row.createCell(0).setCellValue("Ptr.Pos.:");
row.createCell(1).setCellValue(75); // cell B1 is pointer position = first pie chart segment
row = sheet.createRow(1);
row.createCell(0).setCellValue("Ptr.Thickn.:");
row.createCell(1).setCellValue(1); // cell B2 is pointer thickness = second pie chart segment
row = sheet.createRow(2);
row.createCell(0).setCellValue("Helper:");
row.createCell(1).setCellFormula("200-B1-B2"); // cell B3 is helper formula needed to calculate third pie chart segment size up to full circle
row = sheet.createRow(3);
row.createCell(0).setCellValue("Helper:"); // row 4 is needed as chart will have 4 categories; needs more when more categories used
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 6, 5, 20);
XSSFChart chart = drawing.createChart(anchor);
//set chart's background to no fill and no line
XDDFShapeProperties shapeProperties = getOrAddChartSpaceShapeProperties(chart);
shapeProperties.setFillProperties(new XDDFNoFillProperties());
shapeProperties.setLineProperties(new XDDFLineProperties(new XDDFNoFillProperties()));
//data source for categories
XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromArray(new String[]{"1", "2", "3", "4"});
//doughnut chart = three segments (red yellow, green) plus one segment to be invisible (hidden)
XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromArray(new Double[]{25d, 50d, 25d, 100d});
XDDFChartData data = chart.createData(ChartTypes.DOUGHNUT, null, null);
data.setVaryColors(true);
XDDFChartData.Series series = data.addSeries(cat, val);
chart.plot(data);
//set hole size and first slice angle for the doughnut chart
setHoleSize(chart.getCTChart().getPlotArea().getDoughnutChartArray(0), (short)50);
setFirstSliceAngle(chart.getCTChart().getPlotArea().getDoughnutChartArray(0), 270);
//set data point (segments) color
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(0);
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDPtArray(0)
.addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{(byte)255, 0, 0}); //red
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(1);
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDPtArray(1)
.addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{(byte)255, (byte)255, 0}); //yellow
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(2);
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDPtArray(2)
.addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{0, (byte)255, 0}); //green
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(3);
chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).getDPtArray(3).addNewSpPr().addNewNoFill(); //invisible (hidden)
//pie chart = segments: pointer position, pointer thickness, up to full circle
val = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 3, 1, 1));
data = chart.createData(ChartTypes.PIE, null, null);
data.setVaryColors(true);
((XDDFPieChartData)data).setFirstSliceAngle(270);
series = data.addSeries(cat, val);
chart.plot(data);
//correct the id and order, must not start 0 again because there is a doughnut series already
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getIdx().setVal(1);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getOrder().setVal(1);
//set data point (segments) color
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(0);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDPtArray(0).addNewSpPr().addNewNoFill(); //invisible (hidden)
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(1);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDPtArray(1)
.addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(new byte[]{0, 0, 0}); //black
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(2);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDPtArray(2).addNewSpPr().addNewNoFill(); //invisible (hidden)
//write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("ooxml-doughnut-and-pie-chart.xlsx")) {
wb.write(fileOut);
}
}
}
}
import java.io.FileOutputStream;
导入java.io.IOException;
导入org.apache.poi.ss.usermodel.Cell;
导入org.apache.poi.ss.usermodel.Row;
导入org.apache.poi.ss.util.CellRangeAddress;
导入org.apache.poi.xddf.usermodel.XDDFNoFillProperties;
导入org.apache.poi.xddf.usermodel.XDDFLineProperties;
导入org.apache.poi.xddf.usermodel.XDDFShapeProperties;
导入org.apache.poi.xddf.usermodel.chart.XDDFChart;
导入org.apache.poi.xddf.usermodel.chart.XDDFChartData;
导入org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
导入org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
导入org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
导入org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
导入org.apache.poi.xddf.usermodel.chart.ChartTypes;
导入org.apache.poi.xssf.usermodel.XSSFChart;
导入org.apache.poi.xssf.usermodel.XSSFClientAnchor;
导入org.apache.poi.xssf.usermodel.XSSFDrawing;
导入org.apache.poi.xssf.usermodel.xssfheet;
导入org.apache.poi.xssf.usermodel.xssf工作簿;
公共类油炸圈饼{
//方法从XDDFChart获取形状属性
私有静态XDDFShapeProperties GetOradChartSpaceShapeProperties(XDDFChart图表){
if(chart.getCTChartSpace().getSpPr()==null)chart.getCTChartSpace().addnewspr();
返回新的XDDFShapeProperties(chart.getCTChartSpace().getSpPr());
}
//XDDFDoughnutChartData缺少方法setHoleSize。这为CTDoughnutChart提供了此类方法。
私有静态void setHoleSize(org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart图表,短尺寸){
如果(大小==null){
if(chart.isSetHoleSize()){
chart.unsetHoleSize();
}
}否则{
如果(尺寸<0 | | 100<尺寸){
抛出新的IllegalArgumentException(“大小必须介于0和100之间”);
}
if(chart.isSetHoleSize()){
chart.getHoleSize().setVal(大小);
}否则{
chart.addNewHoleSize().setVal(大小);
}
}
}
//XDDFDoughnutChartData缺少方法setFirstSliceAngle。这为CTDoughnutChart提供了此类方法
私有静态void setFirstSliceAngle(org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart图表,整数角度){
如果(角度==null){
if(chart.isSetFirstSliceAng()){
chart.ang();
}
}否则{
如果(角度<0 | | 360<角度){
抛出新的IllegalArgumentException(“角度必须介于0和360之间”);
}
if(chart.isSetFirstSliceAng()){
chart.getFirstSliceAng().setVal(角度);
}否则{
chart.addNewFirstSliceAng().setVal(角度);
}
}
}
公共静态void main(字符串[]args)引发IOException{
尝试(XSSFWorkbook wb=new XSSFWorkbook()){
XSSFSheet sheet=wb.createSheet(“仪表图”);
//设置数据
行行;
行=工作表。创建行(0);
row.createCell(0).setCellValue(“Ptr.Pos:”);
row.createCell(1).setCellValue(75);//单元格B1是指针位置=第一个饼图段
行=工作表。创建行(1);
row.createCell(0.setCellValue(“Ptr.Thickn.:”);
row.createCell(1).setCellValue(1);//单元格B2是指针厚度=第二个饼图段
行=工作表。创建行(2);
createCell(0).setCellValue(“Helper:”);
row.createCell(1).setCellFormula(“200-B1-B2”);//单元格B3是计算第三个饼图段大小(最大为整圈)所需的辅助公式
行=工作表。创建行(3);
row.createCell(0).setCellValue(“Helper:”);//需要第4行,因为图表将有4个类别;使用更多类别时需要更多类别
XSSFDrawing=sheet.createdrawingparhical();
XSSFClientAnchor-anchor=drawing.createAnchor(0,0,0,0,6,5,20);
XSSFChart chart=drawing.createChart(锚定);
//将图表背景设置为无填充和无线条
XDDFShapeProperties shapeProperties=GetOradChartSpaceShapeProperties(图表);
setFillProperties(新的XDDFNoFillProperties());
shapeProperties.setLineProp