Подтвердить что ты не робот

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 использует новую метку.


Любые идеи о том, как изменить метки ярлыков, чтобы один и тот же дочерний документ можно было вызывать несколько раз? Или, возможно, альтернативная стратегия для этого?

4b9b3361

Ответ 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'))).