0

Basically, I want to add a title and subtitle to a grid.arrange() plot.

I have plot_list which is a list of 15 ggplots and

tg <- textGrob('Title', gp = gpar(fontsize = 13, fontface = 'bold'))
sg <- textGrob('Subtitle', gp = gpar(fontsize = 10))

But this doesn't work. I don't get any errors but tg and sg don't show up in the plot.

grid.arrange(tg, sg, grobs = plot_list, ncol = 3)

To be honest, I'm no expert in gridExtra and grid so any advice will be appreciated

piblo95
  • 123
  • 1
  • 2
  • 10
  • Depending on the details of your problem, `facet_wrap` might be a better solution to making multiple plots – Richard Telford Nov 30 '19 at 12:12
  • Hi Richard! Thank for your response. In fact, I'm using facet_wrap to plot the 15 graphs. My problem was that I wanted each graph to have its own gradient color scale (https://stackoverflow.com/questions/59108493/independent-color-gradient-for-each-facet-in-facet-wrap-ggplot2), not share with the rest (something like the option "free_y" for axis) but apparently there is no way to do it so I was forced to built each plot individually (using lapply), inserting them into a list and plotting them with grid.arrange, which I am no expert with. – piblo95 Dec 02 '19 at 19:33

3 Answers3

4

Following changing multiple line title in multiplot ggplot2 using grid.arrange I could do what you asked for by creating two grids, first with only the plots and second with title, subtitle and the first grid. Using a synthetic plot_list:

df <- data.frame(v1 = rnorm(1000))
plot_list <- list()
for (i in 1:15) {
  df[,ncol(df)+1] <- rnorm(1000)
  names(df)[ncol(df)] <- paste0("V_",as.character(i))
  local({
    i <- i
    plot_list[[i]] <<- ggplot(df) + geom_point(aes_string(x = "v1", y = paste0("V_",as.character(i))))
  })
}
tg <- textGrob('Title', gp = gpar(fontsize = 13, fontface = 'bold'))
sg <- textGrob('Subtitle', gp = gpar(fontsize = 10))
margin <- unit(0.5, "line")
grided <- gridExtra::grid.arrange(grobs = plot_list, ncol = 3)
gridExtra::grid.arrange(tg, sg, grided,
                        heights = unit.c(grobHeight(tg) + 1.2*margin, 
                                         grobHeight(sg) + margin, 
                                         unit(1,"null")))

grids

Hope this helps!

JaiPizGon
  • 476
  • 2
  • 8
  • 2
    if you use `arrangeGrob` instead og `grid.arrange` at the line `grided <- gridExtra::grid.arrange ...` you wont draw the plot at that stage – user20650 Nov 30 '19 at 13:44
  • Thanks!! I had already seen the link you provided, but wasn't able to replicate it. Didn't know how to insert my ```plot_list``` within the ```grid.arrange``` function, I was missing previous step ```arrangeGrob``` – piblo95 Dec 02 '19 at 19:37
3

You need to combine tg, sg and your plots into a list. I would specify a layout matrix, which gives you a bit more control, and plot using grid.arrange:

First, we have tg,sg and I make a plot_list of 3 with mtcars.

library(ggplot2)
library(gridExtra)
library(grid)

tg <- textGrob('Title', gp = gpar(fontsize = 13, fontface = 'bold'))
sg <- textGrob('Subtitle', gp = gpar(fontsize = 10))

plot_list <- lapply(c("drat","wt","qsec"),function(i){
  ggplot(mtcars,aes_string("mpg",i))+geom_point()
})

We combine your plots in a list:

g = c(list(tg),list(sg),plot_list)

So now tg is 1st element, sg is 2nd element and your plots are 3-5. We specify the layout:

N = length(plot_list)
laym = rbind(rep(1,N),rep(2,N),(3:(N+2)))
laym
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    4    5

This matrix will have the first one (tg), 1 takes up first row, sg 2nd row and your plots third row. If you have other kinds of arrangements or list, you can change this accordingly.

Now we plot, and specify the relative heights using heights=...

grid.arrange(grobs=g,layout_matrix=laym,heights=c(1,1,10))

enter image description here

StupidWolf
  • 45,075
  • 17
  • 40
  • 72
1

the top argument can take any grob but it needs to know its height to be given the right space,

library(grid)
library(gridExtra)

lg <- replicate(12, ggplot2::ggplot(), simplify = FALSE)
tg <- textGrob('Title', gp = gpar(fontsize = 50, fontface = 'bold'))
sg <- textGrob('Subtitle', gp = gpar(fontsize = 10))

lt <- list(tg, sg)
heights <- do.call(unit.c, lapply(lt, function(.g) 1.5*grobHeight(.g)))
titles <- gtable::gtable_matrix('title', 
                                grobs = matrix(lt, ncol=1), 
                                widths = unit(1,'npc'),
                                heights = heights)

grobHeight.gtable <- function(g) sum(g$heights)

grid.arrange(grobs = lg, top = titles)