问题
I have a requirement to color the different data points in an Excel sunburst chart programatically. By default, Excel creates the chart looking like this.
I need to be able to make something like this.
I've been able to load the chart and series, what I have not been able to work out is how to get to each of the points and change the fill color, and is that even possible.
The data to create this chart is :
Level 1,Level 2,Level 3,Series 1
A,A.a,A.a.1,5
A,A.a,A.a.2,5
A,A.b,A.b.1,5
A,A.b,A.b.2,5
B,B.a,B.a.1,5
B,B.a,B.a.2,5
B,B.b,B.b.1,5
B,B.b,B.b.2,5
C,C.a,C.a.1,5
C,C.a,C.a.2,5
C,C.b,C.b.1,5
C,C.b,C.b.2,5
My code so far
import java.io.IOException;
import java.util.List;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
public class Format {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
XSSFWorkbook xwb = new XSSFWorkbook("ChartExample.xlsx");
XSSFSheet sheet = xwb.getSheetAt(0);
System.out.println("Loaded sheet is " + sheet.getSheetName());
XSSFDrawing drawing = sheet.getDrawingPatriarch();
List <XSSFChart> charts = drawing.getCharts();
System.out.println("No of Charts " + charts.size());
XSSFChart chart = charts.get(0);
List<XDDFChartData> series = chart.getChartSeries();
System.out.println("No of Data Series " + series.size());
XDDFChartData data = series.get(0);
// How do I now get to the data points and then set the fill color for that point?
xwb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
How do I now get to the say Point C.b.1 and set it's fill color to red?
Thanks in advance.
回答1:
If the goal is really to modify an Excel
sunburst chart, then getting the sunburst chart XML will only be possible very low level by parsing the XML directly.
You even will not get the sunburst chart using List <XSSFChart> charts = drawing.getCharts();
. A sunburst chart is not a XSSFChart
. XSSFChart
is of type application/vnd.openxmlformats-officedocument.drawingml.chart+xml
while sunburst chart is of type application/vnd.ms-office.chartex+xml
. This is because the sunburst chart is an extended chart type which is not available in versions of Office Open XML up to year 2007. But those old versions of Office Open XML is what apache poi
is developed on.
But we can using at least parts of apache poi
and must programming the XSSFChartEx
class instead the XSSFChart
our own then. Unfortunately also a class XSSFChartExRelation
is needed because such an relation class of course also not exists already.
Example:
Excel source:
Code:
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ooxml.POIXMLRelation;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import javax.xml.namespace.QName;
public class FormatSunBurstChart {
private static void setDataPointColor(XmlObject series, int number, String colorHex) {
XmlCursor cursor = series.newCursor();
cursor.toLastChild();
cursor.beginElement(new QName("http://schemas.microsoft.com/office/drawing/2014/chartex", "dataPt", "cx"));
cursor.insertAttributeWithValue("idx", "" + number);
cursor.beginElement(new QName("http://schemas.microsoft.com/office/drawing/2014/chartex", "spPr", "cx"));
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "solidFill", "a"));
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "srgbClr", "a"));
cursor.insertAttributeWithValue("val", colorHex);
cursor.dispose();
}
public static void main(String[] args) {
try {
XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream("ChartExample.xlsx"));
XSSFSheet sheet = workbook.getSheetAt(0);
System.out.println("Loaded sheet is " + sheet.getSheetName());
XSSFDrawing drawing = sheet.getDrawingPatriarch();
if (drawing != null) {
for (POIXMLDocumentPart dpart : drawing.getRelations()) {
PackagePart ppart = dpart.getPackagePart();
if ("application/vnd.ms-office.chartex+xml".equals(ppart.getContentType())) {
XSSFChartEx xssfChartEx = new XSSFChartEx(ppart);
String rId = drawing.getRelationId(dpart);
drawing.addRelation(
rId,
new XSSFChartExRelation(
"application/vnd.ms-office.chartex+xml",
"http://schemas.microsoft.com/office/2014/relationships/chartEx",
"/xl/charts/chartEx#.xml"),
xssfChartEx
);
XmlObject series = xssfChartEx.getSeries(0);
setDataPointColor(series, 1, "FF0000");
setDataPointColor(series, 2, "FFFF00");
setDataPointColor(series, 3, "00FF00");
setDataPointColor(series, 14, "FFFF00");
setDataPointColor(series, 16, "00FF00");
setDataPointColor(series, 18, "00FF00");
setDataPointColor(series, 19, "FF0000");
setDataPointColor(series, 20, "00FF00");
System.out.println(series);
}
}
}
FileOutputStream out = new FileOutputStream("ChartExampleChanged.xlsx");
workbook.write(out);
workbook.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static class XSSFChartEx extends POIXMLDocumentPart {
private XmlObject chartExXmlObject;
private XSSFChartEx(PackagePart part) throws Exception {
super(part);
chartExXmlObject = XmlObject.Factory.parse(part.getInputStream());
}
private XmlObject getChartExXmlObject() {
return chartExXmlObject;
}
private XmlObject getSeries(int number) {
XmlObject[] result = chartExXmlObject.selectPath(
"declare namespace cx='http://schemas.microsoft.com/office/drawing/2014/chartex' " +
".//cx:chart/cx:plotArea/cx:plotAreaRegion/cx:series"
);
return result[number];
}
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
chartExXmlObject.save(out);
out.close();
}
}
private static class XSSFChartExRelation extends POIXMLRelation {
private XSSFChartExRelation(String type, String rel, String defaultName) {
super(type, rel, defaultName);
}
}
}
Note: apache poi
version 4.0.0
is used here.
Excel result:
来源:https://stackoverflow.com/questions/52324851/how-to-change-the-graphical-attributes-of-a-point-in-an-excel-sunburst-chart-thr