4

First, some mock graphs:

df <- data.frame(x = 1:10, y = 2:11)

Because my real graphs are fairly complicated, I'm going not going to provide them here, but will use other graphs that reproduce the problem. Suffice it to say that when align is set to "hv" in plot_grid, it creates a lot of white space between my graphs. To fix that, I set the margins in the original plots like so:

library(ggplot2)

plot1 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(-1, 0, 0, 0), "cm"))
plot2 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(-1, 0, 0, 0), "cm"))
plot3 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(-1, 0, 0, 0), "cm"))
plot4 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(-1, 0, 0, 0), "cm"))

Which extended the tops of the plots so they fill the white space. All fine and dandy (in this example, there may be a little overlap between the top and bottom):

library(cowplot)

plot5 <- plot_grid(plot1, plot2, plot3, plot4, nrow = 2, ncol = 2, 
                   align = "hv")
plot5

Until I tried to add labels. Because I had extended the plots, I wanted to add the labels higher than the y = 1 limit.

plot5 <- plot_grid(plot1, plot2, plot3, plot4, nrow = 2, ncol = 2, 
                   align = "hv", labels = c("A", "B", "C", "D"), 
                 label_x = 0.1,
                 label_y = 1.15)+
  theme(plot.margin = unit(c(3, 1, 1, 1), "cm"))
plot5

Returns this warning:

Removed 1 rows containing missing values (geom_text).  

enter image description here

Meaning it took off the two top labels, even though there appears to be sufficient space. So, I thought, perhaps the plot margins aren't being applied until after the labels are plotted, or perhaps clipping was causing a problem. So, I did this:

plot5 <- plot_grid(plot1, plot2, plot3, plot4, nrow = 2, ncol = 2, 
                   align = "hv") + 
  theme(plot.margin = unit(c(3, 0, 0, 0), "cm")) +
  coord_cartesian(clip = "off")

plot5 + 
  draw_plot_label(c("A", "B", "C", "D"), c(0, 0.5, 0, 0.5), c(1.1, 1.1, .5, .5))   

enter image description here Which returns the same error as before, although, as you can see, there is more space availiable at the top of the plot. As a last resort, I also turned off the clipping in the original plots, but that didn't fix anything either, eg:

plot1 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(-1, 0, 0, 0), "cm")) + 
  coord_cartesian(clip = "off")

The problem only occurs when I plot past y = 1. y = 1.01 causes problems, for instance. How do I fix this problem? It seems like a rather simple issue, unless there's a problem with ggplot or cowplot.

Grubbmeister
  • 857
  • 8
  • 25
  • 1
    Not an answer - I recently had the problem of lots of white space around single plots using `plot_grid`, using library `egg` instead of `cowplot` solved the problem without having to adjust margins etc. – erc Jan 24 '19 at 09:44
  • 1
    Thanks for the tip! Will check it out. – Grubbmeister Jan 24 '19 at 09:46
  • I'm not clear exactly where you want the labels to be. y = 1 is by definition the top of the plot area for that plot, and anything above 1 will be outside the plot area. If you look at the code for `cowplot::plot_grid`, it calls `cowplot::ggdraw` with its default limits of `c(0, 1)` for both x and y to create its plot, and that in turn uses `scale_x_continuous` and `scale_y_continuous` with those limits. Labels are plotted using those limits, so by standard ggplot rules, anything outside will be removed. – Nick Kennedy Feb 11 '19 at 23:53
  • The problem I had was whitespace - too much between the plots. So I extended the plots. This fixed the whitespace in the middle of the grid, but pushed the top plots to the boundary of `y=1`. So, when I plotted the labels, they were on top of the plots. I therefore had to plot past `y=1`, which isn't possible, even if you add extra margins around the entire grid. – Grubbmeister Feb 12 '19 at 00:02

2 Answers2

1

By following the suggestion to use the 'egg' package, I fixed the problem: remove whitespace between graphs and have plots labelled in a sensible way.

Also, it's worth noting that egg seems faster than cowplot in drawing plots.

install.packages("egg")
library(egg)

df <- data.frame(x = 1:10, y = 2:11)

plot1 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
plot2 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
plot3 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
plot4 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))

figure <- egg::ggarrange(plot1, plot2, 
         plot3, plot4, 
             nrow = 2,ncol=2,
             labels=c("A", "B", "C","D"),
             label.args = list(gp=gpar(font=2), x=unit(.5,"line")))
figure

enter image description here

Grubbmeister
  • 857
  • 8
  • 25
0

Ok, so I have an answer, which fixes the matter of labels, but it doesn't solve the problem of not being able to plot past y=1. Instead of reducing the top margins in the original plots, I reduced the bottom margins:

plot1 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(1, 0, -1, 0), "cm"))
plot2 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(1, 0, -1, 0), "cm"))
plot3 <- ggplot(df, aes(x = x, y = y)) +
  geom_point() + 
  theme(plot.margin = unit(c(1, 0, -1, 0), "cm"))
plot4 <- ggplot(df, aes(x = y, y = -x)) +
  geom_point() + 
  theme(plot.margin = unit(c(1, 0, -1, 0), "cm"))

plot5 <- plot_grid(plot1, plot2, plot3, plot4, nrow = 2, ncol = 2, 
                   align = "hv", labels = c("A", "B", "C", "D"), 
                   label_x = 0.1,
                   label_y = 1) +
  theme(plot.margin = unit(c(1, 1, 2, 1), "cm"))
plot5

Which lets me plot the labels in a sensible spot. enter image description here

It still makes zero sense to me, though, why the labels are clipped (and it also appears to happen when y<0).

Grubbmeister
  • 857
  • 8
  • 25