在rstudio / knitr文档中导入常见的YAML

时间:2016-10-05 23:47:25

标签: r knitr r-markdown

我有一些Rmd文档除了标题之外都有相同的YAML前缀。 如何将这个前置文件保存在一个文件中,并将其用于所有文档?它变得相当大,我不希望每次调整前端时都保持每个文件的步骤。< / p>

我还想

  • 在RStudio中使用编织按钮/ 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可以创建_output.yaml来放置常见的YAML元数据,但这会将所有元数据放在output:下的YAML中,因此仅适用于html_document:下的选项pdf_document:,而不是像作者,日期等......
  • 编写一个knitr chunk来导入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。但我不够聪明。

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

2 个答案:

答案 0 :(得分:7)

找到了两个可移植的选项(即不需要.Rprofile自定义,YAML前端的重复最少):

  1. 你可以provide common yaml to pandoc on the command-line! D'哦!
  2. 您可以将元数据的knit:属性设置为您自己的函数,以便更好地控制Ctrl + Shift + K时发生的情况。
  3. 选项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(参见this github issue

    example.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!
    

    您甚至可以将html_document:内容放在_output.yaml中,因为rmarkdown会将output:放在knit下,以便该文件夹中的所有文档都可以使用knit。通过这种方式,使用此前端的所有文档之间可能存在重复YAML。

    <强>优点:

    • 没有重复的YAML前线。
    • 非常干净

    <强>缺点:

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

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

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

    选项2:覆盖myknit(inputFile, encoding)命令

    这允许更大的控制,但有点麻烦/棘手。

    This linkthis one在rmarkdown中提到了一个未记录的功能:当点击Rstudio的“Knit”按钮时,将执行YAML的render部分。

    简而言之:

    1. 定义一个函数myknit.r,它将读取YAML,将其放入RMD并在结果上调用example.rmd。保存在自己的文件 knit: (function (...) { source('myknit.r'); myknit(...) })
    2. source('myknit.r')的YAML中,添加

      myknit.r

      似乎必须在一条线上。 knit而不是仅仅将函数定义放在YAML中的原因是为了便于携带。如果我修改common.yaml,我不必修改每个文档的YAML。这样,所有文档必须在其前端重复的唯一 common YAML是myknit行;所有其他常见的YAML都可以留在make

    3. 然后按Ctrl + Shift + K按照我希望的方式在Rstudio中工作。

      补充说明:

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

        我发现输出中只有一个这样的消息[不是多个],或者你没有预览窗口。因此,如果您使用render(..., quiet=T)(生成“输出已创建:basename.extension”)消息并且最终生成的文件实际上位于其他位置,则需要通过suppressMessages(render(...))或{{1来禁止此消息(前者也抑制了knitr进程和pandoc输出),并使用正确的路径创建自己的消息。

      <强>优点:

      • YAML前线针织
      • 如果您需要进行自定义的预处理/后处理,
      • 比选项1更多的控制。

      <强>缺点:

      • 比选项1更多的努力
      • knit:行必须在每个文档中重复(尽管source('./myknit.r')至少函数定义可以存储在一个中心位置)

      这是后人的设置。为了便于携带,您只需随身携带myknit.rcommon.yaml。不需要.Rprofile或项目特定的配置。

      example.rmd

      ---
      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!
      

      common.yaml [例如]:

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

      myknit.r

      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)
      }
      

      example.rmd的编辑器按Ctrl + Shift + K / Knit将编译结果并显示预览。我知道它正在使用common.yaml,因为结果包含日期和作者,而example.rmd本身没有日期或作者。

答案 1 :(得分:0)

@mathematical.coffee提出的第一个解决方案是一种很好的方法,但是它给出的示例对我而言不起作用(可能是因为语法已更改)。如此说来,这可以通过在YAML标头中提供pandoc参数来实现。例如,

这是header.yaml文件的内容:

title: "Crime and Punishment"
author: "Fyodor Dostoevsky"

将此添加到RMarkdown文件的开头:

---
output:
  html_document:
    pandoc_args: ["--metadata-file=header.yaml"]
---

See the pandoc manual作为--metadata-file参数。