[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:
PJ Fanning 2018-02-27 23:12:53 +00:00
parent 2dff049db9
commit 24fee0c0d5
7 changed files with 278 additions and 26 deletions

View File

@ -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);
}
}

View File

@ -0,0 +1,4 @@
My Bar or Column Chart
First 1.0
Second 3.0
Third 4.0

View File

@ -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) {
}
}
/**

View File

@ -31,5 +31,7 @@ public interface XDDFDataSource<T> {
boolean isNumeric();
int getColIndex();
String getDataRangeReference();
}

View File

@ -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;

View File

@ -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);