Francis
Francis

Reputation: 6726

How to pass a vector of ggplot objects to grid.arrange function?

Perhaps the problem has been asked and solved, but the solution didn't work for me. I wrote a function able to create ggplot objects and return them in a vector. The following is the code inside the function, vars is a vector of column names of my data d.

plotting <- function(d){
    P <- numeric(0)
    vars <- names(d)[!names(d)%in%c('channel','label')]
    for (var in vars){
        p <- ggplot(d, aes(x=channel,y=var)) + 
             geom_boxplot(aes(fill=label)) + ggtitle(var)
        P <- c(P,p)
    }
    return(list(plots=P, num=length(vars)))
}

What I want to do is to use the above function to return a concatenated lists P consisting of several ggplots objects as following which is the 'manual' version working fine:

p1 <- ggplot()+ ...
p2 <- ggplot()+ ...
p3 <- ggplot()+ ...
pdf('...')
grid.arrange(p1, p2, p3, nrow = 3)
dev.off()

The purpose of returning num is for latter usage in layout arg. of grid.arrange function. I have PLOTS as returning variable:

PLOTS <- plotting(d)
pdf('...')
grid.arrange(PLOTS$plots, PLOTS$num)
dev.off()

and I got error:

Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main,  :
input must be grobs!

So I tried the solution in Passing a vector to grid.arrange as a list of arguments.

do.call(grid.arrange, c(PLOTS$plots, nrow = PLOTS$num))

but still get the same error. Any comment would be appreciated.

Edit: made problem description clearer, and paste the reproducible data d below:

structure(list(percent = c(0.0962463533974437, 0.129409967469436,
0.0150265653130588, 0.00299276735619027, 0.0108596845008112,
0.00407417010800106), songs = c(0.231617443342384, 0.430320945945946,
0.109264389042782, 0.282109656611649, 0.0288753799392097, 0.041635687732342
), label = c("1", "1", "1", "1", "1", "1"), channel = c("2",
"2", "2", "2", "2", "2")), .Names = c("percent", "songs", "label",
"channel"), row.names = c(NA, 6L), class = "data.frame")

Please input d as argument to plotting and proceed to PLOTS$plots to help me for debugging, thank you!

Upvotes: 6

Views: 6522

Answers (1)

shadow
shadow

Reputation: 22333

Your plotting function has a few problems. First you need to initialize P as a list. Second, you need to use aes_string instead of aes, if you want to use the character input var. And then you have to use list(p), to keep the ggplot object intact.

plotting <- function(d){
  P <- list()
  vars <- names(d)[!names(d)%in%c('channel','label')]
  for (var in vars){
    p <- ggplot(d, aes_string(x='channel', y=var)) + 
      geom_boxplot(aes(fill=label)) + ggtitle(var)
    P <- c(P, list(p))
  }
  return(list(plots=P, num=length(vars)))
}

PLOTS <- plotting(d)
do.call(grid.arrange, c(PLOTS$plots, nrow = PLOTS$num))

Upvotes: 7

Related Questions