Search code examples
rggplot2gridextraannotatecowplot

Modify space after adding annotate for multiplot panels


I have a multiplot panel with annotations (outside the plots) that I would like to modify.

This is the plot: enter image description here

How can I:

  1. move the titles (I. and II.) over to the far left?
  2. change the amount of white space around the titles?
  3. change the amount of white space around the plots?

(ggplot() solution preferred)

This is the code (adapted from OP) to get the above plot (removed unneeded code for theme, etc.):

    panelA <- data.frame(
        Stage = c("Juvenile", "Juvenile", "Yearling", "Juvenile", "Juvenile", "Yearling","Juvenile", "Juvenile", "Yearling","Juvenile", "Juvenile", "Yearling"),
        Individual = c ("A", "A", "A","B", "B", "B","C", "C", "C","D", "D", "D"),
        Score = c(  1.4, 1.2, NA,0.4, 0.6, 0.5,-0.3, -0.5, -0.4,-1.4, -1.2, NA))

    A<-ggplot(panelA, aes(x = Stage, y = Score, color =Individual, group= Individual)) + 
      geom_point() + 
     geom_line()+
      geom_smooth(method=lm, se=F, fullrange=TRUE)

    panelB <- data.frame(
        Stage = c("Juvenile", "Juvenile", "Yearling", "Juvenile", "Juvenile", "Yearling","Juvenile", "Juvenile", "Yearling", "Juvenile", "Juvenile", "Yearling"),
        Individual = c ("A", "A", "A","B", "B", "B","C", "C", "C","D", "D", "D"),
        Score = c(  1.4, 1.2, 1.3,0.4, 0.6, NA,-0.3, -0.5, NA,-1.4, -1.2, -1.3))

    B<-ggplot(panelB, aes(x = Stage, y = Score, color =Individual, group= Individual)) + 
      geom_point() +
      geom_line()+
       geom_smooth(method=lm, se=F, fullrange=TRUE)

    library(ggplot2)
    library(gridExtra)
    library(RGraphics)
    library(cowplot)

    grid.newpage()
    # Create layout : nrow = 4, ncol = 2
    pushViewport(viewport(layout = grid.layout(4, 2)))
    # A helper function to define a region on the layout
    define_region <- function(row, col){
      viewport(layout.pos.row = row, layout.pos.col = col)
    } 

#text I want to annotate
    t1 <- ggdraw() + draw_label("I. Effects on variance components", fontface='bold')
    t2 <- ggdraw() + draw_label("II. Effects on means (mediated via plasticity)", fontface='bold')

    # Arrange the plots

    print(t1, vp=define_region(1, 1))
    print(A, vp = define_region(2, 1))
    print(B, vp=define_region(2, 2))
    print(t2, vp = define_region(3, 1))
    print(A, vp=define_region(4, 1))
    print(B, vp = define_region(4, 2))

Solution

  • So here would be an semi-pure ggplot solution for your problem, without the need of these extra packages, except for one that ggplot already depends on (and another one ggplot already depends on for annotations).

    To reduce space between your two panels horizontally, you could use facets instead of copy-pasting entire plots, including superfluous axes, whitespace and whatnot:

    AB <- ggplot(mapping = aes(Stage, Score, colour = Individual, group = Individual)) +
      geom_point(data = cbind(panelA, panel = "A")) +
      geom_point(data = cbind(panelB, panel = "B")) +
      geom_line(data = cbind(panelA, panel = "A")) +
      geom_line(data = cbind(panelB, panel = "B")) +
      facet_wrap(~ panel, ncol = 2)
    

    Now to reduce the space within a panel, from points to edge, you can tweak the expand argument in some scales. Set the 0.1 value smaller or larger as you please:

    AB <- AB + scale_x_discrete(expand = c(0,0.1))
    

    In a real case scenario, you probably wouldn't need the same plot twice, but as you're giving an example wherein you plot the same plots vertically, I'll follow that lead. So now we combine the plots:

    top <- AB + ggtitle("I. Effects on variance components")
    bottom <- AB + ggtitle("II. Effects on means (mediated via plasticity)")
    combined <- rbind(ggplotGrob(top), ggplotGrob(bottom), size = "first")
    

    But since we've converted our plots to gtables through ggplotGrob(), we now need grid syntax to draw the plots:

    grid::grid.newpage(); grid::grid.draw(combined)
    

    Which looks like the following:

    enter image description here

    I got a few warnings due to NAs in the data.frames, but otherwise that generally shouldn't happen. If you don't like the strips (panel title like things in darker gray box), you can simple adjust the theme: + theme(strip.background = element_blank(), strip.text = element_blank()) in your plotting code.

    You can add custom annotations as follows:

    combined <- gtable::gtable_add_grob(
      combined,
      grid::textGrob("Here be some annotation", x = 1, hjust = 1),
      t = 16, l = 9 # top/left positions of where to insert this
    )
    grid::grid.newpage(); grid::grid.draw(combined)
    

    enter image description here

    Note however that rbind()ing together plotgrobs requires them to have an equal number of columns, so you can't omit the legend/guide in one plot and not the other. You can remove one of them within the gtable though.