R knitr: Possible to programmatically modify chunk labels?

Solution 1:

For anyone else who comes across this post, I wanted to point out that @Yihui has provided a formal solution to this question in knitr 1.0 with the introduction of the knit_expand() function. It works great and has really simplified my workflow.

For example, the following will process the template script below for every level of mtcars$cyl, each time replacing all instances of {{ncyl}} (in the template) with its current value:

# My report

```{r}
data(mtcars)
cyl.levels <- unique(mtcars$cyl)
```

## Generate report for each level of cylinder variable
```{r, include=FALSE}
src <- lapply(cyl.levels, function(ncyl) knit_expand(file = "template.Rmd"))
```

`r knit(text = unlist(src))`

Template:

```{r, results='asis'}
cat("### {{ncyl}} cylinders")
```

```{r mpg-histogram-{{ncyl}}cyl}
hist(mtcars$mpg[mtcars$cyl == {{ncyl}}], 
  main = paste({{ncyl}}, "cylinders"))
```

```{r weight-histogam-{{ncyl}}cyl}
hist(mtcars$wt[mtcars$cyl == {{ncyl}}], 
  main = paste({{ncyl}}, "cylinders"))
```

Solution 2:

If you make all chunks in your ** nameless, i.e. ```{r} it works. This, of course, is not very elegant, but there are two issues preventing you from changing the label of the current chunk:

  1. A file is parsed before the code blocks are executed. The parser already detects duplicate labels, before any code is executed or custom hooks are called.
  2. The chunk options (inc. the label) are processed before the hook is called (logical: it's an option that triggers a hook), so the hook cannot change the label anymore.

The fact that unnamed blocks work is that internally they get the label unnamed-chunk-+chunk number.

Blocks cannot have duplicate names as internally knitr references them by label. A fix could be to make knitr add the chunk number to all chunks with duplicate names. Or to reference them by chunk number instead of label, but that seems to me a much bigger change.

Solution 3:

There is a similar question posed here I was able to programmatically create r chunks and knit the outputs for use in a flexdashboard (quite useful) based on an arbitrary list of input plots using the knit_expand(text=) and r paste(knitr::knit(text = paste(out, collapse = '\n'))) methods.