0

I am trying to store in a list some plots built through this code:

list7 = NULL
for (col in colnames(mtcars)[1:2]) {
  list7[[col]] <- 
    ggplot(mtcars, aes(x= mtcars[,col])) + 
    geom_histogram(aes(y=..density..), color="darkblue", fill="lightblue")+
    geom_density(alpha=.2, fill="#FF6666") + 
    ggtitle(paste0(col, ' score distribution')) + 
    xlab(col) +   
    theme_classic()
}

I cannot understand why despite I have the right information about the axis names, titles and list names, the plots represent similar results.

Could anyone help me to figure out why? Thanks

12666727b9
  • 1,133
  • 1
  • 8
  • 22
  • 1
    `list7 <- lapply(colnames(mtcars)[1:2], function(col) { ggplot(mtcars, aes(x= mtcars[,col])) + geom_histogram(aes(y=..density..), color="darkblue", fill="lightblue")+ geom_density(alpha=.2, fill="#FF6666") + ggtitle(paste0(col, ' score distribution')) + xlab(col) + theme_classic() })` – r2evans Jul 07 '23 at 14:39
  • 1
    You're getting tripped up by the fact that `aes()` uses lazy evaluation and for loops do not create their own scopes. See the duplicates for more info (I'm sure you can find a lot more as well; it's a common issue). A quick fix is to use `aes(x= .data[[col]])` instead, or avoid the loop and use `lapply` – MrFlick Jul 07 '23 at 14:41
  • @r2evans thanks you. What about if I would like to include the name of the list? Should be this put with the brackets `{}` as `list7[[col]]` = ....? – 12666727b9 Jul 07 '23 at 14:53
  • @12666727b9, why would you need/want to do that? The `lapply` is already assigning the values to each element of a `list` which is then stored in `list7` once `lapply` is done. Even if you predefine `list7 <- NULL` before hand and assuming that you _don't_ assign `list7 <- lapply(...)`, then ... the anon-function has no immediate idea of which element in `list7` it should be referencing. For that, we'd need some indirection (`seq_along` some vector of choice), which afaict adds nothing to this problem. – r2evans Jul 07 '23 at 15:03
  • 1
    Said differently, my code works, and is in many ways the preferred/canonical way of filling a `list` with iterated calculations (though certainly not the only, and usually but not always the fastest). – r2evans Jul 07 '23 at 15:04

1 Answers1

1

Replace your ggplot call with:

ggplot(mtcars, aes(x= !!sym(col)))
LMc
  • 12,577
  • 3
  • 31
  • 43
  • Interesting. Could you please give some further notion about this `!!` which I ignore the meaning? – 12666727b9 Jul 07 '23 at 14:57
  • 1
    @12666727b9 Yes, `sym` will turn your string from `"mpg"` into an unquoted symbol `mpg`. `!!` will inject this symbol into the expression *before* it is evaluated. So after `!!` and before evaluation it will read as `ggplot(mtcars, aes(x= mpg))` during the first iteration of your `for` loop. – LMc Jul 07 '23 at 15:01
  • Try running `col <- "mpg"; rlang::qq_show(ggplot(mtcars, aes(x= !!sym(col))))` to see this. – LMc Jul 07 '23 at 15:02
  • 1
    For more information see the documentation on the injection operator ``?`!!` `` and you can read more about quasiquotation [here](https://adv-r.hadley.nz/quasiquotation.html). – LMc Jul 07 '23 at 15:04