生成动态的R Markdown块

27

在我的数据集中,我有60个组,希望使用R Markdown将其分析并放入HTML报告中。由于我想对每个组应用相同的分析方法,因此希望有一种方法可以动态生成代码块/分析。

简单地说,我想避免重复复制代码块60次。

我看到了这个问题,其中使用了knitr中的children。我已经尝试使用鸢尾花数据集重现此问题。在下面的示例中,我只想为每个物种生成三个H4标题。

值得注意的是,我并没有固定使用这种方法,只是似乎与我想做的事情相关。

以下是我使用的文件:

parent.RMD文件。 这将是我的“主”报告。

Automate Chunks of Analysis in R Markdown 
========================================================


```{r setup, echo=FALSE}
library(knitr)
```


```{r run-numeric-md, include=FALSE}
out = NULL
for (i in as.character(unique(iris$Species))) {
  out = c(out, knit_child('child.Rmd'))
}

这里是 child.Rmd

#### Species = `r [i]`

另一种解决方案是使用我的 pander 包,只需一个支持循环的 brew 文件:http://rapporter.github.io/pander/#brew-to-pandoc。请参见“short-code-long-report”示例。 - daroczig
太棒了,我会去看看。 - Btibert3
1
请点击以下链接查看与您相关的编程问题:https://dev59.com/wVUK5IYBdhLWcg3w4TGN#51159788 - moodymudskipper
2个回答

28

尝试使用knit_expand()函数:

Automate Chunks of Analysis in R Markdown 
========================================================

```{r setup, echo=FALSE}
library(knitr)
```

```{r run-numeric-md, include=FALSE}
out = NULL
for (i in as.character(unique(iris$Species))) {
  out = c(out, knit_expand(text='#### Species = {{i}}'))
}
```

`r paste(knit(text = out), collapse = '\n')`

您还可以创建一个模板文件,例如'child.rmd'并将其放入您的for循环中,这样您就不必将复杂的分析放在引号中:

out = c(out, knit_expand('template.rmd'))

然后将您的 'template.rmd' 设为:

#### Species = {{i}}

1
好的,这正是我所期望的。我的问题是,为什么需要 r paste(knit(text = out), collapse = '\n')?当我编译时,它是否会事先编织循环?我只是想理解这段代码。谢谢! - Btibert3
2
你在for循环中创建的是一个字符向量,但是你希望它像文件的其余非代码部分一样具有字符回车(\n)来分隔不同的行,因此通过在\n上合并向量来实现这一点。 - Sam Dickson
这对于在flexdashboard中自动化输出非常有用。但我想了解的是为什么需要编写\r paste(knit...`而不是`r knit..``(没有paste)。FYI,在运行knit之前,我会折叠所有文本,即knit(paste(out_list, collapse = "\n")) - Danton Noriega
@DantonNoriega 我需要看到你的代码的其余部分才能确定是否有必要。如果没有它也可以正常运行,那么就排除它。将其放入可以确保文本被正确解释,不会假定你是用字符\n而不是换行符结束你的编织。 - Sam Dickson
@Sam Dickson 我当前的猜测是它与调用子文档有关。在我更复杂的 flexdashboard 中,如果没有 paste 就会崩溃,但是当我制作一个更简单的版本时,似乎并不重要。唯一的主要区别是我更复杂的那个正在将 Rmd 文件作为子文档进行调用。否则,在独立的 Rmd 中无论何时都能正常工作。请参见[示例Gist] (https://gist.githubusercontent.com/ultinomics/61559f39c06df92cca1f594bc63bcb8f/raw/bf0003df3193b65268decd83ceebb6d076ab1f9d/auto-tab-flexdashboard.Rmd)。 - Danton Noriega

6

参考 @sam 的解决方案,我制作了以下通用函数。假设您有一个名为 grfDf 的数据框,其中包含在列 graph 中的 DiagrammeR 图形对象。只需要使用以下代码即可在 Rmd 中绘制所有图形: r require(DiagrammeR); renderHtmlWidgetList(grfDf$graph, render_graph)。请查看代码中的注意事项。

```
require(knitr)

#' Render a list of htmlWidgets using various tricks
#'
#' @param widgetList A list of htmlWidget objects to be rendered
#' @param renderFunction The function to render individual widgets. It can be either a name
#'   of the rendering function, e.g., "render_graph" in DiagrammeR, or the actual function to
#'   be passed to this call.
#' @return The knitted string. This is to be included in the output by using `r renderHtmlWidgetList(...)`;
#' @details This is a collection of various tricks. See the URL citations in the code.
#'   Note that this code does alliterate global variables starting with "renderHtmlWidgetList_".
#'   You may want to delete them using rm(list = ls(pattern="renderHtmlWidgetList_*")).
#' @examples Inlcude the following in the Rmd directly
#'   `r require(DiagrammeR); renderHtmlWidgetList(grfDf$graph, render_graph)`
#'
#' @export

renderHtmlWidgetList <- function(widgetList, renderFunction){
  # error checking
  stopifnot(is.list(widgetList))
  # handles if the renderFunction is actually a function
  # https://dev59.com/qWkv5IYBdhLWcg3wiRao
  if(is.function(renderFunction)) {
    # convert back to string, because we need to knit it later
    renderFunction <- deparse(substitute(renderFunction))
  }
  stopifnot(is.character(renderFunction) & length(renderFunction)==1)
  stopifnot(exists(renderFunction, mode = "function"))
  # inject global vars; make sure we have a unique global var name
  gVarName<- paste0("renderHtmlWidgetList_", sample(1:10000, 1))
  while (exists(gVarName)) {
    gVarName<- paste0("renderHtmlWidgetList_", sample(1:10000, 1))
  }
  # assigning widgetList to a global temp var
  # https://dev59.com/3W035IYBdhLWcg3wSN-r
  assign(gVarName, widgetList, envir = .GlobalEnv)
  # solution from https://gist.github.com/ReportMort/9ccb544a337fd1778179
  out <- NULL
  knitPrefix <- "\n```{r results='asis', cache=FALSE, echo=FALSE}\n\n"
  knitSuffix <- "\n\n```"
  for (i in 1:length(widgetList)) {
    knit_expanded <- paste0(knitPrefix, renderFunction, "(", gVarName, "[[", i, "]])")
    out = c(out, knit_expanded)
  }
  #invisible(out)
  paste(knitr::knit(text = out), collapse = '\n')
}
```

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接