在rstudio/knitr文档中导入通用YAML

在rstudio/knitr文档中导入通用YAML,r,knitr,r-markdown,R,Knitr,R Markdown,我有一些Rmd文件,除了标题之外,所有这些文件都具有相同的YAML frontmatter如何将此frontmatter保存在一个文件中并用于所有文档?它越来越大,我不想每次调整frontmatter时都将每个文件保持同步 我想继续 使用RStudio中的Knit按钮/Ctrl+Shift+K快捷键进行编译 保持整个设置的可移植性:希望避免编写自定义输出格式或覆盖rstudio.markdownToHTML(因为这也需要我随身携带.Rprofile) 例子 common.yaml: auth

我有一些Rmd文件,除了标题之外,所有这些文件都具有相同的YAML frontmatter如何将此frontmatter保存在一个文件中并用于所有文档?它越来越大,我不想每次调整frontmatter时都将每个文件保持同步

我想继续

  • 使用RStudio中的Knit按钮/Ctrl+Shift+K快捷键进行编译
  • 保持整个设置的可移植性:希望避免编写自定义输出格式或覆盖
    rstudio.markdownToHTML
    (因为这也需要我随身携带
    .Rprofile
例子 common.yaml:

author: me
date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
link-citations: true
reference-section-title: References
# many other options
示例文档

----
title: On the Culinary Preferences of Anthropomorphic Cats
----

I do not like green eggs and ham. I do not like them, Sam I Am!
期望输出: 已编译的示例文档(即HTML或PDF),已使用
common.yaml
中插入的元数据进行编译。YAML中的R代码(在本例中为日期)将被编译为额外代码,但这并不是必需的(我只将其用于我并不真正需要的日期)

选择/解决方案? 这些东西我还没有完全做好

  • 使用rmarkdown可以创建一个
    \u output.yaml
    来放置常见的yaml元数据,但这会将所有元数据放在yaml中的
    output:
    下,因此只适用于
    html\u文档:
    pdf\u文档:
    下的选项,而不适用于作者、日期等内容
  • 编写knitr块以导入YAML,例如

    ----
    title: On the Culinary Preferences of Anthropomorphic Cats
    ```{r echo=F, results='asis'}
    cat(readLines('common.yaml'), sep='\n')
    ```
    ----
    
    I do not like green eggs and ham. I do not like them, Sam I Am!
    
    如果我
    knitr('input.Rmd')
    ,然后
    pandoc
    输出,这就行得通,但如果我使用Rstudio中的Knit按钮(我假设它调用
    render
    ),则不行,因为这会在运行knitr之前首先解析元数据,直到knitr运行之前元数据的格式都不正确

  • Makefile:如果我足够聪明,我可以编写一个Makefile或其他东西,将
    common.yaml
    注入
    input.Rmd
    ,然后运行
    rmarkdown::render()
    ,并以某种方式将其连接到Rstudio的Knit按钮,也许可以将这个Rstudio配置保存到
    .Rproj
    文件中,这样整个东西就可以移植,而无需我也编辑
    .Rprofile
    。但我不够聪明

编辑:我尝试了最后一个选项,并将一个生成文件连接到Build命令(Ctrl+Shift+B)。但是,每次我通过Ctrl+Shift+B使用它时,这将构建相同的目标,我希望构建与我当前在编辑器中打开的Rmd文件相对应的目标[对于Ctrl+Shift+K]。

找到了两个可移植的选项(即不
。需要定制Rprofile
YAML frontmatter的最小重复):

  • 你可以!哦
  • 您可以将元数据的
    knit:
    属性设置为您自己的函数,以便更好地控制Ctrl+Shift+K时发生的情况
  • 选项1:命令行的通用YAML。 将所有公共YAML放在自己的文件中

    common.yaml

    ---
    author: me
    date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
    link-citations: true
    reference-section-title: References
    ---
    
    注意它是完整的,即需要
    --

    然后在文档中,您可以将YAML指定为pandoc的最后一个参数,它将应用YAML(请参阅)

    示例.rmd
    中:

    ---
    title: On the Culinary Preferences of Anthropomorphic Cats
    output:
      html_document:
        pandoc_args: './common.yaml'
    ---
    
    I do not like green eggs and ham. I do not like them, Sam I Am!
    
    ---
    title: On the Culinary Preferences of Anthropomorphic Cats
    knit:  (function (...) { source('myknit.r'); myknit(...) })
    ---
    
    I do not like green eggs and ham. I do not like them, Sam I Am!
    
    您甚至可以将
    html\u文档:
    内容放在
    \u输出中。yaml
    因为
    rmarkdown
    会将其放在该文件夹中所有文档的
    output:
    下。通过这种方式,使用此frontmatter的所有文档之间可以YAML复制

    优点:

    • 没有YAML frontmatter的重复
    • 非常干净
    缺点:

    • 通用YAML没有通过knit,因此上面的日期字段将不会被解析。您将获得文字字符串“r格式(Sys.time(),格式=“%Y-%m-%d%H:%m:%S%z”)作为日期
    • 来自同一github问题:

      首先看到的元数据定义将保持不变,即使在以后解析冲突数据也是如此

    根据您的设置,可能在某个时候会出现问题

    选项2:覆盖
    knit
    命令 这允许进行更大的控制,尽管有点麻烦/棘手

    并在rmarkdown中提到一个未记录的功能:点击Rstudio的“knit”按钮时,将执行YAML的
    knit:
    部分

    简言之:

  • 定义一个函数
    myknit(inputFile,encoding)
    ,该函数将读取YAML,将其放入RMD并对结果调用
    render
    。保存在自己的文件中
    myknit.r
  • example.rmd
    的YAML中,添加

     knit:  (function (...) { source('myknit.r'); myknit(...) })
    
    似乎必须在一条线上。
    source('myknit.r')
    而不是将函数定义放在YAML中的原因是为了可移植性。如果我修改
    myknit.r
    ,我就不必修改每个文档的YAML。这样,所有文档必须在其前端重复的唯一常见YAML是
    knit
    行;所有其他通用YAML可以保留在
    common.YAML

  • 然后Ctrl+Shift+K可以像我希望的那样在Rstudio中工作

    进一步说明:

    • myknit
      可能只是对
      make
      的系统调用,如果我有makefile设置的话
    • 注入的YAML将通过
      rmarkdown
      传递,因此被编织,因为它是在调用
      render
      之前注入的
    • 预览窗口:只要
      myknit
      生成一条(单个)消息
      Output created:path/to/file.html
      ,文件就会显示在预览窗口中

      我发现输出中只能有一条这样的消息,或者没有预览窗口。因此,如果使用
      render
      (生成一个“Output created:basename.extension”)消息,并且最终生成的文件实际上在别处,那么
      author: me
      date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
      link-citations: true
      reference-section-title: References
      
      myknit <- function (inputFile, encoding, yaml='common.yaml') {   
          # read in the YAML + src file
          yaml <- readLines(yaml)
          rmd <- readLines(inputFile)
      
          # insert the YAML in after the first ---
          # I'm assuming all my RMDs have properly-formed YAML and that the first
          # occurence of --- starts the YAML. You could do proper validation if you wanted.
          yamlHeader <- grep('^---$', rmd)[1]
          # put the yaml in
          rmd <- append(rmd, yaml, after=yamlHeader)
      
          # write out to a temp file
          ofile <- file.path(tempdir(), basename(inputFile))
          writeLines(rmd, ofile)
      
          # render with rmarkdown.
          message(ofile)
          ofile <- rmarkdown::render(ofile, encoding=encoding, envir=new.env())
      
          # copy back to the current directory.
          file.copy(ofile, file.path(dirname(inputFile), basename(ofile)), overwrite=T)
      }
      
      title: "Crime and Punishment"
      author: "Fyodor Dostoevsky"
      
      ---
      output:
        html_document:
          pandoc_args: ["--metadata-file=header.yaml"]
      ---