【问题标题】:In `knitr` how can I test for if the output will be PDF or word?在 `knitr` 中,我如何测试输出是 PDF 还是 word?
【发布时间】:2016-05-10 16:57:51
【问题描述】:

我想根据正在创建的格式添加特定内容。在这个特定的示例中,我的表格在MS word 输出中看起来很糟糕,但在HTML 中却很好。我想根据输出添加一些测试以省略表格。

这是一些伪代码:

output.format <- opts_chunk$get("output")

if(output.format != "MS word"){
print(table1)
}

我确定这不是使用opts_chunk 的正确方法,但这是我对knitr 如何在后台工作的理解的限制。对此进行测试的正确方法是什么?

【问题讨论】:

  • 你的源文件是什么?降价?以及您生成最终文档的功能?为什么不自己创建一个新变量来描述输出格式和条件?
  • 是的,RMarkdown 是我的来源。我也在使用 Rstudio。我可以创建自己的变量,然后在每次运行时更改代码,但我希望让它检测输出是什么,这样我就可以使用 Rstudio 中的下拉菜单。
  • 这篇文章有一些好的想法:jmablog.com/post/bookdown-not-bookout

标签: r knitr


【解决方案1】:

这是我用的

library(stringr)
first_output_format <-
  names(rmarkdown::metadata[["output"]])[1]
if (!is.null(first_output_format)) {
  my_output <- str_split(first_output_format,"_")[[1]][1]
} else {
  my_output = "unknown"
}

【讨论】:

    【解决方案2】:

    knitr1.18开始,这两个功能都可以使用了

    knitr::is_html_output()
    

    knitr::is_latex_output()
    

    【讨论】:

      【解决方案3】:

      只是想在这里补充一点说明,因为我经常将同一个 Rmarkdown 文件(*.Rmd)渲染成多种格式(*.html、*.pdf、*.docx),所以与其想知道是否感兴趣的格式列在前面的 yaml 中指定的格式中(即"word_document" %in% rmarkdown::all_output_formats(knitr::current_input()),我想知道当前正在呈现哪种格式。为此,您可以:

      1. 获取前面列出的格式的第一个元素:rmarkdown::all_output_formats(knitr::current_input()[1];或

      2. 获取默认输出格式名称:rmarkdown::default_output_format(knitr::current_input())$name

      例如...

      ---
      title: "check format"
      output:
        html_document: default
        pdf_document: default
        word_document: default
      ---
      
      ```{r}
      rmarkdown::all_output_formats(knitr::current_input())[1]
      ```
      
      ```{r}
      rmarkdown::default_output_format(knitr::current_input())$name
      ```
      
      ```{r}
      fmt <- rmarkdown::default_output_format(knitr::current_input())$name
      
      if (fmt == "pdf_document"){
        #...
      }
      
      if (fmt == "word_document"){
        #...
      }
      ```
      

      【讨论】:

        【解决方案4】:

        另外一点:上述答案不适用于html_notebook,因为代码直接在那里执行而knitr::current_input() 没有响应。如果您知道文档名称,则可以如上所述调用all_output_formats,明确指定名称。我不知道是否有其他方法可以做到这一点。

        【讨论】:

          【解决方案5】:

          简答

          在大多数情况下,opts_knit$get("rmarkdown.pandoc.to") 会提供所需的信息。

          否则,查询rmarkdown::all_output_formats(knitr::current_input()),检查返回值是否包含word_document

          if ("word_document" %in% rmarkdown::all_output_formats(knitr::current_input()) {
            # Word output
          }
          

          长答案

          我假设源文档是 RMD,因为这是编织成不同输出格式(如 MS Word、PDF 和 HTML)的常用/最常见的输入格式。

          在这种情况下,knitr 选项不能用于确定最终的输出格式,因为从knitr 的角度来看这并不重要:对于所有输出格式,knitr 的工作是编织输入RMD 文件转换为 MD 文件。 MD 文件到 YAML 标头中指定的输出格式的转换在下一阶段由pandoc 完成。

          因此,我们不能使用 package option knitr::opts_knit$get("out.format") 来了解最终输出格式,而是需要解析 YAML 标头。

          目前为止在理论上。现实有点不同。 RStudio 的“Knit PDF”/“Knit HTML”按钮调用rmarkdown::render,后者又调用knit。在这发生之前,render sets a (undocumented?) package option rmarkdown.pandoc.to 为实际输出格式。该值将分别为htmllatexdocx,具体取决于输出格式。

          因此,如果(且仅当)使用 RStudio 的“Knit PDF”/“Knit HTML”按钮,knitr::opts_knit$get("rmarkdown.pandoc.to") 可用于确定输出格式。这也在this answerthat blog post 中有所描述。

          对于直接调用knit 的情况,问题仍未解决,因为没有设置rmarkdown.pandoc.to。在这种情况下,我们可以利用 rmarkdown 包中的(未导出的)函数 parse_yaml_front_matter 来解析 YAML 标头。

          [更新:从rmarkdown 0.9.6 开始,已添加函数all_output_formats(感谢Bill Denney 指出这一点)。它使下面开发的自定义函数过时了——对于生产,使用rmarkdown::all_output_formats!我将这个答案的其余部分保留为最初为教育目的而编写的。]

          ---
          output: html_document
          ---
          ```{r}
          knitr::opts_knit$get("out.format") # Not informative.
          
          knitr::opts_knit$get("rmarkdown.pandoc.to") # Works only if knit() is called via render(), i.e. when using the button in RStudio.
          
          rmarkdown:::parse_yaml_front_matter(
              readLines(knitr::current_input())
              )$output
          ```
          

          上面的例子演示了opts_knit$get("rmarkdown.pandoc.to") (opts_knit$get("out.format")) 的使用(少),而使用parse_yaml_front_matter 的行返回YAML 标头的“输出”字段中指定的格式。

          parse_yaml_front_matter 的输入是作为字符向量的源文件,由readLines 返回。要确定当前正在编织的文件的名称,请使用this answer 中建议的current_input()

          parse_yaml_front_matter 可以在简单的if 语句中使用以实现以输出格式为条件的行为之前,需要进行一些小改进:如果有额外的 YAML 参数,上面显示的语句可能会返回一个列表像这个例子中的输出:

          ---
          output: 
            html_document: 
              keep_md: yes
          ---
          

          下面的辅助函数应该可以解决这个问题:

          getOutputFormat <- function() {
            output <- rmarkdown:::parse_yaml_front_matter(
              readLines(knitr::current_input())
              )$output
            if (is.list(output)){
              return(names(output)[1])
            } else {
              return(output[1])
            }
          }
          

          可以用在诸如

          之类的结构中
          if(getOutputFormat() == 'html_document') {
             # do something
          }
          

          请注意,getOutputFormat 仅使用指定的第一个输出格式,因此使用以下标头仅返回 html_document

          ---
          output:
            html_document: default
            pdf_document:
              keep_tex: yes
          ---
          

          但是,这不是很严格。当使用 RStudio 的“Knit HTML”/“Knit PDF”按钮(以及旁边的下拉菜单以选择输出类型)时,RStudio 会重新排列 YAML 标头,以便选择的输出格式 为列表中的第一种格式。多种输出格式(AFAIK)仅在使用 rmarkdown::renderoutput_format = "all" 时相关。并且:在这两种情况下,rmarkdown.pandoc.to 都可以使用,无论如何这更容易。

          【讨论】:

          • 非常感谢@CL。对于这个非常翔实的解释。你的假设是正确的,这是一个 RMD 源。您最后提到“仅返回第一种输出格式”。这是否意味着此解决方案将始终返回 YAML 标头中的第一项,而不一定是我当前正在运行的输出格式?因此,在您的示例中,如果我正在编写 PDF,getOutputFormat 函数仍将返回“html_document”?
          • @Tom 我更新了我的答案。最后一段应该回答你的问题:当前输出格式是列表中的第一个(通常)。但可能您对“简短解决方案”更感兴趣 - 请参阅更新。
          • 明白了,这很有道理。谢谢!
          • 看起来与此非常相似的东西已在当前的 rmarkdown 包中正式发布。请参阅 3 月份添加的 all_output_formats 函数。
          • @BillDenney 感谢您指出这一点。事实上,rmarkdown::all_output_formats 使手动解析 YAML 标头过时了。我更新了答案。
          猜你喜欢
          • 2017-07-11
          • 2011-02-13
          • 1970-01-01
          • 2011-12-01
          • 2016-01-03
          • 2011-01-29
          • 2017-02-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多