mirror of https://github.com/apache/poi.git
[github-98] write data in respective Column in case of XDDFChart. Thanks to Sandeep Tiwari. This closes #98
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1825521 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2dff049db9
commit
24fee0c0d5
|
@ -0,0 +1,129 @@
|
|||
|
||||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.apache.poi.xwpf.usermodel.examples;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.POIXMLDocumentPart;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
|
||||
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
|
||||
import org.apache.poi.xddf.usermodel.chart.BarDirection;
|
||||
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
|
||||
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.xwpf.usermodel.XWPFChart;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
|
||||
/**
|
||||
* Build a bar chart from a template docx
|
||||
*/
|
||||
public class BarChartExampleDOCX {
|
||||
private static void usage(){
|
||||
System.out.println("Usage: BarChartDemo <bar-chart-template.docx> <bar-chart-data.txt>");
|
||||
System.out.println(" bar-chart-template.docx template with a bar chart");
|
||||
System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
|
||||
"then go pairs {axis-label value}");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileInputStream argIS = new FileInputStream(args[0]);
|
||||
BufferedReader modelReader = new BufferedReader(new FileReader(args[1]))) {
|
||||
|
||||
String chartTitle = modelReader.readLine(); // first line is chart title
|
||||
|
||||
// Category Axis Data
|
||||
List<String> listCategories = new ArrayList<String>(3);
|
||||
|
||||
// Values
|
||||
List<Double> listValues = new ArrayList<Double>(3);
|
||||
|
||||
// set model
|
||||
String ln;
|
||||
while((ln = modelReader.readLine()) != null){
|
||||
String[] vals = ln.split("\\s+");
|
||||
listCategories.add(vals[0]);
|
||||
listValues.add(Double.valueOf(vals[1]));
|
||||
}
|
||||
String[] categories = listCategories.toArray(new String[listCategories.size()]);
|
||||
Double[] values = listValues.toArray(new Double[listValues.size()]);
|
||||
|
||||
try (XWPFDocument doc = new XWPFDocument(argIS)) {
|
||||
XWPFChart chart = doc.getCharts().get(0);
|
||||
setBarData(chart, chartTitle, categories, values);
|
||||
chart = doc.getCharts().get(1);
|
||||
setColumnData(chart, "Column variant");
|
||||
|
||||
// save the result
|
||||
try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) {
|
||||
doc.write(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Done");
|
||||
}
|
||||
|
||||
private static void setBarData(XWPFChart chart, String chartTitle, String[] categories, Double[] values) {
|
||||
final List<XDDFChartData> series = chart.getChartSeries();
|
||||
final XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
|
||||
|
||||
final int numOfPoints = categories.length;
|
||||
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
|
||||
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
|
||||
final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
|
||||
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange, 1);
|
||||
values[2] = 10.0;
|
||||
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values, valuesDataRange2, 2);
|
||||
bar.getSeries().get(0).replaceData(categoriesData, valuesData);
|
||||
bar.addSeries(categoriesData, valuesData2);
|
||||
bar.getSeries().get(0).setTitle(chartTitle, chart.setSheetTitle(chartTitle));
|
||||
chart.plot(bar);
|
||||
}
|
||||
|
||||
private static void setColumnData(XWPFChart chart, String chartTitle) {
|
||||
// Series Text
|
||||
List<XDDFChartData> series = chart.getChartSeries();
|
||||
XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
|
||||
bar.getSeries().get(0).setTitle(chartTitle, chart.setSheetTitle(chartTitle));
|
||||
|
||||
// in order to transform a bar chart into a column chart, you just need to change the bar direction
|
||||
bar.setBarDirection(BarDirection.COL);
|
||||
|
||||
// additionally, you can adjust the axes
|
||||
bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
|
||||
bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
My Bar or Column Chart
|
||||
First 1.0
|
||||
Second 3.0
|
||||
Third 4.0
|
Binary file not shown.
|
@ -21,6 +21,8 @@ package org.apache.poi.xddf.usermodel.chart;
|
|||
|
||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
@ -41,11 +43,14 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
|||
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.util.Beta;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.TempFile;
|
||||
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
@ -67,6 +72,9 @@ import org.openxmlformats.schemas.drawingml.x2006.chart.CTSurface;
|
|||
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns;
|
||||
|
||||
@Beta
|
||||
public abstract class XDDFChart extends POIXMLDocumentPart {
|
||||
|
@ -78,6 +86,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
|
||||
private int chartIndex = 0;
|
||||
|
||||
private POIXMLDocumentPart documentPart = null;
|
||||
|
||||
protected List<XDDFChartAxis> axes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
|
@ -412,8 +422,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
* @since POI 4.0.0
|
||||
*/
|
||||
public PackageRelationship createRelationshipInChart(POIXMLRelation chartRelation, POIXMLFactory chartFactory, int chartIndex) {
|
||||
POIXMLDocumentPart documentPart = createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart();
|
||||
documentPart.setCommited(true);
|
||||
documentPart = createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart();
|
||||
return this.addRelation(null, chartRelation, documentPart).getRelationship();
|
||||
}
|
||||
|
||||
|
@ -442,7 +451,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
* @since POI 4.0.0
|
||||
*/
|
||||
public void saveWorkbook(XSSFWorkbook workbook) throws IOException, InvalidFormatException {
|
||||
PackagePart worksheetPart = getWorksheetPart(true);
|
||||
PackagePart worksheetPart = getWorksheetPart();
|
||||
if (worksheetPart == null) {
|
||||
POIXMLRelation chartRelation = getChartRelation();
|
||||
POIXMLRelation chartWorkbookRelation = getChartWorkbookRelation();
|
||||
|
@ -454,6 +463,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
}
|
||||
}
|
||||
try (OutputStream xlsOut = worksheetPart.getOutputStream()) {
|
||||
setWorksheetPartCommitted();
|
||||
workbook.write(xlsOut);
|
||||
}
|
||||
}
|
||||
|
@ -490,9 +500,43 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
protected void fillSheet(XSSFSheet sheet, XDDFDataSource<?> categoryData, XDDFNumericalDataSource<?> valuesData) {
|
||||
int numOfPoints = categoryData.getPointCount();
|
||||
for (int i = 0; i < numOfPoints; i++) {
|
||||
XSSFRow row = sheet.createRow(i + 1); // first row is for title
|
||||
row.createCell(0).setCellValue(categoryData.getPointAt(i).toString());
|
||||
row.createCell(1).setCellValue(valuesData.getPointAt(i).doubleValue());
|
||||
XSSFRow row = this.getRow(sheet, i + 1); // first row is for title
|
||||
this.getCell(row, categoryData.getColIndex()).setCellValue(categoryData.getPointAt(i).toString());
|
||||
this.getCell(row, valuesData.getColIndex()).setCellValue(valuesData.getPointAt(i).doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method return row on given index
|
||||
* if row is null then create new row
|
||||
*
|
||||
* @param sheet current sheet object
|
||||
* @param index index of current row
|
||||
* @return this method return sheet row on given index
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
private XSSFRow getRow(XSSFSheet sheet,int index){
|
||||
if (sheet.getRow(index) != null) {
|
||||
return sheet.getRow(index);
|
||||
} else {
|
||||
return sheet.createRow(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method return cell on given index
|
||||
* if cell is null then create new cell
|
||||
*
|
||||
* @param row current row object
|
||||
* @param index index of current cell
|
||||
* @return this method return sheet cell on given index
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
private XSSFCell getCell(XSSFRow row,int index){
|
||||
if (row.getCell(index) != null) {
|
||||
return row.getCell(index);
|
||||
} else {
|
||||
return row.createCell(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,10 +581,33 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
*/
|
||||
public CellReference setSheetTitle(String title) {
|
||||
XSSFSheet sheet = getSheet();
|
||||
sheet.createRow(0).createCell(1).setCellValue(title);
|
||||
XSSFRow row = this.getRow(sheet, 0);
|
||||
XSSFCell cell = this.getCell(row, 1);
|
||||
cell.setCellValue(title);
|
||||
this.updateSheetTable(sheet.getTables().get(0).getCTTable(), title, 1);
|
||||
return new CellReference(sheet.getSheetName(), 0, 1, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method update column header of sheet into table
|
||||
*
|
||||
* @param ctTable xssf table object
|
||||
* @param title title of column
|
||||
* @param index index of column
|
||||
*/
|
||||
private void updateSheetTable(CTTable ctTable, String title, int index) {
|
||||
CTTableColumns tableColumnList = ctTable.getTableColumns();
|
||||
CTTableColumn column = null;
|
||||
if(tableColumnList.getCount() >= index) {
|
||||
column = tableColumnList.getTableColumnArray(index);
|
||||
}
|
||||
else {
|
||||
column = tableColumnList.addNewTableColumn();
|
||||
column.setId(index);
|
||||
}
|
||||
column.setName(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param range
|
||||
* @return
|
||||
|
@ -566,17 +633,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* default method for worksheet part
|
||||
*
|
||||
* @return return embedded worksheet part
|
||||
* @throws InvalidFormatException
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
private PackagePart getWorksheetPart() throws InvalidFormatException {
|
||||
return getWorksheetPart(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method is used to get worksheet part
|
||||
* if call is from saveworkbook method then check isCommitted
|
||||
|
@ -587,18 +643,24 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
* @throws InvalidFormatException
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
private PackagePart getWorksheetPart(boolean isCommitted) throws InvalidFormatException {
|
||||
private PackagePart getWorksheetPart() throws InvalidFormatException {
|
||||
for (RelationPart part : getRelationParts()) {
|
||||
if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) {
|
||||
if (isCommitted) {
|
||||
part.getDocumentPart().setCommited(true);
|
||||
}
|
||||
return getTargetPart(part.getRelationship());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setWorksheetPartCommitted() throws InvalidFormatException {
|
||||
for (RelationPart part : getRelationParts()) {
|
||||
if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) {
|
||||
part.getDocumentPart().setCommited(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the workbook object of embedded excel file
|
||||
* @throws IOException
|
||||
|
@ -631,7 +693,19 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
|
|||
* @since POI 4.0.0
|
||||
*/
|
||||
public void setWorkbook(XSSFWorkbook workbook) {
|
||||
this.workbook = workbook;
|
||||
File file;
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
file = TempFile.createTempFile("TempEmbedded",".xlsx");
|
||||
fos = new FileOutputStream(file);
|
||||
workbook.write(fos);
|
||||
fos.close();
|
||||
this.workbook = new XSSFWorkbook(file);
|
||||
} catch (IOException e) {
|
||||
|
||||
} catch (InvalidFormatException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,5 +31,7 @@ public interface XDDFDataSource<T> {
|
|||
|
||||
boolean isNumeric();
|
||||
|
||||
int getColIndex();
|
||||
|
||||
String getDataRangeReference();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,11 @@ public class XDDFDataSourcesFactory {
|
|||
public String getDataRangeReference() {
|
||||
return categoryDS.getStrRef().getF();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColIndex() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -110,6 +115,11 @@ public class XDDFDataSourcesFactory {
|
|||
public String getDataRangeReference() {
|
||||
return valuesDS.getNumRef().getF();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColIndex() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -121,6 +131,14 @@ public class XDDFDataSourcesFactory {
|
|||
return new StringArrayDataSource(elements, dataRange);
|
||||
}
|
||||
|
||||
public static <T extends Number> XDDFNumericalDataSource<T> fromArray(T[] elements, String dataRange, int col) {
|
||||
return new NumericalArrayDataSource<T>(elements, dataRange, col);
|
||||
}
|
||||
|
||||
public static XDDFCategoryDataSource fromArray(String[] elements, String dataRange, int col) {
|
||||
return new StringArrayDataSource(elements, dataRange, col);
|
||||
}
|
||||
|
||||
public static XDDFNumericalDataSource<Double> fromNumericCellRange(XSSFSheet sheet,
|
||||
CellRangeAddress cellRangeAddress) {
|
||||
return new NumericalCellRangeDataSource(sheet, cellRangeAddress);
|
||||
|
@ -133,12 +151,19 @@ public class XDDFDataSourcesFactory {
|
|||
private abstract static class AbstractArrayDataSource<T> implements XDDFDataSource<T> {
|
||||
private final T[] elements;
|
||||
private final String dataRange;
|
||||
private int col = 0;
|
||||
|
||||
public AbstractArrayDataSource(T[] elements, String dataRange) {
|
||||
this.elements = elements.clone();
|
||||
this.dataRange = dataRange;
|
||||
}
|
||||
|
||||
public AbstractArrayDataSource(T[] elements, String dataRange, int col) {
|
||||
this.elements = elements.clone();
|
||||
this.dataRange = dataRange;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPointCount() {
|
||||
return elements.length;
|
||||
|
@ -168,6 +193,11 @@ public class XDDFDataSourcesFactory {
|
|||
return dataRange;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColIndex() {
|
||||
return col;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NumericalArrayDataSource<T extends Number> extends AbstractArrayDataSource<T>
|
||||
|
@ -178,6 +208,10 @@ public class XDDFDataSourcesFactory {
|
|||
super(elements, dataRange);
|
||||
}
|
||||
|
||||
public NumericalArrayDataSource(T[] elements, String dataRange, int col) {
|
||||
super(elements, dataRange, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormatCode() {
|
||||
return formatCode;
|
||||
|
@ -194,6 +228,10 @@ public class XDDFDataSourcesFactory {
|
|||
public StringArrayDataSource(String[] elements, String dataRange) {
|
||||
super(elements, dataRange);
|
||||
}
|
||||
|
||||
public StringArrayDataSource(String[] elements, String dataRange, int col) {
|
||||
super(elements, dataRange, col);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class AbstractCellRangeDataSource<T> implements XDDFDataSource<T> {
|
||||
|
@ -220,6 +258,11 @@ public class XDDFDataSourcesFactory {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColIndex() {
|
||||
return cellRangeAddress.getFirstColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataRangeReference() {
|
||||
return cellRangeAddress.formatAsString(sheet.getSheetName(), true);
|
||||
|
@ -262,7 +305,7 @@ public class XDDFDataSourcesFactory {
|
|||
@Override
|
||||
public Double getPointAt(int index) {
|
||||
CellValue cellValue = getCellValueAt(index);
|
||||
if (cellValue != null && cellValue.getCellTypeEnum() == CellType.NUMERIC) {
|
||||
if (cellValue != null && cellValue.getCellType() == CellType.NUMERIC) {
|
||||
return Double.valueOf(cellValue.getNumberValue());
|
||||
} else {
|
||||
return null;
|
||||
|
@ -284,7 +327,7 @@ public class XDDFDataSourcesFactory {
|
|||
@Override
|
||||
public String getPointAt(int index) {
|
||||
CellValue cellValue = getCellValueAt(index);
|
||||
if (cellValue != null && cellValue.getCellTypeEnum() == CellType.STRING) {
|
||||
if (cellValue != null && cellValue.getCellType() == CellType.STRING) {
|
||||
return cellValue.getStringValue();
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -189,7 +189,7 @@ public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame<XSLFSh
|
|||
XSLFChart srcChart = (XSLFChart) src.getRelationById(id);
|
||||
XSLFChart chartCopy = slide.getSlideShow().createChart(slide);
|
||||
chartCopy.importContent(srcChart);
|
||||
chartCopy.saveWorkbook(srcChart.getWorkbook());
|
||||
chartCopy.setWorkbook(srcChart.getWorkbook());
|
||||
c.setAttributeText(idQualifiedName, slide.getRelationId(chartCopy));
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIXMLException(e);
|
||||
|
|
Loading…
Reference in New Issue