While the report generation functionality of pander
and
knitr
do overlap, we feel that the most powerful way to use
R/knitr/pander
for report generation is to utilize them
together. This short vignette aims to explain how to embed
pander
output in reports generated by knitr
.
If you are not aware of knitr
, be sure to check out the
project’s homepage for extensive
documentation and examples.
One of knitr
’s most useful features is the ability to
convert tables to output format on the fly. For example:
head(iris)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
::kable(head(iris)) knitr
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3.0 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5.0 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
However, kable
table generator is simple by design, and
does not capture all the variety of classes that R
has to
offer. For example, CrossTable
and tabular
are
not supported:
library(descr, quietly = TRUE)
<- CrossTable(mtcars$gear, mtcars$cyl)
ct #> Warning in chisq.test(tab, correct = FALSE, ...): Chi-squared approximation may
#> be incorrect
::kable(ct)
knitr#> Error in as.data.frame.default(x): cannot coerce class '"CrossTable"' to a data.frame
library(tables, quietly = TRUE)
<- tabular( (Species + 1) ~ (n=1) + Format(digits=2)*
tab + Sepal.Width)*(mean + sd), data=iris )
(Sepal.Length ::kable(tab) knitr
term | term | term | term | term |
---|---|---|---|---|
50 | 5.006 | 0.352489687213451 | 3.428 | 0.379064369096289 |
50 | 5.936 | 0.516171147063863 | 2.77 | 0.313798323378411 |
50 | 6.588 | 0.635879593274432 | 2.974 | 0.322496638172637 |
150 | 5.84333333333333 | 0.828066127977863 | 3.05733333333333 | 0.435866284936698 |
This is where pander
comes in handy, as
pander
supports rendering for many popular classes:
methods(pander)
#> [1] pander.Arima* pander.CrossTable* pander.Date*
#> [4] pander.Glm* pander.NULL* pander.POSIXct*
#> [7] pander.POSIXlt* pander.anova* pander.aov*
#> [10] pander.aovlist* pander.call* pander.cast_df*
#> [13] pander.character* pander.clogit* pander.coxph*
#> [16] pander.cph* pander.data.frame* pander.data.table*
#> [19] pander.default* pander.density* pander.describe*
#> [22] pander.ets* pander.evals* pander.factor*
#> [25] pander.formula* pander.ftable* pander.function*
#> [28] pander.glm* pander.gtable* pander.htest*
#> [31] pander.image* pander.irts* pander.list*
#> [34] pander.lm* pander.lme* pander.logical*
#> [37] pander.lrm* pander.manova* pander.matrix*
#> [40] pander.microbenchmark* pander.name* pander.nls*
#> [43] pander.numeric* pander.ols* pander.orm*
#> [46] pander.polr* pander.prcomp* pander.randomForest*
#> [49] pander.rapport* pander.rlm* pander.sessionInfo*
#> [52] pander.smooth.spline* pander.stat.table* pander.summary.aov*
#> [55] pander.summary.aovlist* pander.summary.glm* pander.summary.lm*
#> [58] pander.summary.lme* pander.summary.manova* pander.summary.nls*
#> [61] pander.summary.polr* pander.summary.prcomp* pander.summary.rms*
#> [64] pander.summary.survreg* pander.summary.table* pander.survdiff*
#> [67] pander.survfit* pander.survreg* pander.table*
#> [70] pander.tabular* pander.ts* pander.zoo*
#> see '?methods' for accessing help and source code
Also, pander
is integrated with knitr
by
default. pander
simply identifies if knitr
is
running in the background, and if so, it uses
capture.output
to return the resulting string as an
knit_asis
object, meaning that you do not need to specify
the results='asis'
option in your knitr chunk:
library(descr, quietly = TRUE)
pander(CrossTable(mtcars$gear, mtcars$cyl))
#> Warning in chisq.test(tab, correct = FALSE, ...): Chi-squared approximation may
#> be incorrect
mtcars$gear |
mtcars$cyl 4 |
6 |
8 |
Total |
---|---|---|---|---|
3 N Chi-square Row(%) Column(%) Total(%) |
1 3.3502 6.6667% 9.0909% 3.125% |
2 0.5003 13.3333% 28.5714% 6.250% |
12 4.5054 80.0000% 85.7143% 37.500% |
15 46.8750% |
4 N Chi-square Row(%) Column(%) Total(%) |
8 3.6402 66.6667% 72.7273% 25.000% |
4 0.7202 33.3333% 57.1429% 12.500% |
0 5.2500 0.0000% 0.0000% 0.000% |
12 37.5000% |
5 N Chi-square Row(%) Column(%) Total(%) |
2 0.0460 40.0000% 18.1818% 6.250% |
1 0.0080 20.0000% 14.2857% 3.125% |
2 0.0161 40.0000% 14.2857% 6.250% |
5 15.6250% |
Total |
11 34.375% |
7 21.875% |
14 43.75% |
32 |
library(tables, quietly = TRUE)
<- tabular( (Species + 1) ~ (n=1) + Format(digits=2)*
tab + Sepal.Width)*(mean + sd), data=iris )
(Sepal.Length pander(tab)
Species |
n |
Sepal.Length mean |
sd |
Sepal.Width mean |
sd |
---|---|---|---|---|---|
setosa | 50 | 5.01 | 0.35 | 3.43 | 0.38 |
versicolor | 50 | 5.94 | 0.52 | 2.77 | 0.31 |
virginica | 50 | 6.59 | 0.64 | 2.97 | 0.32 |
All | 150 | 5.84 | 0.83 | 3.06 | 0.44 |
In a nutshell, this is achieved by modification that whenever you
call pander
inside of a knitr
document,
instead of returning the markdown text to the standard output (the
default behavior), pander
returns a knit_asis
class object, which renders correctly in the resulting document —
without the double comment chars, thus properly rendering the tables in
HTML, PDF, or other document formats.
If you don’t want the results of pander
to be converted
automatically, just set knitr.auto.asis
to
FALSE
using panderOptions
:
panderOptions('knitr.auto.asis', FALSE)
pander(head(iris))
#>
#> -------------------------------------------------------------------
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> -------------- ------------- -------------- ------------- ---------
#> 5.1 3.5 1.4 0.2 setosa
#>
#> 4.9 3 1.4 0.2 setosa
#>
#> 4.7 3.2 1.3 0.2 setosa
#>
#> 4.6 3.1 1.5 0.2 setosa
#>
#> 5 3.6 1.4 0.2 setosa
#>
#> 5.4 3.9 1.7 0.4 setosa
#> -------------------------------------------------------------------
panderOptions('knitr.auto.asis', TRUE)
One frequenly asked question is how to use pander
with
knitr
in a loop or vectorized function. For example, we
have 3 tables that we want to render using lapply
:
<- list(mtcars[1:3, 1:4], mtcars[4:6, 1:4], mtcars[7:9, 1:4])
dfs lapply(dfs, pander)
#> [[1]]
#> [1] "\n---------------------------------------------\n mpg cyl disp hp \n------------------- ------ ----- ------ -----\n **Mazda RX4** 21 6 160 110 \n\n **Mazda RX4 Wag** 21 6 160 110 \n\n **Datsun 710** 22.8 4 108 93 \n---------------------------------------------\n\n"
#> attr(,"class")
#> [1] "knit_asis"
#> attr(,"knit_cacheable")
#> [1] NA
#>
#> [[2]]
#> [1] "\n-------------------------------------------------\n mpg cyl disp hp \n----------------------- ------ ----- ------ -----\n **Hornet 4 Drive** 21.4 6 258 110 \n\n **Hornet Sportabout** 18.7 8 360 175 \n\n **Valiant** 18.1 6 225 105 \n-------------------------------------------------\n\n"
#> attr(,"class")
#> [1] "knit_asis"
#> attr(,"knit_cacheable")
#> [1] NA
#>
#> [[3]]
#> [1] "\n-------------------------------------------\n mpg cyl disp hp \n---------------- ------ ----- ------- -----\n **Duster 360** 14.3 8 360 245 \n\n **Merc 240D** 24.4 4 146.7 62 \n\n **Merc 230** 22.8 4 140.8 95 \n-------------------------------------------\n\n"
#> attr(,"class")
#> [1] "knit_asis"
#> attr(,"knit_cacheable")
#> [1] NA
As you can see, this doesn’t work correctly because
pander
tries to return a knit_asis
class
object when run inside knitr
, but for loops/vectorized
functions this results in incorrect output. The recommended way to solve
this is to disable this behavior by setting knitr.auto.asis
to FALSE
using panderOptions
. However, we also
need to tell knitr
to convert the table on the fly by
specifying results='asis'
in the chunk options:
panderOptions('knitr.auto.asis', FALSE)
<- list(mtcars[1:3, 1:4], mtcars[4:6, 1:4], mtcars[7:9, 1:4])
dfs invisible(lapply(dfs, pander))
mpg | cyl | disp | hp | |
---|---|---|---|---|
Mazda RX4 | 21 | 6 | 160 | 110 |
Mazda RX4 Wag | 21 | 6 | 160 | 110 |
Datsun 710 | 22.8 | 4 | 108 | 93 |
mpg | cyl | disp | hp | |
---|---|---|---|---|
Hornet 4 Drive | 21.4 | 6 | 258 | 110 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 |
Valiant | 18.1 | 6 | 225 | 105 |
mpg | cyl | disp | hp | |
---|---|---|---|---|
Duster 360 | 14.3 | 8 | 360 | 245 |
Merc 240D | 24.4 | 4 | 146.7 | 62 |
Merc 230 | 22.8 | 4 | 140.8 | 95 |