Search code examples
rr-markdown

How can I use a loop in RMarkdown to programmatically plot figures and text on individual pages in a document?


The code below will run in an .Rmd file to loop through a list and, using the element at position i in the list, plot a figure. Each figure is plotted on a new page, so that each page only contains one figure.

Note that I added apostrophes before the triple dash to improve readability here.

---
output: word_document
---

'```{r setup, echo=FALSE, include=FALSE}
library(tidyverse)

make_df <- function(z){
  tibble(X = runif(n = 10, min = z, max = z * 2), Y = runif(n = 10, min = z, max = z * 2))
  }

'```

'```{r plots, results='asis', warning=FALSE, message=FALSE, echo=FALSE}

newslide <- function(options = "", heading = "", content) {
  code <- deparse(substitute(content))
  
  cat(sep = "\n", 
      knitr::knit_child(
        quiet = TRUE, 
        text = knitr::knit_expand(text = c("```{r {{options}} }", "{{code}}", "```"))))
}


for (i in 1:3) {
newslide(
  options = paste0("fig.width=6.5, fig.height=8.8, dpi = 600, warning=FALSE, message=FALSE, echo=FALSE"),
  content = plot(make_df(i))
)
}
'```

All that works well! However, I don't just want figures, I want text, too. I need a block of nicely formattable text (eg I want to be able to set the color, font family, size, etc) to print below each figure and for it not to ## look like this (I was able to get the contraindicated formatting by adding + cat("xyz") in the content variable).

The text can be identical, it's just a caption that will apply to each figure, but I do want it to print and be editable, ie not part of the plot.


Solution

  • In the text argument of knit_child(), you can add code as if you were writing both inside and outside a R chunk, like this:

    newslide <- function(options = "", heading = "", content) {
      code <- deparse(substitute(content))
      
      cat(sep = "\n", 
          knitr::knit_child(
            quiet = TRUE, 
            #text = knitr::knit_expand(text = c("```{r {{options}} }", "{{code}}", "```"))))
            text = c("### Header 3",
        "```{r results = 'asis'}", #the r chunk
        "#| echo: false", #options for the chunk, you can delete this if not using Quarto
        code, 
        "```",
        "",
        "Text that will be below your plot, formatted with **markdown** and all")
          )
      )
    }