在`knitr`中如何测试输出是PDF还是单词?

时间:2016-02-02 02:42:58

标签: r knitr

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

这是一些伪代码:

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

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

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

5 个答案:

答案 0 :(得分:40)

简答

在大多数情况下,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是job是将输入RMD文件编织到MD文件。 MD文件到YAML标头中指定的输出格式的转换将在下一阶段由pandoc完成。

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

理论上到目前为止。现实有点不同。 RStudio的“Knit PDF”/“Knit HTML”按钮调用rmarkdown::render,然后调用knit。在此之前,render sets (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。在这种情况下,我们可以利用parse_yaml_front_matter包中的(未导出的)函数rmarkdown来解析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"))的使用(lesness),而使用parse_yaml_front_matter的行返回了YAML标头的“output”字段中指定的格式。

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,这样更容易。

答案 1 :(得分:9)

knitr 1.18起,您可以使用这两个函数

knitr::is_html_output()

knitr::is_latex_output()

答案 2 :(得分: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

  3. 例如......

    ---
    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"){
      #...
    }
    ```
    

答案 3 :(得分:2)

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

答案 4 :(得分: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"
}