R knitr: Возможно ли программно модифицировать метки блоков?
Я пытаюсь использовать knitr для создания отчета, который выполняет один и тот же набор анализов для разных подмножеств набора данных. Проект содержит два файла Rmd: первый файл является основным документом, который устанавливает рабочую область и документ, второй файл содержит только фрагменты, которые выполняют анализы и генерируют связанные цифры.
То, что я хотел бы сделать, это связать главный файл, который затем вызовет второй файл для каждого подмножества данных и включит результаты в один документ. Ниже приведен простой пример.
Главный документ:
# My report
```{r}
library(iterators)
data(mtcars)
```
```{r create-iterator}
cyl.i <- iter(unique(mtcars$cyl))
```
## Generate report for each level of cylinder variable
```{r cyl4-report, child='analysis-template.Rmd'}
```
```{r cyl6-report, child='analysis-template.Rmd'}
```
```{r cyl8-report, child='analysis-template.Rmd'}
```
анализ-template.Rmd:
```{r, results='asis'}
cur.cyl <- nextElem(cyl.i)
cat("###", cur.cyl)
```
```{r mpg-histogram}
hist(mtcars$mpg[mtcars$cyl == cur.cyl], main = paste(cur.cyl, "cylinders"))
```
```{r weight-histogam}
hist(mtcars$wt[mtcars$cyl == cur.cyl], main = paste(cur.cyl, "cylinders"))
```
Проблема заключается в том, что knitr не позволяет использовать нестандартные метки блоков, поэтому вязание терпит неудачу, когда analysis-template.Rmd
вызывается во второй раз. Эту проблему можно было бы избежать, оставив фрагменты без названия, так как после этого будут автоматически генерироваться уникальные метки. Однако это не идеально, потому что я хотел бы использовать ярлыки фрагментов для создания информативных имен файлов для экспортированных графиков.
Потенциальное решение будет использовать простую функцию, которая добавляет текущий цилиндр к метке блока:
```r{paste('cur-label', cyl, sep = "-")}
```
Но не кажется, что knitr будет оценивать выражение в позиции метки куска.
Я также попытался использовать пользовательский кусок куска, который изменил текущую метку блока:
knit_hooks$set(cyl.suffix = function(before, options, envir) {
if (before) options$label <- "new-label"
})
Но изменение метки фрагмента не повлияло на имена файлов для сгенерированных графиков, поэтому я не думал, что knitr использует новую метку.
Любые идеи о том, как изменить метки ярлыков, чтобы один и тот же дочерний документ можно было вызывать несколько раз? Или, возможно, альтернативная стратегия для этого?
Ответы
Ответ 1
Для всех, кто попадает на этот пост, я хотел бы указать, что @Yihui предоставил формальное решение на этот вопрос в knitr 1.0 с введением функции knit_expand()
. Он отлично работает и действительно упростил мой рабочий процесс.
Например, ниже будет обрабатываться шаблон script ниже для каждого уровня mtcars$cyl
, каждый раз заменяя все экземпляры {{ncyl}}
(в шаблоне) его текущим значением:
# My report
```{r}
data(mtcars)
cyl.levels <- unique(mtcars$cyl)
```
## Generate report for each level of cylinder variable
```{r, include=FALSE}
src <- lapply(cyl.levels, function(ncyl) knit_expand(file = "template.Rmd"))
```
`r knit(text = unlist(src))`
Шаблон:
```{r, results='asis'}
cat("### {{ncyl}} cylinders")
```
```{r mpg-histogram-{{ncyl}}cyl}
hist(mtcars$mpg[mtcars$cyl == {{ncyl}}],
main = paste({{ncyl}}, "cylinders"))
```
```{r weight-histogam-{{ncyl}}cyl}
hist(mtcars$wt[mtcars$cyl == {{ncyl}}],
main = paste({{ncyl}}, "cylinders"))
```
Ответ 2
Если вы делаете все куски в своем ** безымянном, т.е. ```{r}
, он работает. Это, конечно, не очень элегантно, но есть две проблемы, препятствующие изменению метки текущего фрагмента:
- Файл анализируется перед выполнением блоков кода. Парсер уже обнаруживает дубликаты меток, прежде чем выполняется какой-либо код или вызываются пользовательские перехватчики.
- Параметры куска (включая метку) обрабатываются до вызова крючка (логический: это опция, которая запускает крючок), поэтому хук больше не может изменять метку.
Тот факт, что неназванные блоки работают, заключается в том, что внутри они получают метку unnamed-chunk-
+ номер фрагмента.
Блоки не могут иметь повторяющиеся имена, так как внутренний knitr ссылается на них по метке. Исправление может заключаться в том, чтобы заставить knitr добавить номер куска ко всем кускам с повторяющимися именами. Или ссылаться на них по номеру блока, а не на метку, но это кажется мне гораздо более значительным изменением.
Ответ 3
Существует аналогичный вопрос, поставленный здесь, я смог программно создать r кусков и связать выходные данные для использования в flexdashboard (довольно полезно) на основе произвольного списка входных графиков, используя knit_expand (text =) и r paste(knitr::knit(text = paste(out, collapse = '\n')))
методы r paste(knitr::knit(text = paste(out, collapse = '\n')))
.