Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R - Change list of ggplot objects into a list of grobs that grid.arrange will accept?

Tags:

r

ggplot2

I'm iterating through some data creating lists of ggplot graphics that I want to print together on a single image. My code has two loops, one inside the other. The outer loop subdivides the data based on one variable. The inner loop subdivides the data further and produces a scatterplot for each subdivision; the plots are saved in a list. Once the inner loop has completed, a grid.arrange object is created using list objects like this (NOTE: This code includes a custom function, my_scatter that is shared at the bottom of this question):

require(ggplot2)
require(grid)
require(gridExtra)
PRIMARY LOOP STRUCTURE {
    ...
    my_plots = list()
      for (j in c(1:length(my_nodes))){
        cur_node = my_nodes[j]
        node_dat = temp_dat[temp_dat$Node == cur_node,]
        p = my_scatter(node_dat, "PRE", "POST") + geom_point(aes(color = Node, shape = Recurrence_Type, size = 2))
        my_plots[[j]] = p
      }         
    grid.arrange(my_plots[[1]],my_plots[[2]],my_plots[[3]],my_plots[[4]],my_plots[[5]], nrow = 4, ncol = 3)
}

The problem is that for some iterations of the loop, my_plots will have a different number of elements. I know that I could solve this problem with a series of conditional statements:

if (length(my_plots) == 2) {
    grid.arrange(my_plots[[1]],my_plots[[2]],nrow=1,ncol=2)
} elsif ( length(my_plots == 3) {
    grid.arrange(my_plots[[1]],my_plots[[2]],nrow=2,ncol=2)
} elsif...

But this seems cumbersome and I am hoping to find a less blunt solution. Ordinarily I would use facet_grid() for this kind of thing but the scatter plots are difficult to interpret when they are distorted into the ultra thin rectangles facet_grid produces when it has more than 2 or 3 plots to produce.

I see that this question seems to solve the problem using grobs and lapply - which are two aspects of R programming I've never had much success with in the past.

How can I either:

  • change my list of ggplot objects into a list of grobs that grid.arrange will accept?
  • tell facet_grid (or similar existing function) that I want more than one row of plots so that they are close to square-shaped?

Here's the function my_scatter used in the first code block:

my_scatter = function (df,a,b) {
  test1 = class(df)
  if (! test1 == "data.frame") { 
    stop("1st Variable should be a data frame")
  }
  test2 = class(df[,a])
  valid_classes = c("integer", "numeric")
  if (! test2 %in% valid_classes) {
    stop("2nd Variable should either be an integer or numeric")
  }
  test3 = class(df[,b])
  if (! test3 %in% valid_classes) {
    stop("3rd Variable should either have class numeric or integer")
  }
  p = ggplot(data = df, aes_string(a, b)) + xlim(0,1) + ylim(0,1) + geom_point() + geom_abline(slope = 1, intercept = 0, color = "white")
  return(p)
} 
like image 449
Slavatron Avatar asked Dec 15 '22 06:12

Slavatron


1 Answers

grid.arrange(grobs = my_plots)

should do the trick. You don't need to convert the plots to grobs, grid.arrange does it for you. But if you had to, you could do:

my_grobs = lapply(my_plots, ggplotGrob)
like image 139
baptiste Avatar answered Dec 16 '22 19:12

baptiste