Almacenamiento de objetos ggplot en una lista desde un bucle en R

Mi problema es similar a este ; cuando genero objetos de trazado (en este caso histogtwigs) en un bucle, parece que todos ellos se sobreescriben con el trazado más reciente.

Para depurar, dentro del ciclo, estoy imprimiendo el índice y el gráfico generado, los cuales aparecen correctamente. Pero cuando miro los gráficos almacenados en la lista, todos son idénticos excepto por la etiqueta.

(Estoy usando multiplot para hacer una imagen compuesta, pero obtienes el mismo resultado si print (myplots[[1]]) través de print(myplots[[4]]) uno por vez.

Como ya tengo un dataframe adjunto (a diferencia del póster del problema similar), no estoy seguro de cómo resolver el problema.

(Por cierto, las clases de columnas son un factor en el conjunto de datos original que estoy aproximando aquí, pero el mismo problema ocurre si son un número entero)

Aquí hay un ejemplo reproducible:

 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) 

Cuando miro un resumen de un objeto de la ttwig en la lista de ttwig, esto es lo que veo

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

Creo que el mapping: x = data2[, i] es el problema, ¡pero estoy perplejo! No puedo publicar imágenes, por lo que tendrá que ejecutar mi ejemplo y observar los gráficos si mi explicación del problema es confusa.

¡Gracias!

Además de la otra respuesta excelente, aquí hay una solución que utiliza evaluación de aspecto “normal” en lugar de eval . Como los bucles for no tienen un ámbito de variable separado (es decir, se realizan en el entorno actual), necesitamos utilizar local para envolver el bloque for ; Además, debemos hacer que i una variable local, lo cual podemos hacer simplemente reasignándolo:

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

Sin embargo, una forma totalmente más limpia es renunciar for completo al bucle for y usar funciones de lista para generar el resultado. Esto funciona de varias maneras posibles. Lo siguiente es lo más fácil en mi opinión:

 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) 

Esto tiene numerosas ventajas: es más simple y no saturará el entorno (con la variable de ciclo i ).

Debido a todas las citas de las expresiones que se pasan, la i que se evalúa al final del ciclo es lo que sea que esté en ese momento, que es su valor final. Puedes eval(substitute( esto por eval(substitute( el valor correcto durante cada iteración).

 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)