knitr chunk labels.In response to this stackoverflow question.
The original question asked about modifying, well instead of modifying this will generate the chunks which, when knitted, will run the reusable histogram generators for mpg and weight by cylinders.
We can take advantage of brew to generate chunks from a template, and then have knitr execute the Rmarkdown to produce and execute the desired chunks.
When setting up the reusable chunks expect errors and messages which can be suppressed as garbage. All that is wanted is to load the chunks into the knitting environment.
```{r setup-reusable, echo=TRUE, message=FALSE, warning=FALSE, error=FALSE, results='hide'}
# Prepare some yarn.
knit_child( "child-chunks.Rmd" )
```
Look in child-chunks.Rmd for the reusable chunks including a single prestiched chunk.
```{r generate-report}
# A prestiched pattern.
run_chunk('iterate')
run_chunk('mpg-histogram')
run_chunk('weight-histogram')
````
This can be knitted in at any given time; so long as the rules of knitr aren't broken. If the generate-report chunk is run then each of the reusable child chunks or filaments get weaved into a single yarn and any knitting is done in the context of that yarn. So file naming and such sees the chunk label as whatever we set it to at the yarn level and does not think of the filaments as distinct elements. Since I don't want my yarn split-up without explicitly saying so, this setup, to me, makes complete sense and is desirable; more on that later.
There are three choices when labeling code chunks.
- An empty, omitted, or nameless label indicate for knitr to handle it internally.
- A given, manually created label.
- A generated label, which we may or may not know at the time of writing the document.
All three have advantages and disadvantages in relation to what is automagically done behind the scenes during document generation. The empty label may lead to totally meaningless generated file names, where a given label could become excessively verbose and repetitive, and generating labels of dynamic data can yield unaccounted for labels such that any real referencing of them later would require programmatic methods just as the generation did.
Generate the labelled chunks that result in plots with specific naming conventions.
# Prepare knitr.
knit_child("child-chunks.Rmd")
# Prepare R
library(brew)
library(iterators)
data(mtcars)
brewed.chunks <- tempfile(tmpdir = getwd(), pattern = "brewed-chunks", fileext = ".Rmd")
# Prepare label data.
engine.cyl <- rep(sort(unique(mtcars$cyl)), each = 2)
reusable.chunk.label <- c("mpg-histogram", "weight-histogram")
generated.chunk.label <- paste(engine.cyl, "cyl", sep = "")
generated.chunk.label <- paste(reusable.chunk.label, generated.chunk.label,
sep = "-")
label.data <- data.frame(engine.cyl, reusable.chunk.label, generated.chunk.label,
stringsAsFactors = FALSE)
Personally I'm not a fan of using the iterator for this, but since it is in the original question I'll assume there is a specific reason and will continue to do it this way instead of switching to a data.table and applying a function using the fine capabilities of that package.
# Prepare iterator
cyl.i <- iter(unique(engine.cyl))
We now have everything we need for brew to generate our executable chunks. The iterator contains the filtering value for the data set, the reusable.chunk.label contains the chunk labels that match the chunks in child-chunks.Rmd, and generated.chunk.label contains our new labels that will be used for knitting.
print(label.data)
## engine.cyl reusable.chunk.label generated.chunk.label
## 1 4 mpg-histogram mpg-histogram-4cyl
## 2 4 weight-histogram weight-histogram-4cyl
## 3 6 mpg-histogram mpg-histogram-6cyl
## 4 6 weight-histogram weight-histogram-6cyl
## 5 8 mpg-histogram mpg-histogram-8cyl
## 6 8 weight-histogram weight-histogram-8cyl
Let's do some inline brewing…
The chunk for doing the brewing isn't very pretty to look at when done inline instead of a file; but still illustrates the point and seems self explanatory
for( i in seq( 1, length( engine.cyl ), by=2 ) ) {
capture.output(
brew( text= quote("```{r '<%=label.data$generated.chunk.label[i]%>'}\n\
run_chunk('iterate')\n\
run_chunk('<%=label.data$reusable.chunk.label[i]%>')\n```\n") ),
file=brewed.chunks, append=TRUE )
capture.output(
brew( text= quote("```{r '<%=label.data$generated.chunk.label[i+1]%>'}\n\
run_chunk('<%=label.data$reusable.chunk.label[i+1]%>')\n```\n") ),
file=brewed.chunks, append=TRUE )
}
What was generated?
## ```{r 'mpg-histogram-4cyl'}
##
## run_chunk('iterate')
##
## run_chunk('mpg-histogram')
## ```
##
## ```{r 'weight-histogram-4cyl'}
##
## run_chunk('weight-histogram')
## ```
##
## ```{r 'mpg-histogram-6cyl'}
##
## run_chunk('iterate')
##
## run_chunk('mpg-histogram')
## ```
##
## ```{r 'weight-histogram-6cyl'}
##
## run_chunk('weight-histogram')
## ```
##
## ```{r 'mpg-histogram-8cyl'}
##
## run_chunk('iterate')
##
## run_chunk('mpg-histogram')
## ```
##
## ```{r 'weight-histogram-8cyl'}
##
## run_chunk('weight-histogram')
## ```
##
Now the only thing left to do is to knit, which we'll echo to give a verbose output showing the commands being executed; but let's suppress the actual plots…
```{r generate-reports, child=brewed.chunks, echo=TRUE}
```
run_chunk("iterate")
## Generating reports for 4 vehicles...
run_chunk("mpg-histogram")
run_chunk("weight-histogram")
run_chunk("iterate")
## Generating reports for 6 vehicles...
run_chunk("mpg-histogram")
run_chunk("weight-histogram")
run_chunk("iterate")
## Generating reports for 8 vehicles...
run_chunk("mpg-histogram")
run_chunk("weight-histogram")
unlink(brewed.chunks)
The resulting file names are:
list.files("./figure")
## [1] "mpg-histogram-4cyl.png" "mpg-histogram-6cyl.png"
## [3] "mpg-histogram-8cyl.png" "weight-histogram-4cyl.png"
## [5] "weight-histogram-6cyl.png" "weight-histogram-8cyl.png"
And so we have shown it is doable, and simple to do.
Enjoy!