The answer from @baptiste helped me get a better understanding of the gtable structure and how to modify it. Below I post just my modified variant as code snippet for (my own) reuse.
It is using find_panel()
to get the panel extent, and pipes %>%
the modifications directly into grid.draw
. The piping considerably simplified playing around with the gtable_*
functions, as it allows to easily uncomment single lines and check the effect on the final plot.
library(ggplot2)
library(grid)
library(gtable)
library(dplyr)
p <- ggplot(tribble(~x,~y,~a,~b,
1, 1, "a1","b1",
1, 1, "a2","b1",
1, 1, "a2","b2"),
aes(x=x,y=y)) +
geom_point() +
facet_grid(vars(a),vars(b))
g <- ggplotGrob(p)
panels_extent <- g %>% find_panel()
g %>%
# Add red box to the very right, by appending a column and then filling it
gtable_add_cols(widths = unit(1,"cm"), pos = -1) %>%
gtable_add_grob(rectGrob(gp=gpar(fill="red")),
t = panels_extent$t, b = panels_extent$b,
l = -1, r = -1) %>%
# Add green box to the top, by prepending a row and then filling it
# Note the green box extends horizontally over the first panel as well
# as the space in between.
gtable_add_rows(heights = unit(1,"cm"), pos = 0) %>%
gtable_add_grob(rectGrob(gp=gpar(fill="green")),
t = 1, b = 1,
l = panels_extent$l, r = panels_extent$l+1) %>%
{grid.newpage();grid.draw(.)}
gtable
, in my opinion, and from there you'll be able to append new grobs, new viewports, etc. to the not-so-basic gtable returned by ggplot. – Creon