A pivottabler
pivot table object has a fairly complex
internal structure - containing two trees of data groups (the row groups
and the column groups) plus a set of cells linked to the data
groups.
The pivottabler
package supports outputting a pivot
table in a number of different forms:
pt$renderPivot()
to
render the pivot table into the “Viewer” tab in R-Studio,pivottabler(pt)
to render the pivot table into the Shiny
app,pt$getHtml()
to retrieve a character variable
containing HTML, orpt$saveHtml()
to save the HTML to a file.pt$getLatex()
to retrieve a character
variable containing Latex.pt
to output to the console or
pt$asCharacter
to retrieve as a character value.Sometimes it is desirable to retrieve the pivot table results as a more standard data type that is easier to work with in R code. A pivot table can be converted to either a matrix or a data frame. Neither data type is a perfect representation of a pivot table - which option is better will depend upon your use case.
The following pivot table is used as the basis of the examples in the rest of this vignette:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$renderPivot()
A pivot table is outputted to the console as plain text simply by
using pt
:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt
DMU EMU HST Total
Arriva Trains Wales 3909 3909
CrossCountry 22196 732 22928
London Midland 11229 37050 48279
Virgin Trains 2137 6457 8594
Total 39471 43507 732 83710
Alternatively, the plain text representation of the pivot table can
be retrieved as a character value using pt$asCharacter
.
pt
and pt$asString
show the current state
of the pivot table. If the pivot table has not been evaluated (either by
using pt$evaluatePivot()
or pt$renderPivot()
)
then pt
and pt$asCharacter
will return the
headings only:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt
DMU EMU HST Total
Arriva Trains Wales
CrossCountry
London Midland
Virgin Trains
Total
A pivot table is outputted as a htmlwidget simply by calling
pt$renderPivot()
. There are numerous examples throughout
these vignettes, including the example directly above.
For outputting as a htmlwidget in a Shiny application, use
pivottabler(pt)
.
To retrieve the HTML of a pivot table, use pt$getHtml()
.
This returns a list of html tag objects built using the htmltools
package. This object can be converted to a simple character variable
using as.character()
or as illustrated below. The CSS
declarations for a pivot table can be retrieved using
pt$getCss()
- also illustrated below.
library(pivottabler)
library(htmltools)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
cat(paste(pt$getHtml(), sep="", collapse="\n"))
<table class="Table">
<tr>
<th class="RowHeader"> </th>
<th class="ColumnHeader">DMU</th>
<th class="ColumnHeader">EMU</th>
<th class="ColumnHeader">HST</th>
<th class="ColumnHeader">Total</th>
</tr>
<tr>
<th class="RowHeader">Arriva Trains Wales</th>
<td class="Cell">3909</td>
<td class="Cell"></td>
<td class="Cell"></td>
<td class="Total">3909</td>
</tr>
<tr>
<th class="RowHeader">CrossCountry</th>
<td class="Cell">22196</td>
<td class="Cell"></td>
<td class="Cell">732</td>
<td class="Total">22928</td>
</tr>
<tr>
<th class="RowHeader">London Midland</th>
<td class="Cell">11229</td>
<td class="Cell">37050</td>
<td class="Cell"></td>
<td class="Total">48279</td>
</tr>
<tr>
<th class="RowHeader">Virgin Trains</th>
<td class="Cell">2137</td>
<td class="Cell">6457</td>
<td class="Cell"></td>
<td class="Total">8594</td>
</tr>
<tr>
<th class="RowHeader">Total</th>
<td class="Total">39471</td>
<td class="Total">43507</td>
<td class="Total">732</td>
<td class="Total">83710</td>
</tr>
</table>
cat(pt$getCss())
.Table {display: table; border-collapse: collapse; }
.ColumnHeader {font-family: Arial; font-size: 0.75em; border: 1px solid lightgray; vertical-align: middle; font-weight: bold; background-color: #F2F2F2; padding: 2px; text-align: center; }
.RowHeader {font-family: Arial; font-size: 0.75em; border: 1px solid lightgray; vertical-align: middle; font-weight: bold; background-color: #F2F2F2; padding: 2px 8px 2px 2px; text-align: left; }
.Cell {font-family: Arial; font-size: 0.75em; padding: 2px 2px 2px 8px; border: 1px solid lightgray; vertical-align: middle; text-align: right; }
.OutlineColumnHeader {font-family: Arial; font-size: 0.75em; border: 1px solid lightgray; vertical-align: middle; font-weight: bold; background-color: #F2F2F2; padding: 2px; text-align: center; }
.OutlineRowHeader {font-family: Arial; font-size: 0.75em; border: 1px solid lightgray; vertical-align: middle; font-weight: bold; background-color: #F2F2F2; padding: 2px 8px 2px 2px; text-align: left; }
.OutlineCell {font-family: Arial; font-size: 0.75em; padding: 2px 2px 2px 8px; border: 1px solid lightgray; vertical-align: middle; text-align: right; background-color: #F8F8F8; font-weight: bold; }
.Total {font-family: Arial; font-size: 0.75em; padding: 2px 2px 2px 8px; border: 1px solid lightgray; vertical-align: middle; text-align: right; }
Please see the Latex Output vignette.
Please see the Excel Export vignette.
Converting a pivot table to a table from the flextabler
package is possible:
# construct the table
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
# convert to a basictabler table
library(basictabler)
tbl <- pt$asBasicTable()
# convert to flextable
library(flextable)
ft <- tbl$asFlexTable()
ft
DMU |
EMU |
HST |
Total |
|
Arriva Trains Wales |
3909 |
3909 |
||
CrossCountry |
22196 |
732 |
22928 |
|
London Midland |
11229 |
37050 |
48279 |
|
Virgin Trains |
2137 |
6457 |
8594 |
|
Total |
39471 |
43507 |
732 |
83710 |
Converting a pivot table to a Word document is possible using the
flextabler
package:
# construct the table
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
# convert to a basictabler table
library(basictabler)
tbl <- pt$asBasicTable()
# convert to flextable
library(flextable)
ft <- tbl$asFlexTable()
# save word document
library(officer)
docx <- read_docx()
docx <- body_add_par(docx, "Example Table")
docx <- body_add_flextable(docx, value = ft)
print(docx, target = "example_table_word.docx")
Converting a pivot table to a PowerPoint document is possible using
the flextabler
package:
# construct the table
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
# convert to a basictabler table
library(basictabler)
tbl <- pt$asBasicTable()
# convert to flextable
library(flextable)
ft <- tbl$asFlexTable()
# save PowerPoint document
library(officer)
ppt <- read_pptx()
ppt <- add_slide(ppt, layout = "Title and Content", master = "Office Theme")
ppt <- ph_with(ppt, value = ft, location = ph_location_left())
print(ppt, target = "example_table_powerpoint.pptx")
Converting a pivot table to a matrix is possible. The row/column headers become the row/column names in the matrix:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataMatrix()
DMU EMU HST Total
Arriva Trains Wales 3909 NA NA 3909
CrossCountry 22196 NA 732 22928
London Midland 11229 37050 NA 48279
Virgin Trains 2137 6457 NA 8594
Total 39471 43507 732 83710
If only the cell values are required, the headings can be removed
from the matrix by setting the includeHeaders
parameter to
FALSE
.
By default, asDataMatrix()
populates the matrix with the
raw cell values. Setting the rawValue
parameter to
FALSE
specifies that the matrix should contain the
formatted character
values instead of the raw values.
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataMatrix(rawValue=FALSE)
DMU EMU HST Total
Arriva Trains Wales "3909" NA NA "3909"
CrossCountry "22196" NA "732" "22928"
London Midland "11229" "37050" NA "48279"
Virgin Trains "2137" "6457" NA "8594"
Total "39471" "43507" "732" "83710"
When there are multiple levels of headers, headers are concatenated. A separator can be specified:
library(dplyr)
library(pivottabler)
data <- filter(bhmtrains, (Status=="A")|(Status=="C"))
pt <- PivotTable$new()
pt$addData(data)
pt$addColumnDataGroups("PowerType", addTotal=FALSE)
pt$addColumnDataGroups("Status", addTotal=FALSE)
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$renderPivot()
pt$asDataMatrix(separator="|")
DMU|A DMU|C EMU|A EMU|C HST|A HST|C
Arriva Trains Wales 3833 74 NA NA NA NA
CrossCountry 21621 548 NA NA 709 23
London Midland 11054 168 35930 1082 NA NA
Virgin Trains 2028 107 6331 119 NA NA
Total 38536 897 42261 1201 709 23
character
matrix
It is also possible to convert a pivot table to a
character
matrix, where the row/column names are within the
body of the matrix:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asMatrix()
[,1] [,2] [,3] [,4] [,5]
[1,] "" "DMU" "EMU" "HST" "Total"
[2,] "Arriva Trains Wales" "3909" "" "" "3909"
[3,] "CrossCountry" "22196" "" "732" "22928"
[4,] "London Midland" "11229" "37050" "" "48279"
[5,] "Virgin Trains" "2137" "6457" "" "8594"
[6,] "Total" "39471" "43507" "732" "83710"
If only the cell values are required, the headings can be removed
from the matrix by setting the includeHeaders
parameter to
FALSE
.
When there are multiple levels of headers, by default the column headers are not repeated:
library(dplyr)
library(pivottabler)
data <- filter(bhmtrains, (Status=="A")|(Status=="C"))
pt <- PivotTable$new()
pt$addData(data)
pt$addColumnDataGroups("PowerType", addTotal=FALSE)
pt$addColumnDataGroups("Status", addTotal=FALSE)
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$renderPivot()
pt$asMatrix()
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] "" "DMU" "" "EMU" "" "HST" ""
[2,] "" "A" "C" "A" "C" "A" "C"
[3,] "Arriva Trains Wales" "3833" "74" "" "" "" ""
[4,] "CrossCountry" "21621" "548" "" "" "709" "23"
[5,] "London Midland" "11054" "168" "35930" "1082" "" ""
[6,] "Virgin Trains" "2028" "107" "6331" "119" "" ""
[7,] "Total" "38536" "897" "42261" "1201" "709" "23"
However, the repeatHeaders
parameter can be used to
specify repeating headings:
pt$asMatrix(repeatHeaders=TRUE)
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] "" "DMU" "DMU" "EMU" "EMU" "HST" "HST"
[2,] "" "A" "C" "A" "C" "A" "C"
[3,] "Arriva Trains Wales" "3833" "74" "" "" "" ""
[4,] "CrossCountry" "21621" "548" "" "" "709" "23"
[5,] "London Midland" "11054" "168" "35930" "1082" "" ""
[6,] "Virgin Trains" "2028" "107" "6331" "119" "" ""
[7,] "Total" "38536" "897" "42261" "1201" "709" "23"
Two different functions can be used to convert a pivot table to a
data frame. The asDataFrame()
function returns a data frame
with a roughly similar layout to the pivot table, e.g. a pivot table
with a body consisting of 10 rows and 2 columns will result in a data
frame also containing 10 rows and 2 columns. The
asTidyDataFrame()
function returns a data frame consisting
of one row for every cell in the body of the pivot table, e.g. a pivot
table with a body consisting of 10 rows and 2 columns will result in a
data frame containing 20 rows.
Examples of both functions are given below.
asDataFrame()
function
The example pivot table converts as follows:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
df <- pt$asDataFrame()
df
DMU EMU HST Total
Arriva Trains Wales 3909 NA NA 3909
CrossCountry 22196 NA 732 22928
London Midland 11229 37050 NA 48279
Virgin Trains 2137 6457 NA 8594
Total 39471 43507 732 83710
str(df)
'data.frame': 5 obs. of 4 variables:
$ DMU : int 3909 22196 11229 2137 39471
$ EMU : int NA NA 37050 6457 43507
$ HST : int NA 732 NA NA 732
$ Total: int 3909 22928 48279 8594 83710
Data frames can have at most one name for each row and column. Therefore, when there are multiple levels of headers in the pivot table, the captions are concatenated into a single value for each row and column:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("TrainCategory")
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataFrame()
Express Passenger DMU Express Passenger EMU
Arriva Trains Wales 3079 NA
CrossCountry 22133 NA
London Midland 5638 8849
Virgin Trains 2137 6457
Total 32987 15306
Express Passenger HST Express Passenger Total
Arriva Trains Wales NA 3079
CrossCountry 732 22865
London Midland NA 14487
Virgin Trains NA 8594
Total 732 49025
Ordinary Passenger DMU Ordinary Passenger EMU
Arriva Trains Wales 830 NA
CrossCountry 63 NA
London Midland 5591 28201
Virgin Trains NA NA
Total 6484 28201
Ordinary Passenger Total Total
Arriva Trains Wales 830 3909
CrossCountry 63 22928
London Midland 33792 48279
Virgin Trains NA 8594
Total 34685 83710
The space character is the default character used to combine headers as seen above. This can easily be changed, e.g. to a pipe character:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("TrainCategory")
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataFrame(separator="|")
Express Passenger|DMU Express Passenger|EMU
Arriva Trains Wales 3079 NA
CrossCountry 22133 NA
London Midland 5638 8849
Virgin Trains 2137 6457
Total 32987 15306
Express Passenger|HST Express Passenger|Total
Arriva Trains Wales NA 3079
CrossCountry 732 22865
London Midland NA 14487
Virgin Trains NA 8594
Total 732 49025
Ordinary Passenger|DMU Ordinary Passenger|EMU
Arriva Trains Wales 830 NA
CrossCountry 63 NA
London Midland 5591 28201
Virgin Trains NA NA
Total 6484 28201
Ordinary Passenger|Total Total|
Arriva Trains Wales 830 3909
CrossCountry 63 22928
London Midland 33792 48279
Virgin Trains NA 8594
Total 34685 83710
In addition, the row group headings can be exported as separate columns:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("TrainCategory")
pt$addRowDataGroups("TOC")
pt$addRowDataGroups("PowerType")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataFrame(rowGroupsAsColumns=TRUE)
TOC PowerType Express Passenger
Arriva Trains Wales DMU Arriva Trains Wales DMU 3079
Arriva Trains Wales Total Arriva Trains Wales Total 3079
CrossCountry DMU CrossCountry DMU 22133
CrossCountry HST CrossCountry HST 732
CrossCountry Total CrossCountry Total 22865
London Midland DMU London Midland DMU 5638
London Midland EMU London Midland EMU 8849
London Midland Total London Midland Total 14487
Virgin Trains DMU Virgin Trains DMU 2137
Virgin Trains EMU Virgin Trains EMU 6457
Virgin Trains Total Virgin Trains Total 8594
Total Total 49025
Ordinary Passenger Total
Arriva Trains Wales DMU 830 3909
Arriva Trains Wales Total 830 3909
CrossCountry DMU 63 22196
CrossCountry HST NA 732
CrossCountry Total 63 22928
London Midland DMU 5591 11229
London Midland EMU 28201 37050
London Midland Total 33792 48279
Virgin Trains DMU NA 2137
Virgin Trains EMU NA 6457
Virgin Trains Total NA 8594
Total 34685 83710
asTidyDataFrame()
function
The example pivot table converts as follows:
library(pivottabler)
pt <- PivotTable$new()
pt$addData(bhmtrains)
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
pt$asDataFrame()
DMU EMU HST Total
Arriva Trains Wales 3909 NA NA 3909
CrossCountry 22196 NA 732 22928
London Midland 11229 37050 NA 48279
Virgin Trains 2137 6457 NA 8594
Total 39471 43507 732 83710
df <- pt$asTidyDataFrame()
str(df)
'data.frame': 20 obs. of 11 variables:
$ rowNumber : int 1 1 1 1 2 2 2 2 3 3 ...
$ columnNumber : int 1 2 3 4 1 2 3 4 1 2 ...
$ isTotal : logi FALSE FALSE FALSE TRUE FALSE FALSE ...
$ RowLevel01 : chr "Arriva Trains Wales" "Arriva Trains Wales" "Arriva Trains Wales" "Arriva Trains Wales" ...
$ ColumnLevel01 : chr "DMU" "EMU" "HST" "Total" ...
$ TOC : chr "Arriva Trains Wales" "Arriva Trains Wales" "Arriva Trains Wales" "Arriva Trains Wales" ...
$ PowerType : chr "DMU" "EMU" "HST" "NA" ...
$ calculationName : chr "TotalTrains" "TotalTrains" "TotalTrains" "TotalTrains" ...
$ calculationGroupName: chr "default" "default" "default" "default" ...
$ rawValue : int 3909 NA NA 3909 22196 NA 732 22928 11229 37050 ...
$ formattedValue : chr "3909" NA NA "3909" ...
head(df)
rowNumber columnNumber isTotal RowLevel01 ColumnLevel01
1 1 1 FALSE Arriva Trains Wales DMU
2 1 2 FALSE Arriva Trains Wales EMU
3 1 3 FALSE Arriva Trains Wales HST
4 1 4 TRUE Arriva Trains Wales Total
5 2 1 FALSE CrossCountry DMU
6 2 2 FALSE CrossCountry EMU
TOC PowerType calculationName calculationGroupName rawValue
1 Arriva Trains Wales DMU TotalTrains default 3909
2 Arriva Trains Wales EMU TotalTrains default NA
3 Arriva Trains Wales HST TotalTrains default NA
4 Arriva Trains Wales NA TotalTrains default 3909
5 CrossCountry DMU TotalTrains default 22196
6 CrossCountry EMU TotalTrains default NA
formattedValue
1 3909
2 <NA>
3 <NA>
4 3909
5 22196
6 <NA>
By default the generated pivot table contains columns for both the
captions of the data groups and the variables/values that the data
groups represent. Each of these sets of columns can be removed from the
data frame by setting includeGroupCaptions=FALSE
or
includeGroupValues=FALSE
respectively.
Where a data group represents multiple values, those values are
concatenated and returned in a single column in the data frame. Again,
the separator between the values can be changed, e.g. by specifying
separator="|"
.
The asBasicTable()
function allows a pivot table to be
converted to a basic table - from the basictabler
package.
The basictabler
package allows free-form tables to be
constructed, in contrast to pivottabler
which creates pivot
tables with relatively fixed structures. pivottabler
contains calculation logic - to calculate the values of cells within the
pivot table. basictabler
contains no calculation logic -
cell values must be provided either from a data frame, row-by-row,
column-by-column or cell-by-cell.
Converting a pivot table to a basic table allows the structure of pivot tables to be altered after they have been created, e.g.
library(pivottabler)
library(dplyr)
library(lubridate)
trains <- mutate(bhmtrains,
GbttDate=if_else(is.na(GbttArrival), GbttDeparture, GbttArrival),
GbttMonth=make_date(year=year(GbttDate), month=month(GbttDate), day=1))
pt <- PivotTable$new()
pt$addData(trains)
pt$addColumnDataGroups("GbttMonth", dataFormat=list(format="%B %Y"))
pt$addColumnDataGroups("PowerType")
pt$addRowDataGroups("TOC")
pt$defineCalculation(calculationName="TotalTrains", summariseExpression="n()")
pt$evaluatePivot()
# convert the pivot table to a basic table, insert a new row, merge cells and highlight
bt <- pt$asBasicTable()
bt$cells$insertRow(5)
bt$cells$setCell(5, 2, rawValue="The values below are significantly higher than expected.",
styleDeclarations=list("text-align"="left", "background-color"="yellow",
"font-weight"="bold", "font-style"="italic"))
bt$mergeCells(rFrom=5, cFrom=2, rSpan=1, cSpan=13)
bt$setStyling(rFrom=6, cFrom=2, rTo=6, cTo=14,
declarations=list("text-align"="left", "background-color"="yellow"))
bt$renderTable()