7

I would like to be able to create RMarkdown chuncks in a loop. I have tried doing this through a for loop, without much success. I imagine this could probably be possible through lapply, as one would do for creating UIs in a shiny app. However, I haven't had any success so far.

Reprex:

---
title: "Untitled"
output:
  html_document:
    theme: united
    highlight: tango
    toc: true
    toc_float:
      collapsed: false
      smooth_scroll: false
---

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

```{r}
library(dplyr)
library(ggplot2)

df <- datasets::iris %>% 
  dplyr::as_tibble()
```

## setosa

```{r}
df %>% 
  dplyr::filter(Species == "setosa") %>% 
  ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) + 
  ggplot2::geom_point()
```

## versicolor

```{r}
df %>% 
  dplyr::filter(Species == "versicolor") %>% 
  ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) + 
  ggplot2::geom_point()
```

## virginica

```{r}
df %>% 
  dplyr::filter(Species == "virginica") %>% 
  ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) + 
  ggplot2::geom_point()
```

My goal is to create the headings (setosa, versicolor, and virginica) and the chuncks with a loop.

For example:

for(i in c("setosa", "versicolor", "virginica")) {

  ## i

  df %>% 
    dplyr::filter(Species == i) %>% 
    ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) + 
    ggplot2::geom_point()
}

Any ideas on how accomplish this?

jay.sf
  • 60,139
  • 8
  • 53
  • 110
FMM
  • 1,857
  • 1
  • 15
  • 38
  • Do you need the repeated code to show up in the output? Or do you just need to have the heading for each group, and then the resulting plot under that? – Marius Jul 15 '19 at 06:55
  • just the heading and the resulting plot :) – FMM Jul 15 '19 at 06:56
  • 1
    Maybe [this](https://stackoverflow.com/questions/19080917/dynamic-number-of-calls-to-a-chunk-with-knitr) is what you need. – Stéphane Laurent Jul 15 '19 at 07:03

2 Answers2

7

If you want to create headings + outputs within a loop, you can do:

```{r species_loop, results='asis'}
for(i in c("setosa", "versicolor", "virginica")) {

  cat(paste0("\n\n## ", i, "\n"))

  p <- df %>% 
    dplyr::filter(Species == i) %>% 
    ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) + 
    ggplot2::geom_point()
  print(p)
}
```

So:

  • Using results='asis' to allow output that you cat() to be interpreted as Markdown syntax
  • cat()ing the required markdown syntax to produce the headers (surrounded by some newlines to make sure it's interpreted properly)
  • Explicitly print()ing the plot within the loop.
Marius
  • 58,213
  • 16
  • 107
  • 105
2

A function based on cat would replicate your chunks for every iris species. For the one-time chunks use single cats.

FUN <- function(x) cat("\n##", x, "
```{r}
df %>%
  dplyr::filter(Species == ",x, ") %>%
  ggplot2::ggplot(ggplot2::aes(Sepal.Length, Petal.Length)) +
  ggplot2::geom_point()
```\n")

To produce the shown .Rmd file, you could use sink. (For sake of brevity I'll omit the header here.)

sink(file="iris.Rmd")  ## start `sink`

cat("```{r}
library(dplyr)
library(ggplot2)
df <- datasets::iris %>% 
  dplyr::as_tibble()
```")

invisible(sapply(c("'setosa'", "'versicolor'", "'virginica'"), FUN))

sink()  ## end `sink`

You'll find your .Rmd file in your working directory (getwd()).

jay.sf
  • 60,139
  • 8
  • 53
  • 110