0

Here is a simplified version of an issue I encountered:

grob.list <- vector("list", length = 2)
for (i in 1:2) { 
  grob.list[[i]] <- qplot(1:5, 1:5 * (-1)^i)
}

grid.arrange(grobs = grob.list)

We get two of the same graph (grob.list[[1]] is wrong).

If we print (even invisibly) the grobs turn out correctly.

grob.list <- vector("list", length = 2)
for (i in 1:2) { 
  grob.list[[i]] <- qplot(1:5, 1:5 * (-1)^i)
  invisible(print(grob.list[[i]]))
}

grid.arrange(grobs = grob.list)

So does printing forces a ggplot object to "settle"? What does printing a ggplot object actually change to it?

Seems related to Grid of multiple ggplot2 plots which have been made in a for loop but doesn't address what printing does.

qwr
  • 9,525
  • 5
  • 58
  • 102
  • printing forces the evaluation of the argument `i`, otherwise R's lazy evaluation delays looking up a value for it until plot rendering time, at which point it's just 2. Add the line `force(i)` as the first line of `plot.g` in your original version of the question will fix it. – joran Mar 06 '19 at 20:37
  • In this case, `lapply` actually will do the argument forcing for you: `l <- lapply(1:2,function(i) qplot(1:5, 1:5 * (-1)^i))`. – joran Mar 06 '19 at 20:39
  • @joran can you post as answer? – qwr Mar 06 '19 at 20:40

1 Answers1

0

Printing forces the evaluation of the argument i, otherwise R's lazy evaluation delays looking up a value for it until plot rendering time, at which point it's just 2.

One option is to use force() in a function:

plot.g <- function(i) {
    force(i)
    qplot(1:5, 1:5 * (-1)^i)
}

grob.list <- vector("list", length = 2)
for (i in 1:2) { 
    grob.list[[i]] <- plot.g(i)
}

grid.arrange(grobs = grob.list)

...or use lapply which in modern versions of R will force the evaluation of the argument i:

l <- lapply(1:2,function(i) qplot(1:5, 1:5 * (-1)^i))

grid.arrange(grobs = l)
joran
  • 169,992
  • 32
  • 429
  • 468