Search code examples
yamlr-markdownknitr

Construct output file name for RStudio knitr button using YAML header


I am using RStudio to generate documents using R markdown and knitr. I would like to specify the output file name dynamically based on the parameters in the YAML. This basic header works:

---
params: 
  experiment_id: "JT001"
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
---

I would like to generate the output file name dynamically using something like the output_filename below:

---
params: 
  experiment_id: "JT001"
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
output_filename: '`r paste0(params$tstamp, ".", params$extension)`'
---

I found this suggestion (https://github.com/quarto-dev/quarto-cli/discussions/9913), though it is specific to quatro. This code runs without errors, but the output file is still the same as the file name of the source Rmd file.

---
params: 
  experiment_id: "JT001"
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
format:
  html:
    output-file: '`r paste0(params$tstamp, ".", params$extension)`'
---

I've also tried modifying knitr in the YAML using the suggestions here (Set output_file in YAML). This works when I manually set the output file name:

---
params: 
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
knit: |
  (function(input, ...) {
    rmarkdown::render(
      input,
      output_file = "test.html",
      envir = globalenv()
    )
  })
---

But this fails when I try to dynamically generate the file name from the params:

---
params: 
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
knit: |
  (function(input, ...) {
    rmarkdown::render(
      input,
      output_file = "`r paste0(params$tstamp, ".", params$extension)`",
      envir = globalenv()
    )
  })
---
Warning message:
In system(paste0("(function(input, ...) {\n  rmarkdown::render(\n    input,\n    output_file = \"`r paste0(params$tstamp, \".\", params$extension)`\",\n    envir = globalenv()\n  )\n}) \"",  :
  '(function(input,' not found

I also tried modifying the knit function in the R code. This code runs without errors, but the output file is still the same as the file name of the source Rmd file.

---
params: 
  tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
  extension: "html"
title: 'Merge dds for: `r params$experiment_id`'
subtitle: 'test' 
author: 'Joshua Theisen' 
date: '`r Sys.time()`' 
output: html_document
---
```{r set_knit_output}
knit <- function(input, ...) {
    rmarkdown::render(
      input,
      output_file = paste0(params$tstamp, ".", params$extension),
      envir = globalenv()
    )
  }

Is there a way to dynamically set the knitr output file in the YAML header, or in an R code chunk in the Rmd file? Thanks


Solution

  • If you want to continue down the path of customizing the knit button, you could add code that parses the yaml from your RMarkdown input and uses it to construct the desired filename.

    Note, this requires the package {yaml}.

    ---
    title: "A Title"
    params: 
      tstamp: !r format(Sys.time(), "%Y%m%d.%H%M%S")
      extension: "html"
    output: html_document
    knit: |
      (function(input, ...) {
        rmd_lines <- readLines(input)
        yaml_delim <- grep("---", rmd_lines)
        yaml_lines <- rmd_lines[yaml_delim[1] + 1:yaml_delim[2] - 1]
        yaml <- yaml::read_yaml(text = yaml_lines)
        output_file <- paste(
          eval(parse(text = yaml$params$tstamp)),
          yaml$params$extension,
          sep = "."
        )
        
        rmarkdown::render(
          input,
          output_file = output_file,
          envir = globalenv()
        )
      })
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = TRUE)
    ```
    
    # A Header
    
    Hello World!
    

    Reprex files hosted with on GitHub