R Markdown——一种打印文档中使用的所有代码片段的简洁方法

R Markdown – a concise way to print all code snippets used in the document

我正在用 R Markdown 编写报告,其中我不想在报告主体中打印我的任何 R 代码——我只想显示图表,计算我代入的变量内联文本,有时会显示少量原始 R 输出。因此,我这样写:

In the following plot, we see that blah blah blah:
```{r snippetName, echo=F}
plot(df$x, df$y)
```

Now...

一切都很好。但我也想在文档末尾提供 R 代码,以供任何想知道它是如何生成的人使用。现在我必须手动写这样的东西:

Here is snippet 1, and a description of what section of the report
this belongs to and how it's used:
```{r snippetName, eval=F}
```
Here is snippet 2:
```{r snippetTwoName, eval=F}
```
<!-- and so on for 20+ snippets -->

一旦有多个代码片段,这将变得相当乏味且容易出错。有什么办法可以遍历片段并自动打印出来吗?我希望我可以做类似的事情:

```{r snippetName, echo=F, comment="This is snippet 1:"}
# the code for this snippet
```

并在编织时以某种方式将以下结果替换到文档中的指定点:

This is snippet 1:
```{r snippetName, eval=F}
```

我想我可以写一些 post 处理代码来扫描 .Rmd 文件,找到所有片段,然后用正则表达式或其他东西提取代码(我似乎记得有某种选项文件可以用来将命令注入 pandoc 进程?),但我希望可能有更简单的东西。

编辑:这绝对不是重复的——如果你仔细阅读了我的问题,最后的代码块显示我正在做链接问题的答案所建议的(带有语法上的细微差别,这可能是混淆的根源?)。我正在寻找一种无需为文档中的所有 20 多个片段手动写出最后一个代码块的方法。

由于使用 knitr 做到这一点即使不是不可能,也是相当困难的,我们可以利用下一步,即 pandoc 编译,以及 pandoc 使用过滤器操作内容的能力。所以我们用 echo=TRUE 编写了一个普通的 Rmd 文档,代码块在调用时照常打印。

然后,我们编写一个过滤器来查找语言 R 的每个代码块(这就是代码块在 pandoc 中的编码方式),将其从文档中删除(在这里用一个空段落替换它)并存储它在列表中。然后我们在文档末尾添加所有代码块的列表。对于这最后一步,问题是确实没有办法告诉 python 过滤器在文档末尾添加内容(haskell 中可能有办法,但我不知道知道)。所以我们需要在Rmd文档的末尾添加一个占位符,告诉过滤器在此时添加R代码。在这里,我认为占位符将是 CodeBlock 代码 lastchunk.

这是过滤器,我们可以将其另存为 postpone_chunks.py

#!/usr/bin/env python

from pandocfilters import toJSONFilter, Str, Para, CodeBlock

chunks = []


def postpone_chunks(key, value, format, meta):
    if key == 'CodeBlock':
        [[ident, classes, keyvals], code] = value
        if "r" in classes:
            chunks.append(CodeBlock([ident, classes, keyvals], code))
            return Para([Str("")])
        elif code == 'lastchunk':
            return chunks

if __name__ == "__main__":
    toJSONFilter(postpone_chunks)

现在,我们可以用pandoc_args让knitr执行它。注意,我们需要记得在文档末尾添加占位符。

---
title: A test
output:
  html_document: 
    pandoc_args: ["--filter", "postpone_chunks.py"]
---

Here is a plot.

```{r}
plot(iris)
```

Here is a table.

```{r}
table(iris$Species)
```

And here are the code chunks used to make them:

    lastchunk

在 haskell 中可能有更好的写法,您不需要占位符。还可以自定义最后返回代码块的方式,例如在每个代码块之前添加一个标题。

这是knitr中的do-able,不需要使用pandoc。基于 Yihui 在 https://github.com/yihui/knitr-examples/blob/master/073-code-appendix.Rnw

发布的示例

在整个文档中设置 echo=FALSEopts_chunk$set(echo = FALSE)

然后把这个块放在最后打印所有代码:

 ```{r show-code, ref.label=all_labels(), echo = TRUE, eval=FALSE}

 ```

这将打印所有块的代码。目前它们都出现在一个区块中;我很想弄清楚如何放入块标签或其他一些 header... 现在我用评论开始我的块(无论如何可能不是一个坏主意)。

更新:要仅显示已评估的块,请使用: ref.label = all_labels(!exists('engine')) - 参见问题 40919201