i am using apache poi to generate line chart in excel. I have two sets of data, and it works well, please look at picture1.
picture1
When i use only one set of data, it generate picture2, and you can see the right side of the picture, it show china, usa and japan. This is not what i want, it should show only one serial on right side. How can i fix this?
picture2
maven
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.1</version>
</dependency>
java code
public static void test() throws Exception {
try (XSSFWorkbook wb = new XSSFWorkbook()) {
String sheetName = "CountryLineChart";
XSSFSheet sheet = wb.createSheet(sheetName);
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 4, 7, 26);
XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText("Area-wise Top Seven Countries");
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("Country");
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setTitle("Area & Population");
XDDFDataSource<String> countries = XDDFDataSourcesFactory.fromArray(new String[] { "china", "usa", "japan" });
XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromArray(new Double[] { 12d, 22d, 12d });
XDDFNumericalDataSource<Double> population = XDDFDataSourcesFactory.fromArray(new Double[] { 33d, 12d, 16d });
XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(countries, area);
series1.setTitle("Area", null);
series1.setSmooth(false);
series1.setMarkerStyle(MarkerStyle.STAR);
// if comment these code, it generate line chart like picture2
// ===========================================================================
XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(countries, population);
series2.setTitle("Population", null);
series2.setSmooth(true);
series2.setMarkerStyle(MarkerStyle.SQUARE);
// ===========================================================================
chart.plot(data);
// Write output to an excel file
String filename = "/Users/jiangxingshang/Downloads/tmp/line-chart.xlsx";
try (FileOutputStream fileOut = new FileOutputStream(filename)) {
wb.write(fileOut);
}
}
}
Related
Currently my diagram inside XLSX looks like this -> Line diagram xlsx result
Unfortunately I need to switch the position between category and values to be looked like this -> expected result line chart where I need to place values of the chart on the X-Axis and category on the Y-axis.
Are there any workaround or tipps how to rotate the position between these two axis in Java Apache POI?
I've tried to manage like this:
XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText("Test Line Chart");
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
XDDFCategoryAxis leftAxis = chart.createCategoryAxis(AxisPosition.LEFT);
leftAxis.setTitle("Test Category");
XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("Test Values");
bottomAxis.setCrosses(AxisCrosses.AUTO_ZERO);
int firstRowNum = sheet.getFirstRowNum() + 1; //hier wird auch benötigt für Balken-component
int lastRowNum = sheet.getLastRowNum();
XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, leftAxis, bottomAxis);
But lineChart still can't put category on X-Axis.
PS: I've also tried to use AxisOrientation.MAX_MIN for the categoryAxis, which at the end will be exported like this
How I add the data?
int indexColor = 0;
MutableInt mutableRow = new MutableInt(-1);
byte[] colorChart = vpsChartsXlsxDocumentExportService.setColorChart(colors.get(indexColor));
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(colorChart));
String[] rawCategoryData = translationService.translate(language, null, chartData.getCaptions().toArray(new String[chartData.getCaptions().size()]));
BigDecimal[] rawValueData = chartData.getValues().get(0).toArray(new BigDecimal[chartData.getValues().get(0).size()]); //not only the first index from array
Row row = sheet.getRow(firstRowNum);
int cellValues = row.getLastCellNum() - 1;
int cellCategories = row.getFirstCellNum();
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromStringCellRange(
(XSSFSheet) sheet,
new CellRangeAddress(firstRowNum, lastRowNum, cellCategories, cellCategories));
final int numOfPoints = rawCategoryData.length;
final String valuesDataRange = chart.formatRange(new CellRangeAddress(mutableRow.intValue(), numOfPoints, cellValues, cellValues));
final XDDFNumericalDataSource<BigDecimal> valuesData = XDDFDataSourcesFactory.fromArray(rawValueData, valuesDataRange, cellValues);
xddfLineChartData.addSeries(categoriesData, valuesData);
chart.plot(xddfLineChartData);
XDDFChartData.Series series = xddfLineChartData.getSeries(0);
It seems like apache does not support anything regarding "rotation" of chart area or switching the x- and y-values.
We ended up to use the original one (ChartTypes.LINE) like what we implemented till now.
The following image is the output before setting the major and minor unit:
I tried to set the majorUnit and minorUnit of my X-axis( category) in apache poi 5.0.0, By using the following code:
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.MIN);
bottomAxis.setCrosses(AxisCrosses.MIN);
setValueAxisTitle(chart, 0, chartDataLocationInExcelFile.getColumnNames()[index + 1]);
setCatAxisTitle(chart, 0, chartDataLocationInExcelFile.getColumnNames()[index - 1]);
// getting minimum cat value of category
CellReference cellReference = new CellReference(chartDataLocationInExcelFile.getFirstRowNumber() + 2,
chartDataLocationInExcelFile.getFirstCellNumber());
Row row = sheet.getRow(cellReference.getRow());
Cell cell = row.getCell(cellReference.getCol());
// setting MajorUnit and MinorUnit of category axis
bottomAxis.setMajorUnit(0.2d);
bottomAxis.setMinorUnit(0.3d);
// setting minimum and maximum of category axis
BigDecimal catMin = new BigDecimal(cell.getNumericCellValue());
BigDecimal subtractResult = catMin.subtract(new BigDecimal(5d));
bottomAxis.setMinimum(subtractResult.doubleValue());
//
Then it didn't work, And the following output generated:
Thanks for your help.
After checking the source of XDDFCategoryAxis in Apache POI 5.0.0, I saw that setMajorUnit and setMinorUnit didn't have body:
#Override
public void setMajorUnit(double major) {
// nothing
}
#Override
public void setMinorUnit(double minor) {
// nothing
}
I use JDK8 and POI-4.1.0 use they example here a link
export chart to Word .when create two series is ok two series img,
but I only create one series .the chart mistake category for series one series img
"lang1" "lang2" "lang3" is category name but they become series name.
i have no ideal. I also find use line chart have the same problem
my code
public static void main(String[] args) throws Exception {
List<String> listLanguages = new ArrayList<>(3);
listLanguages.add("lang1");listLanguages.add("lang2");listLanguages.add("lang3");
List<Double> listCountries = new ArrayList<>(3);
listCountries.add(10d);listCountries.add(20d);listCountries.add(30d);
List<Double> listSpeakers = new ArrayList<>(3);
listSpeakers.add(14d);listSpeakers.add(25d);listSpeakers.add(33d);
String[] categories = listLanguages.toArray(new String[listLanguages.size()]);
Double[] values1 = listCountries.toArray(new Double[listCountries.size()]);
Double[] values2 = listSpeakers.toArray(new Double[listSpeakers.size()]);
try (XWPFDocument doc = new XWPFDocument()) {
XWPFChart chart = doc.createChart(5000000, 4000000);
XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
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(values1, valuesDataRange, 1);
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
series1.setTitle("a",chart.setSheetTitle("a", 1));
//XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
//series2.setTitle("b",chart.setSheetTitle("b", 2));
bar.setVaryColors(true);
bar.setBarDirection(BarDirection.COL);
chart.plot(bar);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.LEFT);
// legend.setOverlay(false);
try (OutputStream out = new FileOutputStream("C:/Users/lyf/Desktop/barExample.docx")) {
doc.write(out);
}
}
catch(Exception e)
{
}
}
The main problem is that setting setVaryColors to true means the following:
If only one series, then do varying the colors for each data point of the series. Then the legend shows the varying data points instead of the series. If more than one series, then do varying the colors for each series. Then the legend shows the varying series.
So we need set setVaryColors to false if only one series is present.
But additional we need set AxisCrossBetween, so the left axis crosses the category axis between the categories. Else first and last category is exactly on cross points and the bars are only half visible.
And at last, XDDF is only half ready at the moment and there are many bugs. For example XDDFChart.setSheetTitle is buggy. It creates a Table but only half way and incomplete. Excel cannot opening the workbook after creating that incomplete Table. So updating the chart data in Word is not possible.
The following code works for me and can create a chart with only one series as well as with two. Additional I have tried making the code more structured in single steps. Each step is commented on what it is doing.
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
public class CreateWordXDDFChart {
// Methode to set title in the data sheet without creating a Table but using the sheet data only.
// Creating a Table is not really necessary.
static CellReference setTitleInDataSheet(XWPFChart chart, String title, int column) throws Exception {
XSSFWorkbook workbook = chart.getWorkbook();
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFRow row = sheet.getRow(0); if (row == null) row = sheet.createRow(0);
XSSFCell cell = row.getCell(column); if (cell == null) cell = row.createCell(column);
cell.setCellValue(title);
return new CellReference(sheet.getSheetName(), 0, column, true, true);
}
public static void main(String[] args) throws Exception {
try (XWPFDocument document = new XWPFDocument()) {
// create the data
String[] categories = new String[]{"Lang 1", "Lang 2", "Lang 3"};
Double[] valuesA = new Double[]{10d, 20d, 30d};
Double[] valuesB = new Double[]{15d, 25d, 35d};
// create the chart
XWPFChart chart = document.createChart(15*Units.EMU_PER_CENTIMETER, 10*Units.EMU_PER_CENTIMETER);
// create data sources
int numOfPoints = categories.length;
String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
String valuesDataRangeA = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
String valuesDataRangeB = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
XDDFNumericalDataSource<Double> valuesDataA = XDDFDataSourcesFactory.fromArray(valuesA, valuesDataRangeA, 1);
XDDFNumericalDataSource<Double> valuesDataB = XDDFDataSourcesFactory.fromArray(valuesB, valuesDataRangeB, 2);
// create axis
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
// Set AxisCrossBetween, so the left axis crosses the category axis between the categories.
// Else first and last category is exactly on cross points and the bars are only half visible.
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
// create chart data
XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
((XDDFBarChartData)data).setBarDirection(BarDirection.COL);
// create series
// if only one series do not vary colors for each bar
((XDDFBarChartData)data).setVaryColors(false);
XDDFChartData.Series series = data.addSeries(categoriesData, valuesDataA);
// XDDFChart.setSheetTitle is buggy. It creates a Table but only half way and incomplete.
// Excel cannot opening the workbook after creatingg that incomplete Table.
// So updating the chart data in Word is not possible.
//series.setTitle("a", chart.setSheetTitle("a", 1));
series.setTitle("a", setTitleInDataSheet(chart, "a", 1));
/*
// if more than one series do vary colors of the series
((XDDFBarChartData)data).setVaryColors(true);
series = data.addSeries(categoriesData, valuesDataB);
//series.setTitle("b", chart.setSheetTitle("b", 2));
series.setTitle("b", setTitleInDataSheet(chart, "b", 2));
*/
// plot chart data
chart.plot(data);
// create legend
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.LEFT);
legend.setOverlay(false);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("CreateWordXDDFChart.docx")) {
document.write(fileOut);
}
}
}
}
I am unable to add a line on a second axis (right axis) on an existing chart. Is there a way to do this with the new implementation of Charts in POI 4.0.0/1?
Desired output will look like this (A simple excel chart with 2 axes):
. The associated data to that chart as an example:
Series 1/Axis1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Series 2/Axis2 = [200,300,400,500,600,700,800,900,1000]
Here is the code that I am trying so far in Java, it is mostly replicated from the LineChart.java example
//Initial code instantiates a document
XWPFDocument doc = new XWPFDocument();
...
// Generate Chart
// This was taken from the example https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/LineChart.java
XWPFChart prChart = doc.createChart();
//Values 1 on the Left Axis
//Values 2 on the Right Axis
String[] categories = dates.toArray(new String[dates.size()]);
BigDecimal[] values1 = prices1.toArray(new BigDecimal[prices1.size()]);
BigDecimal[] values2 = prices2.toArray(new BigDecimal[prices2.size()]);
XDDFChartAxis bottomAxis = prChart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setMajorTickMark(AxisTickMark.NONE);
XDDFValueAxis leftAxis = prChart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
leftAxis.setMajorTickMark(AxisTickMark.OUT);
/*
* Is this made correctly?
*/
XDDFValueAxis rightAxis = prChart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosses(AxisCrosses.MAX);
rightAxis.setMajorTickMark(AxisTickMark.IN);
final int numOfPoints = categories.length;
final String categoryDataRange = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
final String valuesDataRange = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
final String valuesDataRange2 = prChart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
XDDFLineChartData line = (XDDFLineChartData) prChart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) line.addSeries(categoriesData, valuesData);
series1.setTitle("Price", null);
series1.setSmooth(true);
series1.setMarkerStyle(MarkerStyle.NONE);
solidLineSeries(series1, PresetColor.BLUE_VIOLET);
// Am I adding the rightAxis correctly here?
XDDFLineChartData line2 = (XDDFLineChartData) prChart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) line2.addSeries(categoriesData, valuesData2);
series2.setTitle("Index", null);
series2.setSmooth(true);
series2.setMarkerStyle(MarkerStyle.NONE);
solidLineSeries(series2, PresetColor.BLACK);
prChart.plot(line);
prChart.plot(line2); /// <- Does this add to the same plot correctly?
prChart.displayBlanksAs(DisplayBlanks.GAP);
Running this code doesn't produce any compile errors. But I do get errors when opening the document "Problem with its' contents."
I suppose I am not adding the 2nd line and 2nd axes correctly.
Is there a way to accomplish this?
Update w. Solution
Axel's solution below works perfectly. The additional info to know is exactly what was the issue.
I would also like to recognize the order in which you add to the plot, this will hopefully help others
Create first set of axis
Create first Line
Plot first Line
Create new Axis
Create 2nd line
Plot 2nd line
Update the axis ids!
When it comes to multiple different value axes in one chart, this is not fully implemented in XDDF until now. So we need correcting something using the low level ooxml-schemas-1.4 classes.
Needed knowledge:
In principle the series which shall be shown on second value axis are in a separate chart in the same plot area. So the series which shall be shown on second value axis needs it's own bottom axis too. But this bottom axis must be invisible.
Both the axes, the second bottom and the new right axis, must cross each other properly. This crossing apache poi does not properly until now. So we must correct here.
Because while adding to the chart, the apache poi code which adds the second line chart does not knows something about the already present line chart, it's IDs starts with 0 again. But this is wrong for an combined chart. So we need correct the id and order. It must not start with 0 again because there is a line series already in same plot area.
Complete example to be reproducible for others too:
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
public class CreateWordXDDFChart {
public static void main(String[] args) throws Exception {
try (XWPFDocument document = new XWPFDocument()) {
// create the data
String[] categories = new String[]{"1","2","3","4","5","6","7","8","9"};
Double[] values1 = new Double[]{1d,2d,3d,4d,5d,6d,7d,8d,9d};
Double[] values2 = new Double[]{200d,300d,400d,500d,600d,700d,800d,900d,1000d};
// create the chart
XWPFChart chart = document.createChart(15*Units.EMU_PER_CENTIMETER, 10*Units.EMU_PER_CENTIMETER);
// create data sources
int numOfPoints = categories.length;
String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
String valuesDataRange1 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
XDDFNumericalDataSource<Double> valuesData1 = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange1, 1);
XDDFNumericalDataSource<Double> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
// first line chart
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
XDDFChartData data = chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFChartData.Series series = data.addSeries(categoriesData, valuesData1);
chart.plot(data);
solidLineSeries(data, 0, PresetColor.BLUE);
// second line chart
// bottom axis must be there but must not be visible
bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setVisible(false);
XDDFValueAxis rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosses(AxisCrosses.MAX);
// set correct cross axis
bottomAxis.crossAxis(rightAxis);
rightAxis.crossAxis(bottomAxis);
data = chart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
series = data.addSeries(categoriesData, valuesData2);
chart.plot(data);
// correct the id and order, must not be 0 again because there is one line series already
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getIdx().setVal(1);
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getOrder().setVal(1);
solidLineSeries(data, 0, PresetColor.RED);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("CreateWordXDDFChart.docx")) {
document.write(fileOut);
}
}
}
private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
XDDFChartData.Series series = data.getSeries().get(index);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setLineProperties(line);
series.setShapeProperties(properties);
}
}
I'm going to set color and the name of three series with the line chart in Apache POI. According to the following example, the names of each line are just series 1, series 2 and series 3 and the colors are automatically assigned. How can I modify the color and the name of them at the chart?
http://thinktibits.blogspot.hk/2014/07/apache-poi-xlsx-line-chart-java-example.html
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.charts.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xssf.usermodel.charts.*;
/* Line Chart Example in Apache POI */
public class LineChart{
public static void main(String[] args) throws Exception {
/* Create a Workbook object that will hold the final chart */
XSSFWorkbook my_workbook = new XSSFWorkbook();
/* Create a worksheet object for the line chart.
This worksheet will contain the chart */
XSSFSheet my_worksheet = my_workbook.createSheet("LineChart_Example");
/* Let us now create some test data for the chart */
/* Later we can see how to get this test data from a CSV File or SQL Table */
/* We use a 4 Row chart input with 5 columns each */
for (int rowIndex = 0; rowIndex < 4; rowIndex++){
/* Add a row that contains the chart data */
XSSFRow my_row = my_worksheet.createRow((short)rowIndex);
for (int colIndex = 0; colIndex < 5; colIndex++){
/* Define column values for the row that is created */
XSSFCell cell = my_row.createCell((short)colIndex);
cell.setCellValue(colIndex * (rowIndex + 1));
}
}
/* At the end of this step, we have a worksheet with test data, that we want to write into a chart */
/* Create a drawing canvas on the worksheet */
XSSFDrawing xlsx_drawing = my_worksheet.createDrawingPatriarch();
/* Define anchor points in the worksheet to position the chart */
XSSFClientAnchor anchor = xlsx_drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
/* Create the chart object based on the anchor point */
XSSFChart my_line_chart = xlsx_drawing.createChart(anchor);
/* Define legends for the line chart and set the position of the legend */
XSSFChartLegend legend = my_line_chart.getOrCreateLegend();
legend.setPosition(LegendPosition.BOTTOM);
/* Create data for the chart */
LineChartData data = my_line_chart.getChartDataFactory().createLineChartData();
/* Define chart AXIS */
ChartAxis bottomAxis = my_line_chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
ValueAxis leftAxis = my_line_chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
/* Define Data sources for the chart */
/* Set the right cell range that contain values for the chart */
/* Pass the worksheet and cell range address as inputs */
/* Cell Range Address is defined as First row, last row, first column, last column */
ChartDataSource<Number> xs = DataSources.fromNumericCellRange(my_worksheet, new CellRangeAddress(0, 0, 0, 4));
ChartDataSource<Number> ys1 = DataSources.fromNumericCellRange(my_worksheet, new CellRangeAddress(1, 1, 0, 4));
ChartDataSource<Number> ys2 = DataSources.fromNumericCellRange(my_worksheet, new CellRangeAddress(2, 2, 0, 4));
ChartDataSource<Number> ys3 = DataSources.fromNumericCellRange(my_worksheet, new CellRangeAddress(3, 3, 0, 4));
/* Add chart data sources as data to the chart */
data.addSerie(xs, ys1);
data.addSerie(xs, ys2);
data.addSerie(xs, ys3);
/* Plot the chart with the inputs from data and chart axis */
my_line_chart.plot(data, new ChartAxis[] { bottomAxis, leftAxis });
/* Finally define FileOutputStream and write chart information */
FileOutputStream fileOut = new FileOutputStream("xlsx-line-chart.xlsx");
my_workbook.write(fileOut);
fileOut.close();
}
}
You can change the line color after you have plotted the chart:
/* Plot the chart with the inputs from data and chart axis */
my_line_chart.plot(data, new ChartAxis[]{bottomAxis, leftAxis});
Color col1 = new Color(233, 87, 162);
CTSolidColorFillProperties fillProp = CTSolidColorFillProperties.Factory.newInstance();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte) col1.getRed(), (byte) col1.getGreen(), (byte) col1.getBlue()});
fillProp.setSrgbClr(rgb);
CTLineProperties lineProp = CTLineProperties.Factory.newInstance();
lineProp.setSolidFill(fillProp);
CTShapeProperties ctShapeProperties = CTShapeProperties.Factory.newInstance();
ctShapeProperties.setLn(lineProp);
my_line_chart.getCTChart().getPlotArea().getLineChartList().get(0).getSerList().get(0).setSpPr(ctShapeProperties);