Parameterised Rmarkdown templates

rmarkdown

#1

I am generating Rmd files using a function and as part of that, I'd like to set some of the yaml fields to fixed values but that are parameterised. I'm not sure that's a particularly clear way to put it, so I'll proceed with an example:

I have a function that generates an Rmd from a template like so:

library(mypackage)
new_notebook("Sales analysis", author = "Ben")
#> Created sales-analysis.Rmd

Where new_notebook calls rmarkdown::draft inside the function body, and sales-analysis.Rmd looks something like:

---
title: "Untitled"
author: "Set name here"
---

# Overview


# Analysis

Ideally, I'd like to be able to set the values in the yaml header of sales-analysis.Rmd to fixed, parameterised values. That is, something like:

---
title: "Sales analysis"
author: "Ben"
---
...

Is there an easy way to acheive such a thing?


#2

R code in the YAML fields can be executed, and uses the parent environment for looking up variables. Example:

# sales-analysis.Rmd
---
title: "Untitled"
author: "`r author`"
---
# R code
new_notebook <- function(rmd_path, author = "Anonymous", ...) {
  rmarkdown::render(rmd_path, ...)
}

new_notebook("sales-analysis.Rmd", author = "Ben")

Because the document is rendered inside the new_notebook function, it has access to all variables in the function's environment.


#3

Sorry, I haven't been that clear. I'm not looking to render the rmarkdown file with parameters, rather to create the .Rmd file from a template with parameters. Hence using rmarkdown::draft and not rmarkdown::render inside new_notebook. Does that make sense?


#4

I think you can achieve this kind of thing with a templating framework like whisker :package:.

This package will allow you to create an Rmd file with some parameter to replace, and whisker.render will fill the variable with the corresponding value.

You just have to do some wrapping work in your new_notebook function, by not using rmarkdown::draft that do not have this feature but doing the same think (copying from template dir to user dir) with addition of filling up the template.

The brew :package: also allow that but personnaly I prefer whisker.


#5

Okay, this makes sense. Thank you.

Ideally I think I'd avoid replicating the copying logic in rmarkdown::draft but I suppose it's not a lot in the greater scheme of things.

Actually, since rmarkdown::draft (invisibly) returns the file path of the created file, it would probably be possible to use draft to create a template file, and then replace the template with the realised values with whisker afterwards?

It feels like creating a file and overwriting it in one function (i.e. multiple side-effects) is a Bad Thing, though. Is this fair? Is this worse than duplicating some of the code in draft?


#6

Personnaly, in the same function, I would

  • read the template Rmd that is stored in your package
  • apply the templating logic replacement
  • write the result in a file in the user desired location.

The draft function is possibly not useful in your use-case. I think the value of rstudio draft mechanism is for integration I tôt the IDE if you want your template to be in the menu. Also Basically it just look into the template directory, inside the package, and copy the file or the all folder in a user directory. Nothing to difficult to reproduce.


#7

To be honest, I think for my use-case, the templating is light enough that it might not be worth the extra effort :slight_smile:. That said, your advice looks pretty straightforward, so I'll have a play with that as well. Thank you for your help.