pav
pav

Reputation: 333

why does kable not print when used within a function in rmarkdown

I have to repeat certain outputs in many rmarkdown reports and want to write a function to use for this.

Calling a function outputs plots ok when I knit the rmd file but not kable data frames.

For example

---
title: "Markdown example"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# Markdown example
```{r mtcars}
make_outputs <- function(){
  knitr::kable(head(mtcars))
  plot(mtcars$mpg, mtcars$cyl)
  hist(mtcars$cyl)
}

make_outputs()

```

Displays the plots but not the kable table.

Upvotes: 19

Views: 13005

Answers (4)

dww
dww

Reputation: 31454

The problem seems to be related to knitr::kable incorrectly detecting the environment for the printing when it is embedded inside a function. This interferes with its ability to correctly figure out how to format. We can hack around this by placing the object to print in the top level environment before we print it.

---
title: "Markdown example"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
print_kable = function(x) {
  print(kable_print_output <<- x)
  cat('\n')
}
```

# Markdown example
```{r mtcars, results='asis'}
make_outputs <- function() {
  print_kable(knitr::kable(head(mtcars)))
  plot(mtcars$mpg, mtcars$cyl)
  print_kable(knitr::kable(tail(mtcars)))
  }

make_outputs()
```

Upvotes: 2

PKumar
PKumar

Reputation: 11128

Using a return statement with all objects in a list can help here, You can try recordPlot or plot from base R to solve your problem, By putting each of these plots in list, I managed to get the plots along with your table. Changed your code a bit in return statement to plot each of the plots along with tables like this.

Option1: Using list in return with all the objects binded together without using lapply in function call

---
title: "Markdown example"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# Markdown example
```{r mtcars}
make_outputs <- function(){

  return(list(hist(mtcars$cyl), 
              knitr::kable(head(mtcars)),
  plot(mtcars$mpg, mtcars$cyl)))
}

make_outputs()

```    

Another version (In case you don't want the code to print hist output to your html then you can use below function to suppress it.

make_outputs <- function(){

  h1 <- plot(hist(mtcars$cyl, plot=FALSE))
  h2 <- knitr::kable(head(mtcars))
  h3 <- plot(mtcars$mpg, mtcars$cyl)

  return(list(h1, h2, h3))
}

Option2: Another (better version by using invisible function on lapply to suppress NULL printing, then using results='asis' option in the markdown settings as below gives a clean output than earlier.

---
title: "Markdown example"
output: html_document
---

knitr::opts_chunk$set(echo = FALSE)
knitr::opts_knit$set(root.dir= normalizePath('..'))
knitr::opts_chunk$set(error = FALSE)

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# Markdown example
```{r mtcars, results='asis'}
make_outputs <- function(){

  return(list(plot(hist(mtcars$cyl, plot =FALSE)), 
              knitr::kable(head(mtcars)),
  plot(mtcars$mpg, mtcars$cyl)))
}

invisible(lapply(make_outputs(), print))

```   

This has given me a histogram, a scatter plot and a table in the knitted html document. Hope this helps, Not sure though if you wanted this way. Please let me know in case you wanted in any other way.

Upvotes: 4

George Savva
George Savva

Reputation: 5336

You can do this by using print to print the kable output, setting the results="asis" of the code chunk and then using kable_styling from package kableExtra.

This works for me:

```{r mtcars, results='asis'}

library(kableExtra)
library(knitr)

make_outputs <- function(){
  print(kable_styling(kable(head(mtcars))))
  plot(mtcars$mpg, mtcars$cyl)
  hist(mtcars$cyl)
}

make_outputs()
```

Upvotes: 8

BradlesP
BradlesP

Reputation: 9

I got something similar working by

  • moving the knitr::kable(head(mtcars)) inside a return() at the end of the function.
  • including results = 'asis'

e.g.

---
title: "Markdown example"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# Markdown example
```{r  results = 'asis'}
make_outputs <- function(){

print(plot(mtcars$mpg, mtcars$cyl))
print(hist(mtcars$cyl))

return(knitr::kable(head(mtcars)))
}

make_outputs()

```

If you use ggplot for plots, you will need to wrap your plot inside print()

Upvotes: 0

Related Questions