2015-08-13 31 views
10

Mój problem jest podobny do this one; kiedy generuję obiekty fabuły (w tym przypadku histogramy) w pętli, wydaje się, że wszystkie z nich zostają nadpisane przez najnowszy wykres.Przechowywanie obiektów ggplot na liście z pętli wewnętrznej w R

Aby przeprowadzić debugowanie, w pętli drukuję indeks i wygenerowany wykres, które wyglądają prawidłowo. Ale kiedy patrzę na działki zapisane na liście, wszystkie są identyczne pod względem z wyjątkiem dla etykiety.

(używam multiplot dokonać złożony obraz, ale masz ten sam wynik, jeśli print (myplots[[1]]) poprzez print(myplots[[4]]) jednej na raz).

Bo już dołączony dataframe (w przeciwieństwie do plakat podobny problem), nie jestem pewien, jak rozwiązać problem.

(btw, zajęcia kolumn są czynnikiem w oryginalnym zbiorze ja zbliżonej tutaj, ale sam problem występuje, jeśli są one całkowitą)

Oto powtarzalne przykład:

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) 

Kiedy patrzę na podsumowanie obiektu działka w liście działce, to co widzę

> 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) 

myślę że mapping: x = data2[, i] jest problem, ale jestem zakłopotany! Nie mogę publikować obrazów, więc musisz poprowadzić mój przykład i spojrzeć na wykresy, jeśli moje wyjaśnienie problemu jest mylące.

Dzięki!

Odpowiedz

22

Oprócz drugiej doskonałą odpowiedź, oto rozwiązanie, które korzysta z „normalną” ocenę -looking zamiast eval. Ponieważ pętle for nie mają oddzielnego zakresu zmiennego (tj. Są wykonywane w bieżącym środowisku), musimy użyć local do owinięcia bloku for; Ponadto, musimy dokonać i zmienną lokalną - co możemy zrobić po prostu ponowne przypisanie go:

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

Jednak całkowicie przejrzysty sposób jest zrezygnować pętlę for całkowicie i używać funkcji list do budowy wynik. Działa to na kilka różnych sposobów. Poniżej znajduje się najłatwiej moim zdaniem:

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) 

ta ma wiele zalet: jest prostsze i nie będą zaśmiecać środowiska (ze zmienną pętlą i).

+0

fajny pomysł z funkcją – jenesaisquoi

+0

Dziękuję bardzo, szczególnie za wersję lapply; Chciałem to funkcjonalizować, ale nie mogłem tego rozgryźć i postanowiłem zrobić (pozornie łatwiejsze, wręcz okropne) pętle. Pomyślałem, że to problem o zmiennym zakresie, często walczę z nimi w R! – LizPS

2

Ze względu na wszystkie cytowania wyrażeń, które są przekazywane wokół, i, który jest oceniany na końcu pętli, jest to, co i dzieje się w tym czasie, który jest jego ostateczną wartością. Możesz obejść to przez eval(substitute( we właściwej wartości podczas każdej iteracji.

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

Diagnoza jest prawidłowa, ale rozwiązanie jest nieco zawiłe. Łatwiej jest uchwycić słowo "i" w kontekście lokalnym. Problem polega na tym, że pętle 'for' w R nie mają zasięgu, więc musisz użyć' local' zamiast: 'for (i in 1: 4) local ({i = i; ... reszta pętli ...})'. Samozwarzenie "i = i" nie jest przypadkowe - jest to faktycznie potrzebne. Można również użyć innej nazwy zmiennej.Niezależnie od tego, wszystko to byłoby niepotrzebne, używając "właściwych" funkcji list zamiast "for", co jest szczerze błędnym konstruktem językowym w R. –

+0

@KonradRudolph 'local' jest ładne – jenesaisquoi

+0

Ah, zapomniałem coś: jeśli' local' jest użyte, przydział do 'myplots [[i]]' musi użyć operatora '<< -' zamiast przypisania lokalnego. –

Powiązane problemy