4

I have a ggplot2 with a 4 x 3 panel structure. Each column of panels shares the same x-axis text and title. I want all panels to be the same size, but when I add the x-axis title and text to the bottom row, it causes the panels to resize. How can I ensure equal sized panels? A reproducible example is given below:

library(ggmap)
library(maps)
library(ggplot2)

BII.TEMP.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "Temp"=c(8,7,8,9))
BII.PPT.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "PPT"=c(8,7,8,9))
SCAN.TEMP.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "Temp"=c(8,7,8,9))
SCAN.PPT.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "PPT"=c(8,7,8,9))
CE.TEMP.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "Temp"=c(8,7,8,9))
CE.PPT.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "PPT"=c(8,7,8,9))
TEMP.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "Temp"=c(8,7,8,9))
PPT.SUMMER=data.frame("Year"=c(1851, 1901, 1951, 2001), "PPT"=c(8,7,8,9))



BII.coords=data.frame(lon=c(-6.9532,-7.9925,-2.5036,-8.2569,-6.5487,-7.4083,-2.0369,-2.175,-6.1921), 
                          lat=c(53.3653,53.0807,55.0875,53.1865,54.8862,53.7667,54.4253,54.0964,55.0848))

CE.coords=data.frame(lon=c(16.5872,13.8494,6.2317,21.2201,15.3602,17.9821,18.3098,
                           9.8544,22.4419,6.1736,16.4785,18.0833,24.545), 
                     lat=c(53.8078,53.0558,46.5397,53.8726,50.8519,53.5918,53.188,
                           46.49,54.3314,46.5667,54.3619,54.4244,47.5739))

SCAN.coords=data.frame(lon=c(17.3667,18.6833,18.4333,22.7833,19.5828,10.1896,26.25,19.0484), 
                       lat=c(60.0167,59.9667,59.6333,60.7833,64.1647,56.8391,58.8667,68.3568))

BII.MAP=data.frame(xmin=-10.31, xmax=-0.93, ymin=51.44, ymax=55.22)
thismap=map_data("world")
P1=ggplot()+geom_polygon(data=thismap, aes(x=long, y=lat, group=group), color="lightgray", fill="white")+
  coord_fixed(xlim=c(-11, 30), ylim=c(40, 70), ratio=1.0)+
  geom_rect(data=BII.MAP, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax),
            inherit.aes=FALSE, colour="black", alpha=0.1)+
  geom_point(data=BII.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=0)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="black", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  ggtitle("Britain & Ireland")

SCAN.MAP=data.frame(xmin=8.44, xmax=27.19, ymin=55.25, ymax=68.56)
thismap=map_data("world")
P4=ggplot()+geom_polygon(data=thismap, aes(x=long, y=lat, group=group), color="lightgray", fill="white")+
  coord_fixed(xlim=c(-11, 30), ylim=c(40, 70), ratio=1.0)+
  geom_point(data=SCAN.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=1)+
  geom_rect(data=SCAN.MAP, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax),
            inherit.aes=FALSE, colour="black", alpha=0.1)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="black", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  ggtitle("Scandinavia")

CE.MAP=data.frame(xmin=4.69, xmax=25.32, ymin=45.73, ymax=55.22)
thismap=map_data("world")
P7=ggplot()+geom_polygon(data=thismap, aes(x=long, y=lat, group=group), color="lightgray", fill="white")+
  coord_fixed(xlim=c(-11, 30), ylim=c(40, 70), ratio=1.0)+
  geom_point(data=CE.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=2)+
  geom_rect(data=CE.MAP, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax),
            inherit.aes=FALSE, colour="black", alpha=0.1)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="black", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  ggtitle("Continental Europe")

MAP=data.frame(xmin=-10.31, xmax=27.19, ymin=45.73, ymax=68.56)
thismap=map_data("world")
P10=ggplot()+geom_polygon(data=thismap, aes(x=long, y=lat, group=group), color="lightgray", fill="white")+
  coord_fixed(xlim=c(-11, 30), ylim=c(40, 70), ratio=1.0)+
  geom_point(data=BII.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=0)+
  geom_point(data=SCAN.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=1)+
  geom_point(data=CE.coords, aes(lon, lat), inherit.aes=FALSE, color="black", size=2, shape=2)+
  geom_rect(data=MAP, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax),
            inherit.aes=FALSE, colour="black", alpha=0.1)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="black", size=10, face="bold"), 
        axis.ticks.length=unit(0.2, "cm"))+
  ggtitle("All Sites")

P2=ggplot(BII.TEMP.SUMMER, aes(Year,Temp))+
  geom_line(color="gray75")+ylim(12.9,16.6)+geom_smooth(color="red", se=FALSE)+ggtitle("Temperatures (°C)")+
  geom_vline(xintercept=1914, col="purple4", linetype=2)+annotate("text", x=1916, y=12.9, label="Dry Shift", col="purple4")+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="red", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=16.6)

P3=ggplot(BII.PPT.SUMMER, aes(Year,PPT))+
  geom_line(color="gray75")+ylim(88,428)+geom_smooth(color="blue", se=FALSE)+ggtitle("Precipitation (mm)")+
  geom_vline(xintercept=1914, col="purple4", linetype=2)+annotate("text", x=1916, y=88, label="Dry Shift", col="purple4")+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="blue", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=428)

P5=ggplot(SCAN.TEMP.SUMMER, aes(Year,Temp))+
  geom_line(color="gray75")+ylim(11.2,16.2)+geom_smooth(color="red", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=16.2)+
  ggtitle("BLANK")

P6=ggplot(SCAN.PPT.SUMMER, aes(Year,PPT))+
  geom_line(color="gray75")+ylim(144,359)+geom_smooth(color="blue", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=359)+
  ggtitle("BLANK")

P8=ggplot(CE.TEMP.SUMMER, aes(Year,Temp))+
  geom_line(color="gray75")+ylim(16.4,21.3)+geom_smooth(color="red", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=21.3)+
  ggtitle("BLANK")

P9=ggplot(CE.PPT.SUMMER, aes(Year,PPT))+
  geom_line(color="gray75")+ylim(144, 387)+geom_smooth(color="blue", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.text.x=element_blank(), axis.title.x=element_blank(), axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=387)+
  ggtitle("BLANK")

P11=ggplot(TEMP.SUMMER, aes(Year,Temp))+
  geom_line(color="gray75")+ylim(13.9,17.6)+geom_smooth(color="red", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=17.6)+
  ggtitle("BLANK")

P12=ggplot(PPT.SUMMER, aes(Year,PPT))+
  geom_line(color="gray75")+ylim(139,328)+geom_smooth(color="blue", se=FALSE)+
  theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), plot.title=element_text(color="white", size=10, face="bold"), 
        axis.title.y=element_blank(), axis.ticks.length=unit(0.2, "cm"))+
  annotate("text", x=1935, y=328)+
  ggtitle("BLANK")

plots <- list(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)
grobs <- list()
widths <- list()

#collect the widths for each grob of each plot
for (i in 1:length(plots)){
  grobs[[i]] <- ggplotGrob(plots[[i]])
  widths[[i]] <- grobs[[i]]$widths[2:5]
}

#use do.call to get the max width
maxwidth <- do.call(grid::unit.pmax, widths)

#asign the max width to each grob
for (i in 1:length(grobs)){
  grobs[[i]]$widths[2:5] <- as.list(maxwidth)
}

# plot
#do.call("grid.arrange", c(grobs, ncol = 1))
do.call("grid.arrange", c(grobs, nrow = 4))
DJ-AFC
  • 569
  • 6
  • 16
  • 8
    It would help to have a working sample so that we can help you better. Please refer to [this link](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) for instructions on how to post a replicable example. – automa7 Oct 17 '18 at 16:36
  • 1
    The example seems not to be reproducible, executing P2 : `Error: geom_text requires the following missing aesthetics: label`, same with P3, 5, 6, 8, 9, 11, 12. – bVa Oct 18 '18 at 15:55
  • 1
    Your example graphs P2, P3, P5, P6, P8, P9, P11 and P12 are still not working. Consider please updating your question to correct that. It would be reasonable to substitute the similarly named plots @bVa has crafted if your are still having trouble. Also, your very first attempt using: `library(gridExtra)` and `grid.arrange(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, nrow=4)` was very good as (with working graphs) it highlights the problem of inconsistent scaling very well i.e. when the last row of plots has x-axis text and the other rows do not. You might consider putting that back. – krads Oct 23 '18 at 09:33

2 Answers2

4

Another solution is to use the patchwork package (thomasp85/patchwork, from github), you can not do easier.

I could not plot figures P2, P3, P5, P6, P8, P9, P11 and P12, so I created mock data.

# mock data 
library(tidyverse)
data <- lapply(c(2,3,5,6,8,9,11,12), function(k) {
  data.frame(x = seq(1, 100, 1),
             y = runif(100, 0, 50),
             label = k) %>%
    ggplot(., aes(x, y)) +
    geom_point() +
    geom_smooth(method = "lm", se = FALSE) +
    ggtitle(k) +
    theme(axis.ticks.length = unit(0.2, "cm"))
})

p2 <- data[[1]] +
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank())

p3 <- data[[2]] +
  theme(axis.title = element_blank(),
        axis.text.x = element_blank())

p5 <- data[[3]] +
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank())

p6 <- data[[4]] +
  theme(axis.title = element_blank(),
        axis.text.x = element_blank())

p8 <- data[[5]] +
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank())

p9 <- data[[6]] +
  theme(axis.title = element_blank(),
        axis.text.x = element_blank())


p11 <- data[[7]] 

p12 <- data[[8]] +
  theme(axis.title.y = element_blank())

Here is the code for the plot :

devtools::install_github("thomasp85/patchwork")
library(patchwork)
# PLOT
P1 + p2 + p3 + 
  P4 + p5 + p6 + 
  P7 + p8 + p9 + 
  P10 + p11 + p12 + 
  plot_layout(ncol = 3)

plot

bVa
  • 3,839
  • 1
  • 13
  • 22
1

This elegant and clear answer from @slizb does nearly exactly what you want: https://stackoverflow.com/a/19321139/10312356

Only difference is the solution @slizb shows in that example is for a single column grid layout whereas you would like a 4 row by 3 column layout.

All credit to @slizb as below I've only added your data and changed ncol=1 to nrow=4 in the final line.

If this solves your problem please upvote @slizb in the other question rather than upvoting this answer as I cannot claim credit for such a trivial edit.

plots <- list(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)
grobs <- list()
widths <- list()

#collect the widths for each grob of each plot

for (i in 1:length(plots)){
  grobs[[i]] <- ggplotGrob(plots[[i]])
  widths[[i]] <- grobs[[i]]$widths[2:5]
}

#use do.call to get the max width

maxwidth <- do.call(grid::unit.pmax, widths)

#asign the max width to each grob

for (i in 1:length(grobs)){
  grobs[[i]]$widths[2:5] <- as.list(maxwidth)
}

# plot

#do.call("grid.arrange", c(grobs, ncol = 1))
do.call("grid.arrange", c(grobs, nrow = 4))

enter image description here

krads
  • 1,350
  • 8
  • 14
  • Thank you @krads for directing me to this solution and for your edits. This works for the example I provided, but not for the more complex example that I actually need this done for. I've amended my post to include the real data I'm working with. You'll see that grobs will not work for these plots. – DJ-AFC Oct 18 '18 at 14:23
  • BTW, the "...SUM_DIFF" and "...SUM.PERCENT" fields in some of the titles are not provided. Can you either add those to your example, remove, or replace? Otherwise it errors out and is not reproducible. – Jon Spring Oct 18 '18 at 14:46
  • Sorry - I've now removed this – DJ-AFC Oct 18 '18 at 14:50