Home > Software design >  storing ggplot graphs from if/if else loops in a list, and using ggarrange
storing ggplot graphs from if/if else loops in a list, and using ggarrange

Time:01-06

Explanation of the problem

I have extensive if, else if, loops that produce graphs in ggplot2. Each graph gets stored with a unique object name, with the following pattern:

    graph_log_bar_blue <- 
    graph_log_violin_blue <-
    graph_log_bar_red <-
    graph_log_violin_red <-
    graph_log_bar_green <-
    graph_log_violin_green <-

etc...

I wish to store the graphs that are created (the ones that satisfy the loop conditions), in a list, so that I can arrange them with either ggarrange (in ggpubr) or with gridExtra.

graph_list <- ls(pattern = "graph_") #list names of graphs (but doesn't store the graph in the list)

library("ggpubr")
ggarrange(graph_list,
          nrow = 1, ncol = 3)

# OR

library("gridExtra")                                              # Load gridExtra 
do.call("grid.arrange", c(plot_list, ncol = 3)) 

Question

How do I:

  1. Create a list of graphs produced by ggplot (is this possible?)
  2. How can I select/make a list of graphs produced inside an if/else loop?
  3. How do I call graphs produced to then arrange them as a panel figure using ggarrange etc (ggpubr package)?

DATA

using the iris data set. The if loops do not make logical sense, it is just a mock of the structure of loop I am using, take it with a grain of salt :/

library(ggplot2)
iris <- iris
#Dataset 1
kt <- kruskal.test(Petal.Width ~ Species, data = iris)
kt$p.value
if(kt$p.value > 0.05){
  pt <- pairwise.wilcox.test(iris$Petal.Width, g=iris$Species, p.adjust.method = "BH")
}else if(kt$p.value < 0.05){
  graph_log_bar_blue <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species))  
    stat_summary(fun = median, show.legend = FALSE, geom="crossbar")  
    geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5)  
    labs(x=NULL, y= "Petal Width (cm)")
}else{
  graph_log_violin_blue <- ggplot(data = iris, aes(y=Petal.Width, x=Species, fill = Species))  
    geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6)  
                  labs(x=NULL,
                       y= "Petal Width (cm)")
}


#dataset 2
kt_sep <- kruskal.test(Sepal.Width ~ Species, data = iris)
kt_sep$p.value
if(kt_sep$p.value > 0.05){
  pt_sep <- pairwise.wilcox.test(iris$Sepal.Width, g=iris$Species, p.adjust.method = "BH")
}else if(kt_sep$p.value > 0.05){
  graph_log_bar_red <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species))  
    stat_summary(fun = median, show.legend = FALSE, geom="crossbar")  
    geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5)  
    labs(x=NULL, y= "Sepal Width (cm)")
}else{
  graph_log_violin_red <- ggplot(data = iris, aes(y=Sepal.Width, x=Species, fill = Species))  
    geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6)  
    labs(x=NULL,
         y= "Sepal Width (cm)")
}

graph_list <- ls(pattern="graph_")

Where do I go from here to arrange both graphs together!

CodePudding user response:

You could create your plot_list using e.g.

plot_list <- lapply(grep("^graph_", ls(), value = TRUE), get)

Afterwards you could pass the list to the plotlist argument of ggpubr::ggarrange, i.e.

ggpubr::ggarrange(plotlist = plot_list)

A minimal reprex of this approach using some fake plots:

library(ggplot2)
library(ggpubr)

graph_log_bar_blue <- ggplot()
graph_log_violin_blue <- ggplot()

plot_list <- lapply(grep("^graph_", ls(), value = TRUE), get)

ggpubr::ggarrange(plotlist = plot_list)

However, instead of storing your graphs as single objects I would suggest to create a list of plots from start. Additionally, instead of using copy and paste to create your charts it might be worthwhile to write a small custom function to perform your tests and create the charts. Such an approach may look like so:

library(ggplot2)
library(ggpubr)

plot_fun <- function(.data, x, y, ylab) {
  kt <- kruskal.test(.data[[y]] ~ .data[[x]])
  
  if (kt$p.value > 0.05) {
    pt <- pairwise.wilcox.test(.data[[y]], g = .data[[x]], p.adjust.method = "BH")
    plot <- NULL
  } else {
    pt <- NULL
    base <- ggplot(.data, aes(.data[[x]], .data[[y]], fill = .data[[x]]))  
      labs(x = NULL, y = ylab)
    
    plot <- if (kt$p.value < 0.05) {
      base     
        stat_summary(fun = median, show.legend = FALSE, geom="crossbar")  
        geom_jitter(show.legend = FALSE, width = 0.25, shape = 21, colour = "black", size = 2.5)
    } else {
      base   
        geom_violin(show.legend = FALSE, trim = FALSE, adjust = 0.6)
    }
  }
  
  # Return test results and plot as list
  list(kt = kt, pt = pt, plot = plot)
}

p_list <- list(
  plot_fun(iris, "Species", "Petal.Width", "Petal Width (cm)"),
  plot_fun(iris, "Species", "Sepal.Width", "Sepal Width (cm)")
)

# Get the plots
plots <- lapply(p_list, function(x) x[["plot"]])

ggpubr::ggarrange(plotlist = plots)

  • Related