2012-08-23 60 views
36

我正在嘗試使用knitr生成一份報告,該報告對數據集的不同子集執行相同的分析集。該項目包含兩個Rmd文件:第一個文件是設置工作區和文檔的主文檔,第二個文件僅包含執行分析並生成相關數字的塊。R knitr:可以通過編程修改塊標籤嗎?

我想要做的就是編織主文件,然後它會爲每個數據子集調用第二個文件,並將結果包含在單個文檔中。下面是一個簡單的例子。

主控文檔:

# My report 

```{r} 
library(iterators) 
data(mtcars) 
``` 

```{r create-iterator} 
cyl.i <- iter(unique(mtcars$cyl)) 
``` 

## Generate report for each level of cylinder variable 
```{r cyl4-report, child='analysis-template.Rmd'} 
``` 

```{r cyl6-report, child='analysis-template.Rmd'} 
``` 

```{r cyl8-report, child='analysis-template.Rmd'} 
``` 

分析-template.Rmd:

```{r, results='asis'} 
cur.cyl <- nextElem(cyl.i) 
cat("###", cur.cyl) 
``` 

```{r mpg-histogram} 
hist(mtcars$mpg[mtcars$cyl == cur.cyl], main = paste(cur.cyl, "cylinders")) 
``` 

```{r weight-histogam} 
hist(mtcars$wt[mtcars$cyl == cur.cyl], main = paste(cur.cyl, "cylinders")) 
``` 

問題是knitr不允許非唯一的一塊標籤,因此針織失敗時analysis-template.Rmd稱爲第二時間。這個問題可以通過留下未命名的塊來避免,因爲自動生成唯一的標籤。然而,這並不理想,因爲我想使用塊標籤爲導出的圖創建信息文件名。


的潛在解決方案將是使用一個簡單的函數,當前氣缸附加到塊標籤:

```r{paste('cur-label', cyl, sep = "-")} 
``` 

但它不會出現knitr將在塊標籤位置計算表達式。


我也嘗試使用自定義chunk hook是修改了當前塊的標籤:

knit_hooks$set(cyl.suffix = function(before, options, envir) { 
    if (before) options$label <- "new-label" 
}) 

但改變了塊標籤並不會影響產生地塊的文件名,所以我不認爲knitr正在使用新標籤。


有關如何更改塊標籤,以便可以多次調用同一子文檔的任何想法?或者也許是一個替代策略來實現這一點?

回答

35

對於任何遇到這篇文章的人來說,我想指出@Yihui在knitr 1.0中爲這個問題提供了一個formal solution,並引入了knit_expand()函數。它工作得很好,真的簡化了我的工作流程。

例如,以下將處理以下模板腳本的mtcars$cyl每一級,每次具有其當前值替換的{{ncyl}}所有實例(在模板):

# My report 

```{r} 
data(mtcars) 
cyl.levels <- unique(mtcars$cyl) 
``` 

## Generate report for each level of cylinder variable 
```{r, include=FALSE} 
src <- lapply(cyl.levels, function(ncyl) knit_expand(file = "template.Rmd")) 
``` 

`r knit(text = unlist(src))` 

模板:

```{r, results='asis'} 
cat("### {{ncyl}} cylinders") 
``` 

```{r mpg-histogram-{{ncyl}}cyl} 
hist(mtcars$mpg[mtcars$cyl == {{ncyl}}], 
    main = paste({{ncyl}}, "cylinders")) 
``` 

```{r weight-histogam-{{ncyl}}cyl} 
hist(mtcars$wt[mtcars$cyl == {{ncyl}}], 
    main = paste({{ncyl}}, "cylinders")) 
``` 
+0

我已經使用了這種方法,但注意到在模板中使用'echo = FALSE'會導致代碼未被處理。你有沒有注意到同樣的行爲? –

+0

**編輯**:我已經使用了這個方法以及** bookdown **包,並注意到在模板中使用'results ='asis''和'echo = FALSE'會導致代碼未被處理。解決方案是讓每個輸出都在一個單獨的代碼塊中。 –

14

如果你在你的**名稱中作出所有塊,即```{r}它的作品。這當然不是很優雅,但有兩個問題阻止您更改當前塊的標籤:

  1. 在執行代碼塊之前解析文件。在執行任何代碼或調用自定義鉤子之前,解析器已經檢測到重複標籤。
  2. 在鉤子被調用之前處理塊選項(包括標籤)(邏輯:它是一個觸發鉤子的選項),所以鉤子不能再改變標籤。

未命名塊的工作原理是在內部他們得到標籤unnamed-chunk- +塊號。

塊不能有重複的名稱,因爲內部knitr通過標籤引用它們。修復可能是讓knitr將塊號添加到所有重名名稱的塊。或者用塊數而不是標籤來引用它們,但是在我看來這是一個更大的變化。

+7

你的理解絕對正確,這是一個令人信服的案例,knitr需要一些改變。我正在查看你的拉請求。謝謝! –

+0

@羅洛,你對針織者內在運作的解釋是非常有幫助的。我真的很感謝你花時間寫下[執行你的解決方案的代碼](https://github.com/yihui/knitr/issues/368)。 @易輝,你認爲你會包括這個改變嗎?它可以解決我試圖完成的90%的任務,並且除了修改後的塊標籤外,還可以使我無需保存相同的Rmd文件的副本。理想的解決方案將允許像for(for unique(mtcars $ cyl))knit_child(「analysis-template.Rmd」,label.suffix = i)',如果它是可信的。 – aaronwolen

+1

是的,我認爲我傾向於接受拉請求;只需再給我幾分鐘的時間,因爲我仍然有一些替代解決方案。解決這個問題很容易,但很難決定使用哪種解決方案。 –

相關問題