Jonny
Jonny

Reputation: 2783

Print RMarkdown captions from a loop

I am creating a series of plots from within a loop in an RMarkdown document, then knitting this to a PDF. I can do this without any problem, but I would like the caption to reflect the change between each plot. A MWE is shown below:

---
title: "Caption loop"
output: pdf_document
---

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

p <- 
  map(names(mtcars), ~ggplot(mtcars) +
      geom_point(aes_string(x = 'mpg', y = .))) %>% 
  set_names(names(mtcars))
```

```{r loops, fig.cap=paste(for(i in seq_along(p)) print(names(p)[[i]])), echo=FALSE}
for(i in seq_along(p)) p[[i]] %>% print
```

I have made a first attempt at capturing the plots and storing in a variable p, and trying to use that to generate the captions, but this isn't working. I haven't found too much about this on SO, despite this surely being something many people would need to do. I did find this question, but it looks so complicated that I was wondering if there is a clear and simple solution that I am missing.

I wondered if it has something to do with eval.after, as with this question, but that does not involve plots generated within a loop.

many thanks for your help!

Upvotes: 5

Views: 2043

Answers (2)

LiamS
LiamS

Reputation: 81

In case this might be useful to somebody. Here is an adaptation of Jonny's solution for captions without printing list indices. This can be achieved by using purrr::walk instead of purrr::map. Also included is a latex fig label and text that references each plot.

---
title: "Loop figures with captions"
output: 
    pdf_document
---


```{r loops, fig.cap=paste(sprintf("\\label{%s}", names(mtcars)), "Graph of mpg vs.", names(mtcars)),results='asis', message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)
library(stringi)
walk(names(mtcars),
     ~{
         p <- ggplot(mtcars) +
             geom_point(aes_string(x = 'mpg', y = .))
         #print plot
         cat('\n\n') 
         print(p)
         #print text with refernce to plot
         cat('\n\n') 
         cat(sprintf("Figure \\ref{%s} is a Graph of mpg vs. %s. %s \n\n", ., ., 
                     stri_rand_lipsum(1)))
         cat("\\clearpage")
     })
```

Upvotes: 1

Jonny
Jonny

Reputation: 2783

It seems that knitr is smart enough to do the task automatically. By adding names(mtcars) to the figure caption, knitr iterates through these in turn to produce the correct caption. The only problem now is how to stop all of the list indexes from printing in the document...

---
title: "Caption loop"
output: pdf_document
---

```{r loops, fig.cap=paste("Graph of mpg vs.", names(mtcars)), message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)

map(
  names(mtcars),
  ~ ggplot(mtcars) +
    geom_point(aes_string(x = 'mpg', y = .))
)
```

Upvotes: 4

Related Questions