Cannot find API to add error bars using Apache POI - apache-poi

I was trying to find how to add error bars to the scatter plot chart using Apache POI as shown in the picture below. My research could not help me find the corresponding API. Can you please help to find the API.

Adding error bars is not supported by the high level apache poi classes until now. It would must be a method in XDDFChartData.Series.
But *.xlsx files are simply ZIP archives. So we can set the error bars using Excel's GUI. Then unzip the *.xlsx ZIP archive and have a look at /xl/charts/chart1.xml to find what has changed.
We will find something like:
...
<c:ser>
...
<c:errBars>
<c:errDir val="y"/>
<c:errBarType val="both"/>
<c:errValType val="percentage"/>
<c:val val="10.0"/>
</c:errBars>
...
</c:ser>
...
Now we can create that XML using the low level classes of ooxml-schemas:
...
// add error bars
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).addNewErrBars();
// set error bars direction only Y
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrDir().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrDir.Y);
// set error bars type to both (minus and plus)
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrBarType().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrBarType.BOTH);
// set error bars value type to percentage
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrValType().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrValType.PERCENTAGE);
// set error bars value to 10%
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewVal().setVal(10d);
...
Complete example:
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
public class ScatterChart {
public static void main(String[] args) throws IOException {
Double[][] data = new Double[][]{
new Double[]{0d, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d},
new Double[]{1.1d, 1.5d, 1.2d, 2.5d, 2.7d, 6.5d, 6.5d, 1.0d, 1.0d, 0.5d},
};
try (XSSFWorkbook wb = new XSSFWorkbook()) {
XSSFSheet sheet = wb.createSheet();
final int NUM_OF_ROWS = data.length;
final int NUM_OF_COLUMNS = data[0].length;
Row row;
Cell cell;
int rowIndex = 0;
int colIndex = 0;
for (Double[] dataRow : data) {
row = sheet.createRow(rowIndex++);
colIndex = 0;
for (Double value : dataRow) {
cell = row.createCell(colIndex++);
cell.setCellValue(value);
}
}
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 10, 23);
XSSFChart chart = drawing.createChart(anchor);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);
XDDFSolidFillProperties gridLinesFill = new XDDFSolidFillProperties(XDDFColor.from(
new byte[]{(byte)230,(byte)230,(byte)230}));
XDDFLineProperties gridLineProperties = new XDDFLineProperties();
gridLineProperties.setFillProperties(gridLinesFill);
XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("x");
XDDFShapeProperties shapeProperties = bottomAxis.getOrAddMajorGridProperties();
shapeProperties.setLineProperties(gridLineProperties);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setTitle("f(x)");
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
shapeProperties = leftAxis.getOrAddMajorGridProperties();
shapeProperties.setLineProperties(gridLineProperties);
XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(
sheet,
new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1)
);
XDDFNumericalDataSource<Double> ys = XDDFDataSourcesFactory.fromNumericCellRange(
sheet,
new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1)
);
XDDFScatterChartData chartData = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
chartData.setVaryColors(false);
XDDFScatterChartData.Series series = (XDDFScatterChartData.Series) chartData.addSeries(xs, ys);
series.setTitle("Series 1", null);
series.setSmooth(false);
chart.plot(chartData);
solidLineSeries(series, PresetColor.BLUE);
// add error bars
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).addNewErrBars();
// set error bars direction only Y
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrDir().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrDir.Y);
// set error bars type to both (minus and plus)
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrBarType().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrBarType.BOTH);
// set error bars not have no end caps - necessary for current Excel versions
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewNoEndCap().setVal(false);
// set error bars value type to percentage
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewErrValType().setVal(
org.openxmlformats.schemas.drawingml.x2006.chart.STErrValType.PERCENTAGE);
// set error bars value to 10%
chart.getCTChart().getPlotArea().getScatterChartArray(0).getSerArray(0).getErrBarsArray(0).addNewVal().setVal(10d);
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx")) {
wb.write(fileOut);
}
}
}
private static void solidLineSeries(XDDFChartData.Series series, PresetColor color) {
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setLineProperties(line);
series.setShapeProperties(properties);
}
}

Related

POI - Fixed width of image in Excel cell

I followed the approach to add a new image with the POI.
cell.getRow().setHeight(img.getHeightForExcel());
sheet.setColumnWidth(cell.getColumnIndex(), img.getWidthForExcel());
final int picID = workBook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
/* Create the drawing container */
final XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();
// ========adding image START
final XSSFClientAnchor myAnchor = new XSSFClientAnchor();
myAnchor.setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE);
/* Define top left corner, and we can resize picture suitable from there */
myAnchor.setCol1(cell.getColumnIndex()); // Column start
myAnchor.setRow1(rowNum - 1); // Row start
myAnchor.setCol2(cell.getColumnIndex() + 2); // Column end (covers two columns)
myAnchor.setRow2(rowNum); // Row end
/* Invoke createPicture and pass the anchor point and ID */
final XSSFPicture myPicture = drawing.createPicture(myAnchor, picID);
In principal this works quite well. I specify the width of the column at the beginning with the width of the image. (The height as well).
The major problem I'm facing is that as soon as I run autoadjust like
for (; i < max; i++) {
xlsWorkbook.getSheet().autoSizeColumn(i);
}
I get the problem that the first two columns are resized as well. But with this the width of the image is resized as well. Since the width might be quite long (or quite narrow) I don't want to affect the image size.
Is there a way to set the width of the image despite the column width?
If you don't want resizing the image when column widths are changing, then you cannot using that approach. This approach explicitly tells that the image shall be sized as the cell size it is anchored to. So if that cell size changes, the pictures size changes too.
You might think that ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE should protect the image from resizing. But this only is valuable when opened in Excel GUI. Apache poi does not respect ClientAnchor.AnchorType while auto sizing the columns. May be this will change in later versions. But in current version apache poi 5.0.0 it does not.
So to fulfill your requirement you set only a one cell anchor. That is only anchor.setCol1 and anchor.setRow1 as the upper left position of the picture. Then you need resizing the picture later to set the bottom right position. You must do that resizing after all column widths and row heights are set. So after auto sizing the columns. Else the resizing the columns will resizing the picture again.
Complete example:
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
class ImageTest {
public static void main(String[] args) throws Exception {
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("My Sample Excel");
//FileInputStream obtains input bytes from the image file
InputStream inputStream = new FileInputStream("./logo.png");
//Get the contents of an InputStream as a byte[].
byte[] bytes = IOUtils.toByteArray(inputStream);
//Adds a picture to the workbook
int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
//close the input stream
inputStream.close();
//Returns an object that handles instantiating concrete classes
CreationHelper helper = wb.getCreationHelper();
//Creates the top-level drawing patriarch.
Drawing drawing = sheet.createDrawingPatriarch();
//Create an anchor that is attached to the worksheet
ClientAnchor anchor = helper.createClientAnchor();
//Set anchor type; only valuable in Excel GUI
anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
//Create an anchor with upper left cell only
anchor.setCol1(1); //Column B
anchor.setRow1(2); //Row 3
//Create a picture
Picture pict = drawing.createPicture(anchor, pictureIdx);
//Reset the image to the original size
//pict.resize(); // don't do this before autosize column
//Create cell in column B to auto sizing that column
Cell cell = sheet.createRow(0).createCell(1);
cell.setCellValue("12345678901234567890");
sheet.autoSizeColumn(1);
//Reset the image to the original size
//pict.resize();
//Reset the image to half the original size
pict.resize(0.5);
//Write the Excel file
FileOutputStream fileOut = null;
fileOut = new FileOutputStream("./myFile.xlsx");
wb.write(fileOut);
fileOut.close();
}
}

How do I change font sizes in Heaps?

I'm currently coding in Haxe with Heaps and was checking on how to display text. One thing I want to do is give different font sizes to different texts. Naturally, I declared two Font instances and resized one of them. However, both texts are resized and I cannot manage to have them resize independently. How should I resize font sizes in Heaps?
class Main extends hxd.App{
override function init(){
var font : h2d.Font = hxd.res.DefaultFont.get();
var font2 : h2d.Font = hxd.res.DefaultFont.get();
font2.resizeTo(23);
var tf = new h2d.Text(font);
var tf2 = new h2d.Text(font2);
tf.text = "Hello World\nHeaps is great!";
tf.textColor = 0x00FF00;
tf.x = 100;
tf.y = 100;
tf.textAlign = Center;
tf2.text = "Hello World\nHeaps is great!";
tf2.textColor = 0x00FF00;
tf2.x = 300;
tf2.y = 300;
tf2.textAlign = Center;
s2d.addChild(tf);
s2d.addChild(tf2);
static function main(){
new Main();
}
}
The approach taken does not work because DefaultFont.get() caches the result.
You could either:
Copy the second font by doing var font2 : h2d.Font = font.clone() so that it gets its own properties.
Adjust scaleX and scaleY of Text.

How to give poi table margin from left word document

I am creating a word document using POI. I have created a table and a header. I want to give left margin to table so I used this code:
CTSectPr getSectPr = doc.getDocument().getBody().getSectPr();
CTPageMar addNewPgMar = getSectPr.addNewPgMar();
addNewPgMar.setLeft(BigInteger.valueOf(200));
addNewPgMar.setRight(BigInteger.valueOf(200));
addNewPgMar.setFooter(BigInteger.valueOf(0));
addNewPgMar.setHeader(BigInteger.valueOf(0));
[![enter image description here][1]][1]
But this code also give 200 margin to header from left. I Want only for table.
Thanks in Advance.
The page margins, you set using the code shown, are margins for the whole page. Headers and footers also are part of the page as well as the body. The additional settings setFooter and setHeader in page margins are settings for distances of the header from top and the footer from bottom of the page. There are no special settings to set left distance only for body or header/footer. So changed left page margins also affect the header and footer.
All you could do is set additional indentations for paragraphs and tables in the body.
Example:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageMar;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import java.math.BigInteger;
public class CreateWordHeaderFooter {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
// the body content
XWPFParagraph paragraph = document.createParagraph();
// set indentation of the paragraph
paragraph.setIndentationLeft(720); //720 TWentieths of an Inch Point (Twips) = 720/20 = 36 pt = 36/72 = 0.5"
XWPFRun run=paragraph.createRun();
run.setText("The Body:");
paragraph = document.createParagraph();
// set indentation of the paragraph
paragraph.setIndentationLeft(720);
run=paragraph.createRun();
run.setText("Lorem ipsum.... page 1");
// create table
XWPFTable table = document.createTable(3,3);
// set indentation of the table
CTTblWidth tableIndentation = table.getCTTbl().getTblPr().addNewTblInd();
tableIndentation.setW(BigInteger.valueOf(720));
tableIndentation.setType(STTblWidth.DXA);
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
table.getRow(row).getCell(col).setText("row " + row + ", col " + col);
}
}
paragraph = document.createParagraph();
// set indentation of the paragraph
paragraph.setIndentationLeft(720);
// create header start
XWPFHeader header = document.createHeader(HeaderFooterType.DEFAULT);
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run = paragraph.createRun();
run.setText("The Header");
// create footer start
XWPFFooter footer = document.createFooter(HeaderFooterType.DEFAULT);
paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run = paragraph.createRun();
run.setText("The Footer");
// create page margins
CTSectPr sectPr = document.getDocument().getBody().getSectPr();
if (sectPr == null) sectPr = document.getDocument().getBody().addNewSectPr();
CTPageMar pageMar = sectPr.getPgMar();
if (pageMar == null) pageMar = sectPr.addNewPgMar();
pageMar.setLeft(BigInteger.valueOf(720)); //720 TWentieths of an Inch Point (Twips) = 720/20 = 36 pt = 36/72 = 0.5"
pageMar.setRight(BigInteger.valueOf(720));
pageMar.setTop(BigInteger.valueOf(720));
pageMar.setBottom(BigInteger.valueOf(720));
pageMar.setFooter(BigInteger.valueOf(720));
pageMar.setHeader(BigInteger.valueOf(720));
pageMar.setGutter(BigInteger.valueOf(0));
FileOutputStream out = new FileOutputStream("CreateWordHeaderFooter.docx");
document.write(out);
out.close();
document.close();
}
}
This code is tested using apache poi 4.1.0 and needs the the full ooxml-schemas-1.4.jar as mentioned in FAQ-N10025.

iText: add SVG tile as page to new PDF file

I'm trying to create a new PDF file using iText, and the new file should be composed of pages that are generated from an area within an SVG file (tile). And each generated page needs to have a 'drawing border' superimposed upon it, so that it appears as the top layer of each generated page. I think the superimposing can be achieved with the iText stamper, but examples I see work only with an existing PDF, which I don't have as I want to do all this on-the-fly to reduce the time required to generate the resulting PDF. I have a one page PDF file that represents the PDF layer to superimpose upon each page generated in the PDF.
I found an example on the net that divides the SVG canvas into tiles and creates separate PDF files from each tile. However, creating intermediate PDF files wastes time, as I need to read them in again to create the file I am trying to create (with the superimposed layer for each page).
I don't want to dump loads of code here, but here is the code sample that I used to generate one page PDF files for each SVG tile:
http://people.apache.org/~clay/batik/rasterizerTutorial.pdf (see page 5: SaveAsJPEGTiles.java)
As I am an iText newbie, maybe someone here has achieved something similar, or knows how to do this?
Thanks.
I'm using a ByteArrayOutputStream instead of the FileOutputStream, but when I try to combine this with iText's Document type, I keep getting an exception saying no pages in document - see code below. I think I need to add the ByteArrayOutputStream for each tile to the iText document so that it creates a new page for each tile, but I can't see how to do that from the iText API. Here's my code so far, but doesn't quite work:
package examples.aoi;
import java.io.*;
import java.awt.*;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.fop.svg.PDFTranscoder;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
public class FromCanvasToPDFPages {
PDFTranscoder trans = new PDFTranscoder();
public FromCanvasToPDFPages() {
}
public void tile(TranscoderInput input, TranscoderOutput output, Rectangle aoi) throws Exception {
trans.addTranscodingHint(PDFTranscoder.KEY_WIDTH, new Float(aoi.width));
trans.addTranscodingHint(PDFTranscoder.KEY_HEIGHT, new Float(aoi.height));
trans.addTranscodingHint(PDFTranscoder.KEY_AOI, aoi);
trans.transcode(input, output);
}
public static void main(String [] args) throws Exception {
FromCanvasToPDFPages p = new FromCanvasToPDFPages();
String in = "C:\\Documents and Settings/krell/My Documents/1.svg";
String svgURI = new File(in).toURL().toString();
TranscoderInput input = new TranscoderInput(svgURI);
String outputFilename = "canvasPages.pdf";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(baos);
int A4_landscape_width = 1103; // use proper dimensions from class when found
int A4_landscape_height = 780; // use proper dimensions from class when found
int documentWidth = 3309; // read this directly from canvas file (svg)
int documentHeight = 1560; // read this directly from canvas file (svg)
int columns = documentWidth / A4_landscape_width;
int rows = documentHeight / A4_landscape_height;
int tile_width = A4_landscape_width;
int tile_height = A4_landscape_height;
System.err.println(">>> Canvas document width = "+documentWidth);
System.err.println(">>> Canvas document height = "+documentHeight);
System.err.println(">>> A4 width = "+A4_landscape_width);
System.err.println(">>> A4 height = "+A4_landscape_height);
System.err.println(">>> canvas columns = "+columns);
System.err.println(">>> canvas rows = "+rows);
System.err.println(">>> tile_width = "+tile_width);
System.err.println(">>> tile_height = "+tile_height);
// Create A4 document to write tile data into
Document document = new Document(PageSize.A4_LANDSCAPE, 10, 10, 10, 10);
PdfWriter writer = PdfWriter.getInstance(document, baos);
// open the document
document.open();
// now process each tile, row by row, column by column until done
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
// get tile coordinates
Rectangle tile = new Rectangle(column*tile_width, row*tile_height, (column+1)*tile_width, (row+1)*tile_height);
p.tile(input, output, tile);
}
}
// now write the baos to disk:
OutputStream fileOutputStream = new FileOutputStream(outputFilename);
baos.writeTo(fileOutputStream);
// close stuff
fileOutputStream.flush();
fileOutputStream.close();
document.close();
baos.close();
System.exit(0);
}
}

how to set layout_span, layout_margin dynamically in code in android

how to set layout_span, layout_margin dynamically in code in android
You can set layout_margin with a TableRow.LayoutParams instance given to TableRow.addView():
TableLayout newTable = new TableLayout(DisplayContext);
int rowIndex = 0;
// First Row (3 buttons)
TableRow newRow1 = new TableRow(DisplayContext);
newRow1.addView(new Button(DisplayContext), 0);
newRow1.addView(new Button(DisplayContext), 1);
newRow1.addView(new Button(DisplayContext), 2);
newTable.addView(newRow1, rowIndex++);
// Second Row (2 buttons, last one spans 2 columns)
TableRow newRow2 = new TableRow(DisplayContext);
newRow2.addView(new Button(DisplayContext), 0);
Button newButton = new Button(DisplayContext);
// Create the layout to span two columns
TableRow.LayoutParams params = new TableRow.LayoutParams();
params.span = 2;
newRow2.addView(newButton, 1, params);
newTable.addView(newRow2, rowIndex++);

Resources