I am trying to use grid.arrange to display multiple graphs on the same page generated by ggplot. The plots use the same x data but with different y variables. The plots come out with differing dimensions due to the y-data having different scales.
I have tried using various theme options within ggplot2 to change the plot size and move the y axis label but none have worked to align the plots. I want the plots arranged in a 2 x 2 square so that each plot is the same size and the x-axes align.
Here is some test data:
A <- c(1,5,6,7,9) B <- c(10,56,64,86,98) C <- c(2001,3333,5678,4345,5345) D <- c(13446,20336,24333,34345,42345) L <- c(20,34,45,55,67) M <- data.frame(L, A, B, C, D)
And the code that I am using to plot:
x1 <- ggplot(M, aes(L, A,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x2 <- ggplot(M, aes(L, B,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x3 <- ggplot(M, aes(L, C,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x4 <- ggplot(M, aes(L, D,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') grid.arrange(x1,x2,x3,x4,nrow=2)
If you run this code, you will see that the bottom two plots have a smaller plot area due to the greater length of the y-axes units.
How do I make the actual plot windows the same?
Edit
Simpler solutions are: 1) use the cowplot
package (see answer here); or 2) use egg
package available on github.
# devtools::install_github("baptiste/egg") library(egg) library(grid) g = ggarrange(x1, x2, x3, x4, ncol = 2) grid.newpage() grid.draw(g)
Original
Minor edit: Updating code.
If you want to keep the axis labels, then with some fiddling, and borrowing code from here, this does the job.
library(ggplot2) library(gtable) library(grid) library(gridExtra) # Get the widths gA <- ggplotGrob(x1) gB <- ggplotGrob(x2) gC <- ggplotGrob(x3) gD <- ggplotGrob(x4) maxWidth = unit.pmax(gA$widths[2:3], gB$widths[2:3], gC$widths[2:3], gD$widths[2:3]) # Set the widths gA$widths[2:3] <- maxWidth gB$widths[2:3] <- maxWidth gC$widths[2:3] <- maxWidth gD$widths[2:3] <- maxWidth # Arrange the four charts grid.arrange(gA, gB, gC, gD, nrow=2)
ALTERNATIVE SOLUTIONS: There are rbind
and cbind
functions in the gtable
package for combining grobs into one grob. For the charts here, the widths should be set using size = "max"
, but the CRAN version of gtable
throws an error.
One option is to examine the grid.arrange
plot, then use size = "first"
or size = "last"` options:
# Get the ggplot grobs gA <- ggplotGrob(x1) gB <- ggplotGrob(x2) gC <- ggplotGrob(x3) gD <- ggplotGrob(x4) # Arrange the four charts grid.arrange(gA, gB, gC, gD, nrow=2) # Combine the plots g = cbind(rbind(gA, gC, size = "last"), rbind(gB, gD, size = "last"), size = "first") # draw it grid.newpage() grid.draw(g)
A second option is to bind
ing functions from gridExtra
package.
# Get the ggplot grobs gA <- ggplotGrob(x1) gB <- ggplotGrob(x2) gC <- ggplotGrob(x3) gD <- ggplotGrob(x4) # Combine the plots g = cbind.gtable(rbind.gtable(gA, gC, size = "max"), rbind.gtable(gB, gD, size = "max"), size = "max") # Draw it grid.newpage() grid.draw(g)
That's exactly the kind of problem for which I wrote the cowplot package. It can be done in one line in that package:
require(cowplot) # loads ggplot2 as dependency # re-create the four plots A <- c(1,5,6,7,9) B <- c(10,56,64,86,98) C <- c(2001,3333,5678,4345,5345) D <- c(13446,20336,24333,34345,42345) L <- c(20,34,45,55,67) M <- data.frame(L, A, B, C, D) x1 <- ggplot(M, aes(L, A,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x2 <- ggplot(M, aes(L, B,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x3 <- ggplot(M, aes(L, C,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') x4 <- ggplot(M, aes(L, D,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm') # arrange into grid and align plot_grid(x1, x2, x3, x4, align='vh')
This is the result: (Note that cowplot changes the default ggplot2 theme. You can get the gray one back though if you really want to.)
As a bonus feature, you can also add plot labels in the top-left corner of each graph:
plot_grid(x1, x2, x3, x4, align='vh', labels=c('A', 'B', 'C', 'D'))
Result:
I use the labels
option on virtually every multi-part graph I make.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With