---
title: "Using pander with knitr"
author: "Roman Tsegelskyi, Gergely Daróczi"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Using pander with knitr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, echo = FALSE, message = FALSE}
knitr::opts_chunk$set(collapse = T, comment = "#>")
library(pander)
library(knitr)
```

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](https://yihui.org/knitr/) 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:

```{r}
head(iris)
knitr::kable(head(iris))
```

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:

```{r, error = TRUE}
library(descr, quietly = TRUE)
ct <- CrossTable(mtcars$gear, mtcars$cyl)
knitr::kable(ct)
library(tables, quietly = TRUE)
tab <- tabular( (Species + 1) ~ (n=1) + Format(digits=2)*
         (Sepal.Length + Sepal.Width)*(mean + sd), data=iris )
knitr::kable(tab)
```

This is where `pander` comes in handy, as `pander` supports rendering for many popular classes:

```{r}
methods(pander)
```

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:

```{r, error = TRUE}
library(descr, quietly = TRUE)
pander(CrossTable(mtcars$gear, mtcars$cyl))
library(tables, quietly = TRUE)
tab <- tabular( (Species + 1) ~ (n=1) + Format(digits=2)*
         (Sepal.Length + Sepal.Width)*(mean + sd), data=iris )
pander(tab)
```

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`:

```{r}
panderOptions('knitr.auto.asis', FALSE)
pander(head(iris))
```
```{r}
panderOptions('knitr.auto.asis', TRUE)
```

#### Rendering markdown inside loop/vectorized function

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`:

```{r}
dfs <- list(mtcars[1:3, 1:4], mtcars[4:6, 1:4], mtcars[7:9, 1:4])
lapply(dfs, pander)
```

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:

```{r results='asis'}
panderOptions('knitr.auto.asis', FALSE)
dfs <- list(mtcars[1:3, 1:4], mtcars[4:6, 1:4], mtcars[7:9, 1:4])
invisible(lapply(dfs, pander))
```
