In 'Knitr' How to Test for If the Output Will Be PDF or Word

In `knitr` how can I test for if the output will be PDF or word?

Short Answer

In most cases, opts_knit$get("rmarkdown.pandoc.to") delivers the required information.

Otherwise, query rmarkdown::all_output_formats(knitr::current_input()) and check if the return value contains word_document:

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

Long answer

I assume that the source document is RMD because this is the usual/most common input format for knitting to different output formats such as MS Word, PDF and HTML.

In this case, knitr options cannot be used to determine the final output format because it doesn't matter from the perspective of knitr: For all output formats, knitr's job is to knit the input RMD file to a MD file. The conversion of the MD file to the output format specified in the YAML header is done in the next stage, by pandoc.

Therefore, we cannot use the package option knitr::opts_knit$get("out.format") to learn about the final output format but we need to parse the YAML header instead.

So far in theory. Reality is a little bit different. RStudio's "Knit PDF"/"Knit HTML" button calls rmarkdown::render which in turn calls knit. Before this happens, render sets a (undocumented?) package option rmarkdown.pandoc.to to the actual output format. The value will be html, latex or docx respectively, depending on the output format.

Therefore, if (and only if) RStudio's "Knit PDF"/"Knit HTML" button is used, knitr::opts_knit$get("rmarkdown.pandoc.to") can be used to determine the output format. This is also described in this answer and that blog post.

The problem remains unsolved for the case of calling knit directly because then rmarkdown.pandoc.to is not set. In this case we can exploit the (unexported) function parse_yaml_front_matter from the rmarkdown package to parse the YAML header.

[Update: As of rmarkdown 0.9.6, the function all_output_formats has been added (thanks to Bill Denney for pointing this out). It makes the custom function developed below obsolete – for production, use rmarkdown::all_output_formats! I leave the remainder of this answer as originally written for educational purposes.]

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

The example above demonstrates the use(lesness) of opts_knit$get("rmarkdown.pandoc.to") (opts_knit$get("out.format")), while the line employing parse_yaml_front_matter returns the format specified in the "output" field of the YAML header.

The input of parse_yaml_front_matter is the source file as character vector, as returned by readLines. To determine the name of the file currently being knitted, current_input() as suggested in this answer is used.

Before parse_yaml_front_matter can be used in a simple if statement to implement behavior that is conditional on the output format, a small refinement is required: The statement shown above may return a list if there are additional YAML parameters for the output like in this example:

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

The following helper function should resolve this issue:

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

It can be used in constructs such as

if(getOutputFormat() == 'html_document') {
# do something
}

Note that getOutputFormat uses only the first output format specified, so with the following header only html_document is returned:

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

However, this is not very restrictive. When RStudio's "Knit HTML"/"Knit PDF" button is used (along with the dropdown menu next to it to select the output type), RStudio rearranges the YAML header such that the selected output format will be the first format in the list. Multiple output formats are (AFAIK) only relevant when using rmarkdown::render with output_format = "all". And: In both of these cases rmarkdown.pandoc.to can be used, which is easier anyways.

knitr::is_word_output() to check if the current output type is word – just like knitr::is_latex_output() and knitr::is_html_output()

As of knitr 1.31 (released in January 2021), you can use knitr::pandoc_to() in either of the following ways:

```{r}
if (knitr::pandoc_to("docx")) {
cat("Word")
}
```

```{r, include=knitr::pandoc_to("docx")}
cat("Word")
```

To conditionally output literal text content (rather than R code), it's easiest to use an asis chunk (note that we need to use the echo option instead of include):

```{asis, echo=knitr::pandoc_to("docx")}
This will only appear in Word documents.
```

```{asis, echo=knitr::pandoc_to("docx", "pdf")}
This will be appear in Word and PDF documents.
```

Historical answer

In earlier versions of knitr, you can use an internal knitr function to get the type you want:

is_word_output <- function(fmt = knitr:::pandoc_to()) {
length(fmt) == 1 && fmt == "docx"
}

ifelse action depending on document type in rmarkdown

Yes, you can access the output format via knitr::opts_knit$get("rmarkdown.pandoc.to"). This will return a string with the target output format. Here's an example:

---
title: "Untitled"
output: html_document
---

```{r}
library(knitr)
opts_knit$get("rmarkdown.pandoc.to")
```

This returns "html" for html_document, "docx" for word_document, and "latex" for pdf_document. So to answer your question you can do something like:

html <- knitr::opts_knit$get("rmarkdown.pandoc.to") == "html"

In `knitr` how can I test for if the output will be PDF or word?

Short Answer

In most cases, opts_knit$get("rmarkdown.pandoc.to") delivers the required information.

Otherwise, query rmarkdown::all_output_formats(knitr::current_input()) and check if the return value contains word_document:

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

Long answer

I assume that the source document is RMD because this is the usual/most common input format for knitting to different output formats such as MS Word, PDF and HTML.

In this case, knitr options cannot be used to determine the final output format because it doesn't matter from the perspective of knitr: For all output formats, knitr's job is to knit the input RMD file to a MD file. The conversion of the MD file to the output format specified in the YAML header is done in the next stage, by pandoc.

Therefore, we cannot use the package option knitr::opts_knit$get("out.format") to learn about the final output format but we need to parse the YAML header instead.

So far in theory. Reality is a little bit different. RStudio's "Knit PDF"/"Knit HTML" button calls rmarkdown::render which in turn calls knit. Before this happens, render sets a (undocumented?) package option rmarkdown.pandoc.to to the actual output format. The value will be html, latex or docx respectively, depending on the output format.

Therefore, if (and only if) RStudio's "Knit PDF"/"Knit HTML" button is used, knitr::opts_knit$get("rmarkdown.pandoc.to") can be used to determine the output format. This is also described in this answer and that blog post.

The problem remains unsolved for the case of calling knit directly because then rmarkdown.pandoc.to is not set. In this case we can exploit the (unexported) function parse_yaml_front_matter from the rmarkdown package to parse the YAML header.

[Update: As of rmarkdown 0.9.6, the function all_output_formats has been added (thanks to Bill Denney for pointing this out). It makes the custom function developed below obsolete – for production, use rmarkdown::all_output_formats! I leave the remainder of this answer as originally written for educational purposes.]

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

The example above demonstrates the use(lesness) of opts_knit$get("rmarkdown.pandoc.to") (opts_knit$get("out.format")), while the line employing parse_yaml_front_matter returns the format specified in the "output" field of the YAML header.

The input of parse_yaml_front_matter is the source file as character vector, as returned by readLines. To determine the name of the file currently being knitted, current_input() as suggested in this answer is used.

Before parse_yaml_front_matter can be used in a simple if statement to implement behavior that is conditional on the output format, a small refinement is required: The statement shown above may return a list if there are additional YAML parameters for the output like in this example:

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

The following helper function should resolve this issue:

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

It can be used in constructs such as

if(getOutputFormat() == 'html_document') {
# do something
}

Note that getOutputFormat uses only the first output format specified, so with the following header only html_document is returned:

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

However, this is not very restrictive. When RStudio's "Knit HTML"/"Knit PDF" button is used (along with the dropdown menu next to it to select the output type), RStudio rearranges the YAML header such that the selected output format will be the first format in the list. Multiple output formats are (AFAIK) only relevant when using rmarkdown::render with output_format = "all". And: In both of these cases rmarkdown.pandoc.to can be used, which is easier anyways.

Getting document type that is knitted in knitr

As pointed out in an answer to a similar question, knitr 1.18 introduced the following functions

knitr::is_html_output()
knitr::is_latex_output()

which check at compile-time if the output is HTML or LaTeX, and return TRUE/FALSE. Something like the following would work:

if (knitr::is_html_output()) {
cat("HTML file...")
} else if (knitr::is_latex_output()) {
cat("LATEX file...")
}

knitr: include test that on purpose fails in output PDF

The solution is to use test_that. The following code works perfectly:

```{r, error=TRUE}
library(testthat)
test_that(1, expect_equal(1, 2))
```

```{r, error=TRUE}
test_that(2, expect_equal(1, 1))
```

Note that the first argument in test_that is a name for the test.

Including a 3D interactive figure in html and static in word/pdf using knitr and rgl

You could use the following setup to switch according to the output format

```{r, echo=FALSE}
out_type <- knitr::opts_knit$get("rmarkdown.pandoc.to")
keep <- if(out_type == "html") 'none' else 'last'
```


```{r chunk, echo=FALSE, fig.keep=keep}
plot(cars)
if(out_type == "html")
cat("there goes fancy js code")
```

R Markdown Different Echo Options for Different Output Types

You can use the function is_html_output() to check whether you output is html or not and use that in your first chunk:

---
title: "test2"
author: "Carina"
date: "February 13, 2020"
output:
word_document: default
html_document:
code_folding: show

---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = knitr::is_html_output())
```


Related Topics



Leave a reply



Submit