В `knitr` как я могу проверить, будет ли вывод PDF или word?

Я хотел бы включить конкретный контент в зависимости от того, какой формат создается. В этом конкретном примере мои таблицы выглядят ужасно в MS word выходной, но отличный в HTML, Я хотел бы добавить в некоторый тест, чтобы пропустить таблицу в зависимости от вывода.

Вот некоторый псевдокод:

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

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

Я уверен, что это не правильный способ использования opts_chunk, но это предел моего понимания того, как knitr работает под капотом. Какой будет правильный способ проверить это?

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,

Поэтому мы не можем использовать опцию пакета knitr::opts_knit$get("out.format") чтобы узнать окончательный формат вывода, но вместо этого нам нужно проанализировать заголовок YAML.

Пока в теории. Реальность немного отличается. Кнопки RStdio "Knit PDF"/"Knit HTML" rmarkdown::render который в свою очередь вызывает knit, Прежде чем это произойдет, render устанавливает (недокументированный?) параметр пакета rmarkdown.pandoc.to к фактическому формату вывода. Значение будет html, latex или же docx соответственно в зависимости от формата вывода.

Поэтому, если (и только если) используется кнопка "Knit PDF"/"Knit HTML" в RStudio, knitr::opts_knit$get("rmarkdown.pandoc.to") может быть использован для определения выходного формата. Это также описано в этом ответе и в этом блоге.

Проблема остается нерешенной для случая вызова knit прямо потому что тогда rmarkdown.pandoc.to не установлен. В этом случае мы можем использовать (неэкспортированную) функцию parse_yaml_front_matter от rmarkdown пакет для анализа заголовка YAML.

[ Обновление: по состоянию на rmarkdown 0.9.6, функция all_output_formats был добавлен (спасибо Биллу Денни за указание на это). Это делает пользовательскую функцию, разработанную ниже, устаревшей - для производства, использования 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 возвращает формат, указанный в поле "output" заголовка YAML.

Ввод parse_yaml_front_matter исходный файл как символьный вектор, возвращаемый readLines, Чтобы определить имя файла, который в данный момент связан, 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::render с output_format = "all", И: в обоих случаях rmarkdown.pandoc.to можно использовать, что проще в любом случае.

Поскольку knitr 1.18, вы можете использовать две функции

knitr::is_html_output()

а также

knitr::is_latex_output()

Просто хочу добавить немного пояснения, так как я часто визуализирую один и тот же файл 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"){
  #...
}
```

Еще один момент: приведенные выше ответы не работают для html_notebookпоскольку код выполняется прямо там и knitr::current_input() не отвечает. Если вы знаете название документа, вы можете позвонить all_output_formats как указано выше, указав имя явно. Я не знаю, есть ли другой способ сделать это.

Это то, что я использую

      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"
}
Другие вопросы по тегам