---
title: "Lemon print -- pretty printing data frames and tables"
author: "Stefan McKinnon Edwards <sme@iysik.com>"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    fig_caption: yes
vignette: >
  %\VignetteIndexEntry{Lemon print -- pretty printing data frames and tables}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

This vignette demonstrates how load the `lemon` package automatically
enables pretty printing of data frames with knitr's `kable`.

The beauty of defining the function `knit_print.data.frame` is that when
working with R Notebooks in R, the editor can output the data frame dynamically,
while ensuring that the knitted document also has the 


```{r setup,include=FALSE}
library(knitr)
library(stringr)

knitr::opts_chunk$set(fig.height=4, fig.width=6, verbatim=FALSE,
                      cache=FALSE, autodep = TRUE, cache.path='lemon_print-cache/')

# Show chunk verbatim
# Source: https://stackoverflow.com/questions/19908158/show-an-r-markdown-chunk-in-the-final-output
# Set verbatim option as last and it will not be printed. ;)
hook_source_def = knit_hooks$get('source')
knit_hooks$set(source = function(x, options){
  if (!is.null(options$verbatim) && options$verbatim){
    opts = gsub(",\\s*verbatim\\s*=\\s*TRUE\\s*", "", options$params.src)
    bef = sprintf('\n\n    ```{r %s}\n', opts)
    stringr::str_c(bef, paste(knitr:::indent_block(x, "    "), collapse = '\n'), "\n    ```\n\n")
  } else {
     hook_source_def(x, options)
  }
})

```

First we load some data and show the top.
```{r}
data(USArrests)
head(USArrests)
```

Now load `lemon` and set the `lemon_print` functions.

```{r message=FALSE}
library(lemon)
knit_print.data.frame <- lemon_print
```

**The same view is now nicely printed!**

```{r caption="Data frame is now printed using `kable`.",verbatim=TRUE,render=lemon_print}
head(USArrests)
```

Notice how we specified `kable` arguments directly as chunk-options.

## How it works

knitr uses a S3 generic function, `knit_print`, to print objects. 
[Method dispatching in R ](http://adv-r.had.co.nz/S3.html) means that by 
defining a function, say `knit_print.data.frame`, calling `knit_print(df)` will
call our function *if* `df` was a data frame.

To have knitr use our function when outputting a data frame, we define the 
function `knit_print.data.frame` (and similar for data frames passed through
dplyr functions, i.e `tbl_df` and `grouped_df`).

Disabling the function is by usual chunk options, `render = normal_print`.
check `?knit_print`.

**Disabling the functions.**

```{r normal_print,render=normal_print,verbatim=TRUE}
head(USArrests)
```

You can still ask for `kable`.

```{r results='asis',render=normal_print,verbatim=TRUE}
kable(head(USArrests),caption='Normal `kable` usage.')
```



### It uses kable

We have mentioned `kable` a couple of times.
That is because the `lemon_print` for data frames uses 
`kable` of the knitr package.

**Some common arguments:**

* `caption`: Table caption. See examples in demonstration.
* `align`: Vector of column alignments with `'l'`, `'c'`, and `'r'`.
Or, a single element, i.e. `c('c','l','r') = 'clr')`.
* `row.names`: A logical value indicating whether to include row names.
* `col.names`: A character vector of column names to be used in the table.

## Why does it matter

The second code block, when edited in RStudio, would look like this:
![Viewing data frames in R Notebooks in RStudio](lemon_print_capture.png)
And, as demonstrated, the rendered document has the data frame printed nicely.

If we do not wish this behaviour, but still use `kable`,
```{r}
kable(head(USArrests))
```

RStudio would look like this:
![RStudio renders kable'd data frames rather eh](lemon_print_capture2.png)

## Other objects covered

Summaries are nicely formatted, but these require setting the S3 method for 
`table`.

```{r kable.opts=list(caption='Summary tables are printed with some default options.'),verbatim=TRUE}
knit_print.table <- lemon_print
summary(USArrests)
```

Cross-tabulations are however not nicely formatted.

```{r mtcars}
head(mtcars)
with(mtcars, table(cyl, gear))
```


### dplyr

```{r}
library(dplyr)
knit_print.tbl <- lemon_print
```

```{r dplyr,kable.opts=list(caption='Also works on `dplyr` objects.'),verbatim=TRUE}
mtcars %>% group_by(cyl) %>% summarise(mean(disp))
```
