I'm using a for loop
to assign ggplots to a list
, which is then passed to plot_grid()
(package cowplot
). plot_grid
places multiple ggplots side by side in a single figure. This works fine manually, but when I use a for loop
, the last plot generated is repeated in each subframe of the figure (shown below). In other words, all the subframes show the same ggplot.
Here is a toy example:
require(cowplot)
dfrm <- data.frame(A=1:10, B=10:1)
v <- c("A","B")
dfmsize <- nrow(dfrm)
myplots <- vector("list",2)
count = 1
for(i in v){
myplots[[count]] <- ggplot(dfrm, aes(x=1:dfmsize, y=dfrm[,i])) + geom_point() + labs(y=i)
count = count +1
}
plot_grid(plotlist=myplots)
Expected Figure:
Figure from for loop
:
I tried converting the list elements to grobs, as described in this question, like this:
mygrobs <- lapply(myplots, ggplotGrob)
plot_grid(plotlist=mygrobs)
But I got the same result.
I think the problem lies in the loop assignment, not plot_grid()
, but I can't see what I'm doing wrong.
The answers so far are very close, but unsatisfactory in my opinion. The problem is the following - after your
for
loop:As the other answers mention,
ggplot
doesn't actually evaluate those expressions until plotting, and since these are all in the global environment, and the value ofi
is"B"
, you get the undesirable results.There are several ways of avoiding this issue, the simplest of which in fact simplifies your expressions:
The reason this works, is because the environment is different for each of the values in the
lapply
loop:So even though the expressions are the same, the results are different.
And in case you're wondering what exactly is stored/copied to the environment of
lapply
- unsurprisingly it's just the column name:There is a nice explanation of what happens with ggplot2's lazy evaluation and for loops in [this answer](https://stackoverflow.com/a/26246791/2461552.
I usually switch to
aes_string
oraes_
for situations like this so I can use variables as strings in ggplot2.I find
lapply
loops easier than afor
loop in your case as initializing the list and using the counter can be avoided.First, I add the x variable to the dataset.
Now, the
lapply
loop, looping through the columns inv
.I think
ggplot
is getting confused by looking for yourx
andy
variables inside ofdfrm
even though you are actually defining them on the fly. If you change thefor
loop slightly to build a new subdata.frame
as the first line it works just fine.I believe the problem here is that the non-standard evaluation of the
aes
method delays evaluatingi
until the plot is actually plotted. By the time of plotting,i
is the last value (in the toy example "B") and thus they
aesthetic mapping for all plots refers to that last value. Meanwhile, thelabs
call uses standard evaluation and so the labels correctly refer to each iteration ofi
in the loop.This can be fixed by simply using the standard evaluation version of the mapping function,
aes_q
: