1

I've got a function that produces a plot, which I run six times. I want to extract each plot, then draw one multi-panel plot with each plot and only one legend.

I've tried using the assign function, along with return, to extract my plots, but I can't seem to get it to work.

My code:

levels = c('Genus','Family','Order','Class','Phylum','Domain')

Taxon_senPrec_func = function(x){
  df = subset(d, Taxonomic_level == x)

  q=ggplot(df, aes(x=Sensitivity, y=Precision, col=Database, shape=ID_cutoff)) +
    geom_point(size=3) +
    ggtitle(
      paste('The ',x,' sensitivity and precision of various annotation techniques.', 
            sep='')) +
    ylim(0,100) +
    xlab('Sensitivity (%)') +
    ylab('Precision (%)') +
    scale_shape_manual(values=1:9)

  p = assign(paste("plot_",x,sep=""), q)
  return(p)
}

for(level in levels){
  Taxon_senPrec_func(level)
}
zx8754
  • 52,746
  • 12
  • 114
  • 209
RB88
  • 157
  • 1
  • 3
  • 10
  • 3
    Why not use [facet_grid](http://docs.ggplot2.org/0.9.3.1/facet_grid.html)? – zx8754 Sep 02 '14 at 13:43
  • @zx8754 Before I can attempt methods such as facet_grid, I need to figure out how to extract the plots from my function, as I'm not drawing each plot separately with a unique variable name, rather I'm running a function to draw them. – RB88 Sep 02 '14 at 14:33

2 Answers2

3

To expand on facet_grid comment, we are trying to plot multiple plots based on subsets of one data.frame separately using custom function then trying to put them together into one plot, why not use facet_grid.

Example:

require(ggplot2)

#reproducible dummy data
set.seed(123)
df <- data.frame(Sensitivity=runif(600,1,100),
                 Precision=runif(600,1,100),
                 Database=sample(c("DB1","DB2","DB3"),600,replace = TRUE),
                 ID_cutoff=sample(LETTERS[1:4],600,replace = TRUE),
                 my_levels = c('Genus','Family','Order','Class','Phylum','Domain'))

#plot with facet
ggplot(df, aes(x=Sensitivity, y=Precision, col=Database, shape=ID_cutoff)) +
  geom_point(size=3) +
  facet_grid(.~my_levels) +
  ggtitle('The sensitivity and precision of various annotation techniques.') +
  ylim(0,100) +
  xlab('Sensitivity (%)') +
  ylab('Precision (%)') +
  scale_shape_manual(values=1:9)

Plot:

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209
2

One way is to use multiplot function (from here), like this:

multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
  require(grid)

  plots <- c(list(...), plotlist)

  numPlots = length(plots)

  if (is.null(layout)) {

    layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
                     ncol = cols, nrow = ceiling(numPlots/cols))
  }

  if (numPlots==1) {
    print(plots[[1]])

  } else {

    grid.newpage()
    pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))


    for (i in 1:numPlots) {
      matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))

      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                      layout.pos.col = matchidx$col))
    }
  }
}

and can use it like this:

library(ggplot2); 
library(grid)

q1<-ggplot(...) #your first graph
q2<-ggplot(...) # your second graph
...
q6<-ggplot(...) # 6-th graph

then call multiplot(q1,q2,q3,q4,q5,q6,cols=3). There are various alternative ways: see here which uses grid.arrange, and there is of course the facet-types that ship with ggplot: facet_grid (as Baptiste says) and facet_wrap, the latter of which can be used like this (random/dummy data):

times_<-c(0,cumsum(rexp(19,1)));

out.df<-matrix(c(sample(-10:10,20,TRUE),sample(-10:10,20,TRUE),sample(-10:10,20,TRUE),
sample(-10:10,20,TRUE),rep(times_,4),c(rep(1,20),rep(2,20),rep(3,20),rep(4,20))), ncol=3);

out.df<-as.data.frame(out.df); colnames(out.df)<-c("R","time","qq");

ggplot(out.df,aes(x=time, y=R) )+geom_line(colour='blue')+
facet_wrap(~ qq, ncol = 2, scales="free")

which gives this wonderful plot:

enter image description here

Community
  • 1
  • 1
Rusan Kax
  • 1,894
  • 2
  • 13
  • 17
  • 1
    This is good, but would be better if you could post equivalent code which uses `ggplot2` rather than `grid` graphics. – Carl Witthoft Sep 02 '14 at 13:58
  • Yes. `ggplot2` imports `grid`, does it not? Anyway, 9.5 out of 10 times I use `multiplot`, or `grid.arrange`. http://stackoverflow.com/questions/8899151/grid-layout-in-ggplot – Rusan Kax Sep 02 '14 at 14:45
  • @Rusan Kax Thanks. These are some good options to try, but I'm still stuck trying to extract my plots from my function. Each plot variable is simply 'q' in the function, so I don't (yet) have six individual variables to use with these methods. – RB88 Sep 02 '14 at 14:47
  • 1
    @RB88 yes,`facet_grid` as answer above. You function body *is* just the `ggplot` object. You just need to rearrange a little: see answer from *zx8754*... assuming you already have a data frame `d` do `ggplot(d, aes(x=Sensitivity, y=Precision, col=Database, shape=ID_cutoff))+geom_point(size=3)+ylim(0,100)+xlab('Sensitivity (%)')+ylab('Precision (%)')+facet_grid(.~Taxonomic_level)` – Rusan Kax Sep 02 '14 at 15:09
  • @zx8754, and Rusan Kax. I see! No need for the function at all. Thanks a lot for your help, I've got it working now. I've used facet_wrap rather than facet_grid as it displays better. – RB88 Sep 02 '14 at 16:10