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=FALSE
:opts_chunk$set(echo = FALSE)
然后把这个块放在最后打印所有代码:
```{r show-code, ref.label=all_labels(), echo = TRUE, eval=FALSE}
```
这将打印所有块的代码。目前它们都出现在一个区块中;我很想弄清楚如何放入块标签或其他一些 header... 现在我用评论开始我的块(无论如何可能不是一个坏主意)。
更新:要仅显示已评估的块,请使用:
ref.label = all_labels(!exists('engine'))
- 参见问题 40919201
我正在用 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=FALSE
:opts_chunk$set(echo = FALSE)
然后把这个块放在最后打印所有代码:
```{r show-code, ref.label=all_labels(), echo = TRUE, eval=FALSE}
```
这将打印所有块的代码。目前它们都出现在一个区块中;我很想弄清楚如何放入块标签或其他一些 header... 现在我用评论开始我的块(无论如何可能不是一个坏主意)。
更新:要仅显示已评估的块,请使用:
ref.label = all_labels(!exists('engine'))
- 参见问题 40919201