I am trying to set up a knitr::knit_hooks()
to automatically format data frame output of an R-markdown chunk with kableExtra
in my HTML report.
I would like to not repeatedly add the following lines (or any lines) to the end of each chunk of tabulated data:
head(iris) %>%
kable("html") %>%
kable_styling("hover", full_width = FALSE)
I came up with one solution based on this answer that works by evaluating the chunk source (see my answer below that includes some issues that I have with this approach); I'm hoping there might be a better solution using the chunk output.
Here is an example .Rmd with an outline of what I would like to achieve.
---
title: "Untitled"
author: "Paul"
date: "25 September 2018"
output: html_document
---
```{r setup, include = F}
library(dplyr)
library(kableExtra)
library(knitr)
data(iris)
default_source_hook <- knit_hooks$get('source')
knit_hooks$set(
output = function(x, options) {
x %>%
kable("html") %>%
kable_styling("hover", full_width = FALSE)
},
source = function(x, options) {
if(is.null(options$table))
default_source_hook(x, options)
else {
eval(parse(text = x)) %>%
kable("html") %>%
kable_styling("hover", full_width = F)
}}
)
```
Desired chunk input:
```{r test, echo = F}
head(iris)
```
Desired output will look like:
```{r output, echo = F}
head(iris) %>%
kable("html") %>%
kable_styling("hover", full_width = FALSE)
```
Solution using the source chunk output:
```{r table_format, results = "hide", table = T, eval = F}
head(iris)
```
Thank you.
If using knit hooks is not necessary, the following might help. The idea is to just define a function that prints whatever it gets exactly the way you want. This does not eliminate all typing, but reduces it substantially.
---
title: "Untitled"
author: "Paul"
date: "25 September 2018"
output: html_document
---
```{r setup, include = F}
library(dplyr)
library(kableExtra)
library(knitr)
tbl_out <- function(data) {
data %>% kable("html") %>% kable_styling("hover", full_width = FALSE)
}
```
Prints as desired:
```{r test, echo = F}
head(iris) %>% tbl_out()
```
Output:
I found a work-around by using the knit_hooks()
source as the formatted chunk output.
The difficulty in formatting the chunk output is that character data is passed to the hook. Drawing inspiration from the linked answer in the OP, I found a solution by evaluating the chunk source in knit_hooks()
.
This solution re-evaluates the chunk and is piped into the desired KableExtra
formatting.
I needed to add a new chunk option table = T
so that the formatting was only applied to source code that produces a data table; results = "hide"
was also needed so the default chunk output was not included in the report.
---
title: "Untitled"
author: "Paul"
date: "27 September 2018"
output: html_document
---
```{r setup, include = F}
library(dplyr)
library(ggplot2)
library(kableExtra)
library(knitr)
default_source_hook <- knit_hooks$get('source')
knit_hooks$set(
source = function(x, options) {
if(is.null(options$table))
default_source_hook(x, options)
else {
eval(parse(text = x)) %>%
kable("html") %>%
kable_styling("hover", full_width = F)
}
}
)
data(iris)
```
## Normal
With no chunk options:
```{r normal}
head(iris)
```
## The desired ouptut
With chunk options `results = "hide"` and `table = T`:
```{r table_format, results = "hide", table = T, eval = F}
head(iris)
```
## It still work as normal for other other output types
With no chunk options:
```{r image}
iris %>%
ggplot(aes(x = Sepal.Length, y = Sepal.Width, group = Species)) +
geom_point()
```
There are a few problems with this solution
- the code used to produce the table is now unavailable
- eval = F should be included - especially if the code will take a while to run (as it is again evaluated in the hook)
- I'm replacing 2 lines of code with 3 chunk options - although not a deal killer it's not quite as automagical as I would have liked.