1

I want to build a list of ggplot objects. I want to plot one variable on the x axis but plot each of the other variables in the data frame in the y. When I run the loop all of my values end up being the same as the last variable.

I'm hoping to use the grid.arrange function to plot all the graphs on one page.

My reprex:

library(ggplot2)

 l <- list()
for(i in 2:11){
    p <- ggplot(mtcars, aes(x = mpg, y = mtcars[,i])) + geom_smooth() + geom_point()
    name <- paste("p",i,sep="_")
    tmp <- list(p)
    l[[name]] <- tmp
}
print(l$p_2)
print(l$p_3)
www
  • 38,575
  • 12
  • 48
  • 84
dhbrand
  • 162
  • 3
  • 16
  • 1
    Using a loop probably isn't the best way to solve the issue. It's better to describe your original problem rather than your assumed solution to the problem. Would something like this help? https://stackoverflow.com/questions/4877357/how-to-plot-all-the-columns-of-a-data-frame-in-r – Jack Brookes Mar 08 '18 at 21:57
  • I did describe my original problem in the first 2 sentences. The link you sent is not the same. I cannot plot on the same graph because my variables have unique scales like they do in the reprex. I looked at facet_grid but it uses a static value for aes(y =). – dhbrand Mar 08 '18 at 22:07
  • Here's my tidyverse solution which I think is a lot cleaner than the ones below, now the question is closed https://gist.github.com/jackbrookes/3bbcc47cdd246b3d8a9173a4b9bacf43 – Jack Brookes Mar 08 '18 at 22:23

2 Answers2

3

You can create a list of plots directly using sapply. For example:

plist = sapply(names(mtcars)[-grep("mpg", names(mtcars))], function(col) {
  ggplot(mtcars, aes_string(x = "mpg", y = col)) + geom_smooth() + geom_point()
}, simplify=FALSE)

The list elements (each of which is a ggplot object) will be named after the y variable in the plot:

names(plist)
[1] "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"

You can print all the plots by typing plist in the console. Or, for a single plot, just select the plot you want:

plist[["hp"]]

enter image description here

For a situation like this, you might prefer faceting, which requires converting the data from wide to long format. You can have facets with different y scales by setting scales="free_y".

library(tidyverse)

ggplot(gather(mtcars, key, value, -mpg), aes(mpg, value)) + 
  geom_smooth() + geom_point() +
  facet_wrap(~ key, scales="free_y", ncol=5)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
2

Subset the data frame before calling ggplot, and then use aes_string to call column names as string.

library(ggplot2)

l <- list()
for(i in 2:11){
  temp <- mtcars[, c(1, i)]
  p <- ggplot(temp, aes_string(x = "mpg", y = names(temp)[2])) + geom_smooth() + geom_point()
  name <- paste("p",i,sep="_")
  tmp <- list(p)
  l[[name]] <- tmp
}
print(l$p_2)

enter image description here

print(l$p_3)

enter image description here

www
  • 38,575
  • 12
  • 48
  • 84