2015-08-13 85 views
10

我的問題類似於this one;當我在循環中生成繪圖對象(在這種情況下是直方圖)時,似乎它們都被最近的繪圖覆蓋。將ggplot對象存儲在循環中的列表中R

要在循環內進行調試,我打印索引和生成的圖,兩者都顯示正確。但是當我查看存儲在列表中的圖表時,它們都是相同的,但標籤的除外。

(我使用的multiplot使合成圖像,但你如果你print (myplots[[1]]) 通過print(myplots[[4]])一次一個相同的結果。)

因爲我已經有一個附加的數據框(不像的海報類似的問題),我不知道如何解決這個問題。

(順便說一句,列類是在原有的數據集,我在這裏近似的因素,但如果是整數發生同樣的問題)

這裏是一個重複的例子:

library(ggplot2) 
source("http://peterhaschke.com/Code/multiplot.R") #load multiplot function 

#make sample data 
col1 <- c(2, 4, 1, 2, 5, 1, 2, 0, 1, 4, 4, 3, 5, 2, 4, 3, 3, 6, 5, 3, 6, 4, 3, 4, 4, 3, 4, 
      2, 4, 3, 3, 5, 3, 5, 5, 0, 0, 3, 3, 6, 5, 4, 4, 1, 3, 3, 2, 0, 5, 3, 6, 6, 2, 3, 
      3, 1, 5, 3, 4, 6) 
col2 <- c(2, 4, 4, 0, 4, 4, 4, 4, 1, 4, 4, 3, 5, 0, 4, 5, 3, 6, 5, 3, 6, 4, 4, 2, 4, 4, 4, 
      1, 1, 2, 2, 3, 3, 5, 0, 3, 4, 2, 4, 5, 5, 4, 4, 2, 3, 5, 2, 6, 5, 2, 4, 6, 3, 3, 
      3, 1, 4, 3, 5, 4) 
col3 <- c(2, 5, 4, 1, 4, 2, 3, 0, 1, 3, 4, 2, 5, 1, 4, 3, 4, 6, 3, 4, 6, 4, 1, 3, 5, 4, 3, 
      2, 1, 3, 2, 2, 2, 4, 0, 1, 4, 4, 3, 5, 3, 2, 5, 2, 3, 3, 4, 2, 4, 2, 4, 5, 1, 3, 
      3, 3, 4, 3, 5, 4) 
col4 <- c(2, 5, 2, 1, 4, 1, 3, 4, 1, 3, 5, 2, 4, 3, 5, 3, 4, 6, 3, 4, 6, 4, 3, 2, 5, 5, 4, 
      2, 3, 2, 2, 3, 3, 4, 0, 1, 4, 3, 3, 5, 4, 4, 4, 3, 3, 5, 4, 3, 5, 3, 6, 6, 4, 2, 
      3, 3, 4, 4, 4, 6) 
data2 <- data.frame(col1,col2,col3,col4) 
data2[,1:4] <- lapply(data2[,1:4], as.factor) 
colnames(data2)<- c("A","B","C", "D") 

#generate plots 
myplots <- list() # new empty list 
for (i in 1:4) { 
    p1 <- ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+ 
    geom_histogram(fill="lightgreen") + 
    xlab(colnames(data2)[ i]) 
    print(i) 
    print(p1) 
    myplots[[i]] <- p1 # add each plot into plot list 
} 
multiplot(plotlist = myplots, cols = 4) 

當我看在情節列表中的劇情對象的總結,這是我看到

> summary(myplots[[1]]) 
data: A, B, C, D [60x4] 
mapping: x = data2[, i] 
faceting: facet_null() 
----------------------------------- 
geom_histogram: fill = lightgreen 
stat_bin: 
position_stack: (width = NULL, height = NULL) 

我認爲mapping: x = data2[, i]的問題,但我難倒!我無法發佈圖片,因此如果我對問題的解釋令人困惑,則需要運行我的示例並查看圖表。

謝謝!

回答

22

除了其他優秀的答案,這裏是一個解決方案,使用「正常」的評價而不是eval。由於for循環沒有單獨的變量範圍(即它們在當前環境中執行),我們需要使用local來包裝for塊;此外,我們需要i一個局部變量 - 我們可以通過簡單地重新分配它:

myplots <- list() # new empty list 
for (i in 1:4) 
    local({ 
     i <- i 
     p1 <- ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+ 
      geom_histogram(fill="lightgreen") + 
      xlab(colnames(data2)[ i]) 
     print(i) 
     print(p1) 
     myplots[[i]] <<- p1 # add each plot into plot list 
    }) 

然而,一個完全清潔的方式是完全放棄了for迴路,並使用列表功能來構建結果。這有幾種可能的方式。以下是我認爲最簡單的:

plot_data_column = function (data, column) 
    ggplot(data = data2, aes_string(x = column)) + 
     geom_histogram(fill = "lightgreen") + 
     xlab(column) 

myplots <- lapply(colnames(data2), plot_data_column, data = data2) 

這有許多優點:它的簡單,不會弄亂環境(與循環變量i)。

+0

功能不錯的想法 – jenesaisquoi

+0

非常感謝你,特別是對於lapply版本;我想將其功能化,但無法弄清楚,並決定爲循環做(表面上更容易,實際上是可怕的)。我認爲這是一個可變範圍問題,我經常在R中與他們戰鬥! – LizPS

2

由於所有傳入的表達式的引用,在循環結束時評估的i是無論i碰巧在那個時候,這是它的最終值。在每次迭代期間,您都可以通過正確的值來解決這個問題。

myplots <- list() # new empty list 
for (i in 1:4) { 
    p1 <- eval(substitute(
     ggplot(data=data.frame(data2),aes(x=data2[ ,i]))+ 
      geom_histogram(fill="lightgreen") + 
      xlab(colnames(data2)[ i]) 
    ,list(i = i))) 
    print(i) 
    print(p1) 
    myplots[[i]] <- p1 # add each plot into plot list 
} 
multiplot(plotlist = myplots, cols = 4) 
+0

診斷正確,但解決方案有些複雜。在本地環境中捕捉'i'更容易。問題是R中的'for'循環沒有作用域,所以你需要使用'local'來代替:'for(in in 1:4)local({i = i; ... rest of the loop ...})''。自我分配'我=我'不是偶然 - 這實際上是需要的。還可以使用不同的變量名稱。無論如何,通過使用「適當的」列表函數而不是'for',這一切都是不必要的,這在坦克裏是一個糟糕的語言結構。 –

+0

@KonradRudolph'local'很好 – jenesaisquoi

+0

啊,我忘記了一些東西:如果'local'是使用時,對'myplots [[i]]的賦值需要使用'<< - '運算符而不是本地賦值。 –