Armazenando objects ggplot em uma lista de dentro do loop em R

Meu problema é semelhante a este ; quando eu gero objects de plotagem (neste caso, histogramas) em um loop, parece que todos eles são sobrescritos pelo enredo mais recente.

Para depurar, dentro do loop, estou imprimindo o índice e o gráfico gerado, os quais aparecem corretamente. Mas quando olho para os charts armazenados na lista, eles são todos idênticos, exceto pelo label.

(Estou usando o multiplot para fazer uma imagem composta, mas você obtém o mesmo resultado se print (myplots[[1]]) através da print(myplots[[4]]) um de cada vez.)

Porque eu já tenho um dataframe anexado (ao contrário do poster do problema semelhante), não sei como resolver o problema.

(btw, as classs de coluna são fator no dataset original que estou aproximando aqui, mas o mesmo problema ocorre se elas forem inteiras)

Aqui está um exemplo reproduzível:

 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) 

Quando eu olho para um resumo de um object de enredo na lista de enredo, é isso que eu vejo

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

Eu acho que o mapping: x = data2[, i] é o problema, mas estou perplexo! Não posso postar imagens, então você precisará executar meu exemplo e ver os charts se a minha explicação do problema for confusa.

Obrigado!

Além da outra excelente resposta, aqui está uma solução que usa avaliação de aparência “normal” em vez de avaliação. Como loops for não possuem escopo de variável separado (isto é, eles são executados no ambiente atual), precisamos usar local para quebrar o bloco for ; Além disso, precisamos fazer de uma variável local – o que podemos fazer simplesmente re-atribuindo-a:

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

No entanto, uma maneira totalmente mais limpa é abrir completamente o loop for e usar funções de lista para construir o resultado. Isso funciona de várias maneiras possíveis. O seguinte é o mais fácil na minha opinião:

 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) 

Isso tem inúmeras vantagens: é mais simples e não sobrecarregará o ambiente (com a variável de loop i ).

Por causa de todas as citações de expressões passadas, o i que é avaliado no final do loop é o i quer que i esteja naquele momento, que é seu valor final. Você pode contornar isso por eval(substitute( ing no valor correto durante cada iteração).

 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)