2016-02-19 22 views
4

我在R Markdown中編寫了一份報告,其中我不想在報告的主體中打印任何R代碼 - 我只想顯示圖,計算我將其替換爲文本內聯的變量,並且有時會顯示少量的原始R輸出。因此,我寫這樣的東西:R Markdown - 打印文檔中使用的所有代碼片段的簡明方法

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} 
``` 

我想我可以寫一些後處理代碼來掃描.Rmd文件,找到所有代碼片斷,並用正則表達式或其他東西(我似乎記得有一些選項文件可以用來將命令注入到pandoc進程中?),但我'希望可能會更簡單些。

編輯:這絕對不是一個重複的 - 如果你仔細閱讀我的問題,最後一個代碼塊展示我到底做答案的鏈接的問題提出了什麼(在語法上的些許差異,這可能是混亂的根源?)。我正在尋找一種方法,無需手動爲文檔中的所有20個代碼片段寫出最後一個代碼塊。

+1

的可能的複製[使用rmarkdown/knitr來保存所有代碼,直到結束](http://stackoverflow.com/question/28458384/use-rmarkdown-knitr-to-hold-all-code-until-the-end) – kukushkin

+0

你可能會調用'purl()'來生成一個包含所有代碼塊的外部R文件,將它讀回該文檔可能在將eval = FALSE重新定義爲默認值並刪除最後兩個塊(用於purl和用於顯示的塊)之後。 – baptiste

+0

實際上,[purl可以關閉](http://stackoverflow.com/a/17246052/471093)最後兩個塊 – baptiste

回答

2

由於這對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) 

現在,我們可以讓knitr用pandoc_args執行它。請注意,我們需要記住在文檔的末尾添加佔位符。

--- 
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中編寫它,你不需要佔位符。還可以定製代碼塊在最後返回的方式,以在每個代碼塊之前添加標題。

+1

工程很棒。我想添加的一件事就是在代碼塊上面寫一些描述其內容的文本。就像你說的那樣,當我有更多的空閒時間來玩時,這應該是一個簡單的定製。 另外請注意,在這個工作之前,我必須做一個'sudo pip install pandocfilters' - 它在第一次失敗時出現了一個非常神祕的錯誤,而不是第一次追蹤。 –

2

這是在knitr中可以實現的,不需要使用pandoc。基於在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} 

``` 

這將打印所有塊碼。目前它們全部出現在一個區塊中;我很想弄清楚如何放入大塊標籤或其他標題......現在,我用評論開始我的大塊(在任何情況下可能不是一個壞主意)。

更新:只顯示進行了評價,該塊,使用: ref.label = all_labels(!exists('engine')) - 參見問題40919201

+0

請注意,函數'all_labels()'在knitr中找到,因此您還必須使用'library(knitr)'加載knitr或明確引用它:'{r show-code,ref.label = knitr :: all_labels ),echo = TRUE,eval = FALSE}。 – Frank

相關問題