如何像源代码('myfile.r')那样获取R Markdown文件?

Jer*_*lim 74 markdown r knitr

我经常有一个主R Markdown文件或knitr LaTeX文件,其中我source有一些其他R文件(例如,用于数据处理).但是,我认为在某些情况下,将这些源文件作为自己的可再现文档(例如,R Markdown文件不仅包括用于数据处理的命令,而且还生成可重复的文档来解释数据处理将是有益的.决定).

因此,我想source('myfile.rmd')在我的主R Markdown文件中有一个命令.这将提取和源代码的R代码块内的所有R代码myfile.rmd.当然,这会引起错误.

以下命令有效:

```{r message=FALSE, results='hide'}
knit('myfile.rmd', tangle=TRUE)
source('myfile.R')
```
Run Code Online (Sandbox Code Playgroud)

results='hide'如果需要输出,可以省略.即,从knitr输出的R代码myfile.rmdmyfile.R.

但是,它似乎并不完美:

  • 它导致创建一个额外的文件
  • 如果需要控制显示,它需要出现在它自己的代码块中.
  • 它并不像简单那么优雅source(...).

因此我的问题: 是否有更优雅的方式来获取R Markdown文件的R代码?

Yih*_*Xie 30

看来你正在寻找单线.怎么样把它放在你的.Rprofile

ksource <- function(x, ...) {
  library(knitr)
  source(purl(x, output = tempfile()), ...)
}
Run Code Online (Sandbox Code Playgroud)

但是,我不明白为什么你想要source()Rmd文件本身的代码.我的意思是knit()将运行本文档中的所有代码,如果您提取代码并在一个块中运行它,所有代码将在knit()您运行此文档时运行两次(您自己运行).这两项任务应该是分开的.

如果你真的想要运行所有的代码,RStudio已经让这个变得相当简单:Ctrl + Shift + R.它基本上调用purl()source()幕后.

  • 嗨@Yihui我认为它很有用,因为有时你的分析可能是用小脚本组织的,但是在你的报告中你想拥有整个管道的代码. (8认同)
  • 因此,这里的用例是您要编写所有代码并对其进行大量记录和解释,但代码由其他一些脚本运行. (7认同)
  • @BrashEquilibrium这是一个使用`source()`或`knitr :: knit()`来运行代码的问题.我知道人们不太熟悉后者,但是'purl()`并不可靠.您已被警告:https://github.com/yihui/knitr/pull/812#issuecomment-53088636 (4认同)
  • @Yihui在您的视图中,'source(purl(x,...))'的替代方案是什么?如何才能获得多个*.Rmd-Files,而不会遇到有关重复块标签的错误?我宁愿不想回到待采购的文件并编织它.我对许多文件使用*.Rmd,我可能需要导出并与其他人讨论,因此能够为分析的所有步骤提供多个Rmd文件会很棒. (4认同)

Kei*_*ley 18

将公共代码分解为单独的R文件,然后将该R文件导入到您希望的每个Rmd文件中.

例如,假设我需要制作两份报告,流感爆发和枪支与黄油分析.当然,我会创建两个Rmd文档并完成它.

现在假设老板出现并希望看到流感爆发与黄油价格的变化(控制9毫米弹药).

  • 复制和粘贴代码以将报告分析到新报告中对于代码重用等是一个坏主意.
  • 我希望它看起来不错.

我的解决方案是将项目纳入这些文件:

  • Flu.Rmd
    • flu_data_import.R
  • Guns_N_Butter.Rmd
    • guns_data_import.R
    • butter_data_import.R

在每个Rmd文件中,我有类似的东西:

```{r include=FALSE}
source('flu_data_import.R')
```
Run Code Online (Sandbox Code Playgroud)

这里的问题是我们失去了可重复性.我的解决方案是创建一个包含在每个Rmd文件中的公共子文档.所以在我创建的每个Rmd文件的末尾,我添加了这个:

```{r autodoc, child='autodoc.Rmd', eval=TRUE}
``` 
Run Code Online (Sandbox Code Playgroud)

当然,还有autodoc.Rmd:

Source Data & Code
----------------------------
<div id="accordion-start"></div>

```{r sourcedata, echo=FALSE, results='asis', warnings=FALSE}

if(!exists(autodoc.skip.df)) {
  autodoc.skip.df <- list()
}

#Generate the following table:
for (i in ls(.GlobalEnv)) {
  if(!i %in% autodoc.skip.df) {
    itm <- tryCatch(get(i), error=function(e) NA )
    if(typeof(itm)=="list") {
      if(is.data.frame(itm)) {
        cat(sprintf("### %s\n", i))
        print(xtable(itm), type="html", include.rownames=FALSE, html.table.attributes=sprintf("class='exportable' id='%s'", i))
      }
    }
  }
}
```
### Source Code
```{r allsource, echo=FALSE, results='asis', warning=FALSE, cache=FALSE}
fns <- unique(c(compact(llply(.data=llply(.data=ls(all.names=TRUE), .fun=function(x) {a<-get(x); c(normalizePath(getSrcDirectory(a)),getSrcFilename(a))}), .fun=function(x) { if(length(x)>0) { x } } )), llply(names(sourced), function(x) c(normalizePath(dirname(x)), basename(x)))))

for (itm in fns) {
  cat(sprintf("#### %s\n", itm[2]))
  cat("\n```{r eval=FALSE}\n")
  cat(paste(tryCatch(readLines(file.path(itm[1], itm[2])), error=function(e) sprintf("Could not read source file named %s", file.path(itm[1], itm[2]))), sep="\n", collapse="\n"))
  cat("\n```\n")
}
```
<div id="accordion-stop"></div>
<script type="text/javascript">
```{r jqueryinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/jquery-1.9.1.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r tablesorterinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://tablesorter.com/__jquery.tablesorter.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r jqueryuiinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/ui/1.10.2/jquery-ui.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r table2csvinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(file.path(jspath, "table2csv.js")), sep="\n")
```
</script>
<script type="text/javascript">
  $(document).ready(function() {
  $('tr').has('th').wrap('<thead></thead>');
  $('table').each(function() { $('thead', this).prependTo(this); } );
  $('table').addClass('tablesorter');$('table').tablesorter();});
  //need to put this before the accordion stuff because the panels being hidden makes table2csv return null data
  $('table.exportable').each(function() {$(this).after('<a download="' + $(this).attr('id') + '.csv" href="data:application/csv;charset=utf-8,'+encodeURIComponent($(this).table2CSV({delivery:'value'}))+'">Download '+$(this).attr('id')+'</a>')});
  $('#accordion-start').nextUntil('#accordion-stop').wrapAll("<div id='accordion'></div>");
  $('#accordion > h3').each(function() { $(this).nextUntil('h3').wrapAll("<div>"); });
  $( '#accordion' ).accordion({ heightStyle: "content", collapsible: true, active: false });
</script>
Run Code Online (Sandbox Code Playgroud)

NB,这是专为Rmd - > html工作流程设计的.如果你选择乳胶或其他任何东西,这将是一个丑陋的混乱.此Rmd文档在全局环境中查找所有source()'ed文件,并在文档末尾包含它们的源.它包括jquery ui,tablesorter,并设置文档以使用手风琴样式来显示/隐藏源文件.这是一项正在进行的工作,但可以根据自己的用途进行调整.

我知道,不是单行.希望它至少给你一些想法:)


小智 6

试试 knitr 的 purl 函数:

source(knitr::purl("myfile.rmd", quiet=TRUE))