50

我正在尝试使用 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'}
```

分析模板.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 没有使用新标签。


关于如何更改块标签以便可以多次调用同一个子文档的任何想法?或者也许是实现这一目标的替代策略?

4

3 回答 3

47

对于看到这篇文章的其他人,我想指出@Yihui在 knitr 1.0 中通过引入该功能为这个问题提供了正式的解决方案。knit_expand()它工作得很好,确实简化了我的工作流程。

例如,以下将为每个级别处理下面的模板脚本,每次将(在模板中) 的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"))
```
于 2013-01-16T21:26:59.563 回答
15

如果您将 ** 中的所有块都设为无名,即```{r}它可以工作。当然,这不是很优雅,但是有两个问题阻止您更改当前块的标签:

  1. 在执行代码块之前解析文件。在执行任何代码或调用自定义挂钩之前,解析器已经检测到重复的标签。
  2. 块选项(包括标签)在调用钩子之前处理(逻辑:这是一个触发钩子的选项),因此钩子不能再更改标签。

未命名块起作用的事实是它们在内部获得标签unnamed-chunk-+块编号。

块不能有重复的名称,因为内部 knitr 通过标签引用它们。一个修复方法是让 knitr 将块编号添加到具有重复名称的所有块中。或者通过块编号而不是标签来引用它们,但这在我看来是一个更大的变化。

于 2012-08-23T18:27:41.713 回答
1

这里提出了一个类似的问题,我能够使用 knit_expand(text=) 和r paste(knitr::knit(text = paste(out, collapse = '\n')))方法根据输入图的任意列表以编程方式创建 r 块并编织输出以在 flexdashboard 中使用(非常有用) 。

于 2019-04-09T00:58:27.920 回答