Refresh Pivot table using Apache POI - java

No/Minimal documentation regarding Apache POI for Pivot tables in the Apache site has got me to write this.
I want to refresh a pivot table in a Work Book using Apache POI.
Please let me know where I can get proper documentation and Examples regarding this.

Kindly follow the followings which i did.
Fill rough data for pivot table in your MyFileName.xlsx file.
Create a Dynamic Range Formula through OFFSET() or Named Table as Source Data for Pivot table and draw pivot table.
Simply Right click your pivot table and choose
pivotTable Options->Data-> Check Refresh Data when opening File
Open a MyFileName.xlsx file and fill out the data.
That's all...
whenever you opening workbook it will be refreshed to current data. :-)
Note: This will not work when you creating Pivot table through POI.

The link codeMan refers to has some advice that looks quite specific to Apache POI & Excel.
You'll see that there is no great documentation for a reason here (it's not supported):
http://poi.apache.org/spreadsheet/limitations.html
To quote Solitudes answer in codeMans link verbatim:
It is possible. In the PivotCacheDefinition, there is an attribute
refreshOnLoad that can be set to true. The cache is then refreshed
when the workbook is opened. More information here.
> In POI this can be done by calling the method setRefreshOnLoad(boolean
bool), that takes a boolean as parameter, on a CTPivotCacheDefinition
If you need to refresh the pivot table before the file is opened, (for example to then use the pivottable calculated data in further calculations and have POI write this) then I'm not sure that this would be possible at all with POI, and potentially hooking up to excel using a COM solution might be the way to go.

Apart from the limitations, you can check a little information about Package org.apache.poi.hssf.record.pivottable
Though if I will have to do the same, I would create the table/chart manually once and will update the chart using apache poi as I have done here

another solution (WO VBA scripts)
In tempalate.xlsx create xlTable object on headers of source record set. Set name to the xlTable, ex. 'mySourceTable'.
Also in file preSet for your PivotTable:
sourceRef ='mySourceTable'
check in RefreshOnLoad
In POI:
private void updateXlTableSource() {
XSSFTable sourceTable = ((XSSFWorkbook)workbook).getTable("mySourceTable");
CTTable ctTable = sourceTable.getCTTable();
String sourceRef = getSourceDataRange().formatAsString();
ctTable.setRef(sourceRef);
ctTable.getAutoFilter().setRef(sourceRef);
}
private CellRangeAddress getSourceDataRange() {
XSSFSheet xssfSheet = (XSSFSheet) workbook.getSheet("sourceSheetName");
int uBoundSourceDataRow = findFirstEmptyRowFrom(xssfSheet) - 1;
if (uBoundSourceDataRow < 2) {
uBoundSourceDataRow = 2;
}
int uBoundSourceDataCol = findFirstEmptyColFromFirstRow(xssfSheet) - 1;
return new CellRangeAddress(0, uBoundSourceDataRow, 0, uBoundSourceDataCol);
}
Note: check your tempalate.xlsx for unKnown query. Delete if it exists, else it will block PT updating
Drawback: PT's autoFilter contains notexisting elements (elements from PT template).

save your file with PTs as file.xlsm and insert VBA script (ALT+F11):
' Create module and insert this:
Public Const pivotName1 As String = "myPivotName"
Public Const sourceSheetName As String = "source"
Public Const sourceColumnCount As Long = 23
' In "ThisWorkbook" chapter insert this:
Dim lRow As Long
Private Sub Workbook_Open()
Application.ScreenUpdating = False
ActiveWorkbook.Worksheets(sourceSheetName).Activate
' In file should preliminarily insert keyWord "firstOpenFlag" in CV1 cell (sheet sourceSheetName)
' It gona start actions below
If ActiveSheet.Cells(1, 100) = "firstOpenFlag"
Then
ActiveSheet.Cells(1, 100) = ""
lRow = getLastRowForFirstCol(sourceSheetName)
Call updateAllPTCache
ActiveWorkbook.Worksheets(sourceSheetName).Activate
ActiveSheet.Range("A1").Select
End If
Application.ScreenUpdating = True
End Sub
Private Function getLastRowForFirstCol(sourceSheetName As String) As Long
ActiveWorkbook.Worksheets(sourceSheetName).Activate
getLastRowForFirstCol = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
If getLastRowForFirstCol < 2 Then getLastRowForFirstCol = 2
End Function
Private Sub updateAllPTCache()
Dim pt As PivotTable
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
For Each pt In ws.PivotTables
pt.ChangePivotCache ActiveWorkbook.PivotCaches.Create( _
SourceType:=xlDatabase, _
SourceData:=sourceSheetName + "!R1C1:R" + CStr(lRow) + "C" + CStr(sourceColumnCount), _
Version:=xlPivotTableVersion14)
' xlPivotTableVersion14 - work in 2013, 2016 exlApp
' Downgrade xlPivotTableVersion for backward compatibility
pt.RefreshTable
Next pt
Next ws
End Sub
Drawback: clients xlsApp should be configed to enable VBA scripts

Related

Is it possible to set the active range with Apache POI XSSF?

I am using Apache POI XSSF to read and write Excel Sheets.
I know that I can set the active cell on a worksheet by using Sheet.setActiveCell(CellAddress address).
However, I'd like to set it to a Range containing more than one cell on the sheet, as illustrated by the picture below:
When I save a sheet with multiple cells selected using Excel those are selected upon opening the saved file.
Is there a way to do this with POI XSSF?
you can use following line to achieve a ranke as active cell in excel:
sheet.setActiveCell("A1:B2");
Hope it helps.
As from 3.16 onwards the setActiveCell(String) method is deprecated and you do not want to use a deprecated method I would suggest to create your own CellAddress:
public class CellRangeAddress extends CellAddress {
private CellAddress start;
private CellAddress end;
public CellRangeAddress(final CellAddress start, final CellAddress end) {
super(start);
this.start = start;
this.end = end;
}
#Override
public String formatAsString() {
if (end != null) {
return start.formatAsString() + ":" + end.formatAsString();
}
return super.formatAsString();
}
}
and use ist like:
sheet.setActiveCell(new CellRangeAddress(new CellAddress("A1"), new CellAddress("B2")));
Not the cleanest and best way, but works without warnings.

Can't add worksheets to an excel file through my R script

I'm trying to create a workbook with several spreadsheets where I have to pass three data frames to each sheet. However, I'm having problems creating the sheets, having the following error:
Error in .jcall(wb, "Lorg/apache/poi/ss/usermodel/Sheet;",
"createSheet", : method createSheet with signature
(D)Lorg/apache/poi/ss/usermodel/Sheet; not found
I'm using the xlsx package and the relevant code part is the following:
wb <- createWorkbook(type="xlsx")
saveWorkbook(wb, 'output.xlsx')
for (i in year)
{
sheet.1 <- createSheet(wb, sheetName = i)
data.filter <- realdata[realdata$year_ == i,]
data.filter <- data.filter[data.filter$month_ >= month[1],]
data.filter <- data.filter[data.filter$month_ <= month[4],]
ptable_data_usado <- cast(data.filter, mondat ~ BASE, value = "myidx")
correl_usado <- cor(ptable_data_usado)
addDataFrame(correl_usado, sheet = i, startRow = 0, startColumn = 0)
ptable_data_prx <- cast(data.filter, mondat ~ NearestBaseName, value = "myidx")
correl_prx <- cor(ptable_data_prx)
addDataFrame(correl_prx, sheet = i, startRow = 14, startColumn = 0)
}
I ran into a similar problem. My solution was to coerce sheet name into a character.
So in your case it might be
sheet.1 <- createSheet(wb, sheetName = as.character(i))
Hope it will help.
xlsx package is using rJava to call functions written in JAVA from the APACHE POI project for functionality.
The function to creat worksheet is declared as:
public XSSFSheet createSheet(java.lang.String sheetname)
this means that you need to pass a string to the function. Return back to R, the sheet name must be a character vector. #Oleksii-Sh answer is right.
Or you can use:
sheet.1 <- createSheet(wb, sheetName = paste0("sheet", i))
if you want to name it sheet1, sheet2 ...
Can't be positive without a reproducible example, but it looks like the problem is the two lines where you have sheet = i. Instead, it should be sheet = sheet.1.
In addition, startRow and startColumn need to be integers greater than zero, though that would give an out-of-allowable-range error, rather than a not-found error.
Also, saveWorkbook(wb, 'output.xlsx') should come after the loop.

Insert new row into LibreOffice writer table using UNO

I have recently tried to code a small java file which will insert a row into an already existing table in a .odt document. The table itself has 4 rows and 3 column, but I would like to implement a check which will expand that table if the content to be inserted is larger than 4. However, every time I try to get the table's rows, it returns a null pointer. I am not that familiar with UNO api, but as far as i read through the documentation, the class XColumnsAndRowRange should be used in this situation. My code is as follows:
XTextTablesSupplier xTablesSupplier = (XTextTablesSupplier) UnoRuntime.queryInterface(XTextTablesSupplier.class, xTextDocument);
XNameAccess xNamedTables = xTablesSupplier.getTextTables();
try {
Object table = xNamedTables.getByName(tblName);
XTextTable xTable = (XTextTable) UnoRuntime.queryInterface(XTextTable.class, table);
XCellRange xCellRange = (XCellRange) UnoRuntime.queryInterface(XCellRange.class, table);
if(flag){
XColumnRowRange xCollumnAndRowRange =(XColumnRowRange)
UnoRuntime.queryInterface(XColumnRowRange.class, xCellRange);
XTableRows rows = xCollumnAndRowRange.getRows();
System.out.println("Testing if this works");
rows.insertByIndex(4, size-4);
}
I am not sure if I am missing something here or if I should be using a different function.
As Lyrl suggested, this works:
XTableRows rows = xTable.getRows();
Apparently XColumnRowRange is only used for spreadsheets.
Note: With Basic or Python you would not have this problem, because those languages do not need queryInterface. The code would simply be:
table = tables.getByName(tblName)
rows = table.getRows()

Apache POI : Update cells in a named range

I am using Apache POI library to read/write to xlsx. In my original xlsx, I have a namedrange "XYZ".
I want to update the values of cells within this name range. How can I do that?
I did this:
XSSFName name = workbook.getName("XYZ");
String formula = name.getRefersToFormula();
System.out.println("Formula = " + formula);
Now, I dont know how to get a handle to individual cell in this named range.
Can anyone please point me to the correct API that I can use?
Rgds
Sapan
There is an example from the Busy Developers' Guide for retrieving the cells in the range. Then you can use Cell.setCellValue() to update.
// setup code
String cname = "TestName";
Workbook wb = getMyWorkbook(); // retrieve workbook
// retrieve the named range
int namedCellIdx = wb.getNameIndex(cname);
Name aNamedCell = wb.getNameAt(namedCellIdx);
// retrieve the cell at the named range and test its contents
AreaReference aref = new AreaReference(aNamedCell.getRefersToFormula());
CellReference[] crefs = aref.getAllReferencedCells();
for (int i=0; i<crefs.length; i++) {
Sheet s = wb.getSheet(crefs[i].getSheetName());
Row r = s.getRow(crefs[i].getRow());
Cell c = r.getCell(crefs[i].getCol());
// extract the cell contents based on cell type etc.
}

Accessing Field Settings of Pivot Table using Apache POI

I am creating a workbook with a sheet populated data from a data source then creating a second sheet with a pivot table view of that data. Everything works fine, but I can't seem to change the default look of the pivot table. I am trying to get the setting ( Row Labels-->Click one from the list-->Field Settings-->Subtotals-->None and Row Labels-->Click one from the list-->Field Settings-->Layout & Print-->'Show item labels in tabular form' ) checked while creating the pivot table but couldn't find the handle / flag in the POI. Tried finding something under pivotTable.getCTPivotTableDefinition() or pivotTable.getCTPivotTableDefinition().getPivotTableStyleInfo(), but no lock. Please advise if there is a way to set these settings using poi during pivot table creation, not after the fact following the steps mentioned in the parenthesis. Here is my pivot table code :
XSSFSheet sheet = (XSSFSheet)wb.createSheet("Data");
...
...
//filling data sheet, skipping this part as it's not relevant
...
XSSFSheet pivotSheet = (XSSFSheet)wb.createSheet("Pivot Table");
AreaReference source = new AreaReference(sheet.getSheetName()+"!A$1:W$"+String.valueOf(sheet.getLastRowNum()));
CellReference position = new CellReference("A3");
XSSFPivotTable pivotTable = pivotSheet.createPivotTable(source, position);
/* Add filters */
pivotTable.addRowLabel(17);
pivotTable.addRowLabel(20);
pivotTable.addRowLabel(21);
pivotTable.addRowLabel(22);
pivotTable.addRowLabel(13);
pivotTable.addRowLabel(19);
pivotTable.addRowLabel(6);
pivotTable.addRowLabel(0);
pivotTable.addRowLabel(18);
pivotTable.addRowLabel(1);
pivotTable.addRowLabel(7);
pivotTable.addRowLabel(9);
Finally figured it out; lack of good documentation forced me to try a zillion things and finally was able to achieve what I wanted; here is the code :
for(CTPivotField ctPivotField:pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldList()){
ctPivotField.setAutoShow(false);
ctPivotField.setOutline(false);
ctPivotField.setSubtotalTop(false);
ctPivotField.setSubtotalCaption("");
}
instead of creating the pivot table every time, I created one template XLS file with all the desired styling and included that in the source, now I am opening that file filling the necessary data in the source tab, and saving the XLS file with the dynamic data with a different name; since the Pivot table tab is marked to refresh when opened, it does the work. Instead of going through the POI API with the limitations on Pivot Tables, creating a template and using it is much easier and flexible if you will generate the same styled pivot table for dynamic data.
#ninjaxelite here how it goes :
List<Object[]> resultSet = //get raw data
XSSFWorkbook wb = null;
try {
wb = new XSSFWorkbook(new FileInputStream(this.getClass().getResource("/content/XLS_template.xlsx").getPath()));
} catch (FileNotFoundException e1) {
//error
} catch (IOException e1) {
//error
}
Map<String, CellStyle> styles = createStyles(wb); // some local function to get styles
XSSFSheet sheet = (XSSFSheet)wb.getSheetAt(0);
XSSFRow row;
XSSFCell cell;
int rowNum = 0;
for (Object[] aRow : resultSet) {
rowNum++;
row = sheet.createRow(rowNum);
cell = row.createCell(0);
cell.setCellValue((String)aRow[0]);
cell.setCellStyle(styles.get("cell_normal_centered"));
...
..
.

Categories