2015-08-13 4 views
10

Mein Problem ist ähnlich zu this one; Wenn ich Plot-Objekte (in diesem Fall Histogramme) in einer Schleife erzeuge, scheint es, dass sie alle von der letzten Plot überschrieben werden.Speichern ggplot Objekte in einer Liste von innerhalb der Schleife in R

Zum Debuggen, innerhalb der Schleife, drucke ich den Index und das generierte Diagramm, die beide korrekt angezeigt werden. Aber wenn ich mir die in der Liste gespeicherten Plots ansehe, sind sie alle identisch außer für das Label.

(Ich verwende Multiplot ein zusammengesetztes Bild zu machen, aber Sie gleiches Ergebnis, wenn man print (myplots[[1]]) durch print(myplots[[4]]) einen nach dem anderen.)

Da ich bereits einen angeschlossenen Datenrahmen habe (im Gegensatz zu dem Plakate der ähnliches Problem), ich bin mir nicht sicher, wie ich das Problem lösen soll.

(btw, Spalte Klassen Faktor in der ursprünglichen Datenmenge ich hier annähert, aber gleiche Problem tritt auf, wenn sie integer sind)

Hier ist ein reproduzierbares Beispiel:

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) 

Wenn ich mir anschaue, eine Zusammenfassung eines Plot-Objekt in der Plotliste, ist das, was ich

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

sehen ich denke, dass mapping: x = data2[, i] das Problem ist, aber ich bin ratlos! Ich kann keine Bilder posten. Sie müssen also mein Beispiel ausführen und die Grafiken betrachten, wenn meine Erklärung des Problems verwirrend ist.

Danke!

Antwort

22

Neben der anderen ausgezeichneten Antwort, hier ist eine Lösung, die „normale“ -looking Auswertung statt eval verwendet. Da for Schleifen keinen separaten Variablenbereich haben (d. H. Sie werden in der aktuellen Umgebung ausgeführt), müssen wir local verwenden, um den for Block zu umbrechen; Darüber hinaus müssen wir i eine lokale Variable machen - was wir einfach durch die Neuzuweisung es tun können:

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

jedoch ein ganz sauberer Weg ist, die for Schleife vollständig und verwenden Listenfunktionen verzichten die bauen Ergebnis. Dies funktioniert auf verschiedene Arten. Im Folgenden ist die einfachste meiner Meinung nach:

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) 

Dies hat zahlreiche Vorteile: Es ist einfacher, und es wird nicht die Umwelt Krempel (mit Schleifenvariable i).

+0

nette Idee mit der Funktion – jenesaisquoi

+0

Vielen Dank, besonders für die lapply Version; Ich wollte das funktionalisieren, konnte es aber nicht herausfinden und entschloss mich dazu, (oberflächlich einfacher, eigentlich fürchterlich) eine Schleife zu machen. Ich dachte, es wäre ein Problem mit einem variablen Oszilloskop, ich kämpfe oft mit ihnen in R! – LizPS

2

Wegen des Zitatens von Ausdrücken, die herumgereicht werden, ist die i, die am Ende der Schleife ausgewertet wird, was auch immer i zu dieser Zeit sein mag, was sein endgültiger Wert ist. Sie können dies durch eval(substitute( in der richtigen Wert während jeder Iteration umgehen.

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

Die Diagnose ist korrekt, aber die Lösung ist etwas verworren. Es ist einfacher, 'i' in einem lokalen Kontext zu erfassen. Das Problem ist, dass "For" -Schleifen in R keinen Geltungsbereich haben, also müssen Sie stattdessen 'local' verwenden:' für (i in 1: 4) lokal ({i = i; ... Rest der Schleife ...}) '. Die Selbstzuweisung "i = i" ist nicht zufällig - das ist eigentlich nötig. Ein anderer Variablenname kann ebenfalls verwendet werden.Egal, all dies wäre unnötig durch die Verwendung "richtiger" Listenfunktionen anstelle von 'for', was ehrlich gesagt ein schlechtes Sprachkonstrukt in R ist. –

+0

@KonradRudolph' local' ist nett – jenesaisquoi

+0

Ah, ich habe etwas vergessen: wenn 'local' ist verwendet, muss die Zuweisung zu 'mplotts [[i]]' den '<< - Operator anstelle der lokalen Zuweisung verwenden. –

Verwandte Themen