【问题标题】:Importing common YAML in rstudio/knitr document在 rstudio/knitr 文档中导入通用 YAML
【发布时间】:2017-02-14 13:42:39
【问题描述】:

我有一些 Rmd 文档,除了标题之外,它们都具有相同的 YAML 前题。 我怎样才能将这个 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 可以创建一个 _output.yaml 来放置常见的 YAML 元数据,但这会将所有元数据放在 YAML 中的 output: 下,因此仅适用于 html_document:pdf_document: 下的选项,而不是对于作者、日期、...等内容。
  • 编写一个 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。但我不够聪明。

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

【问题讨论】:

  • 好问题!由于`r format(...)` 位,.yaml 中的“块”似乎特别成问题——很难知道 R 会如何告诉它应该递归地评估代码。
  • 是的,我认为这可能很麻烦。这就是为什么我仍然对不解析 common.yaml 中的 R 块的解决方案感到高兴的原因。
  • @hrbrmstr 我已经找到了这个;这是我在我的问题中列为(不是)解决方案的第一件事。
  • @hrbrmstr 我在我的问题中将其列为第三个选项,但如前所述,我还不够聪明(因此提出了这个问题)。我目前正在尝试学习 Makefile 语法,并认为我可以将 Makefile 连接到 Rstudio 的“构建”命令,而不是 Knit,但这不是我的首选。
  • 由于 YAML 被转换为 knit/render 作为参数,您可能可以在存储的参数列表上调用 knitr::opts_knit$set()。或者,只需使用 rmarkdown::output_format 制作您自己的模板,这可能是明智的做法。

标签: r knitr r-markdown


【解决方案1】:

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

  1. 你可以provide common yaml to pandoc on the command-line!哦!
  2. 您可以将元数据的 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(请参阅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: 下,用于该文件夹中的所有文档。通过这种方式,使用此 frontmatter 的所有文档之间可以没有 YAML 重复。

优点:

  • YAML frontmatter 没有重复。
  • 很干净

缺点:

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

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

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

选项 2:覆盖 knit 命令

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

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

简而言之:

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

     knit:  (function (...) { source('myknit.r'); myknit(...) })
    

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

然后 Ctrl+Shift+K 就像我希望在 Rstudio 中一样工作。

补充说明:

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

    我发现输出中只能有一个这样的消息[不是多个],或者你没有预览窗口。因此,如果您使用render(生成“输出已创建:basename.extension”)消息并且最终生成的文件实际上位于其他位置,您将需要通过render(..., quiet=T)suppressMessages(render(...)) 禁止此消息(前者禁止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 本身没有日期或作者。

【讨论】:

  • 存在 'preserve_yaml: true' 选项是为了在 knitr 之后保留 Markdown 文档中的 yaml 选项。
【解决方案2】:

@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 参数。

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 2014-06-30
    • 2019-05-14
    • 1970-01-01
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 2012-12-14
    • 2014-09-16
    相关资源
    最近更新 更多