I have two graphs that I'm placing one above the other, in the following way:
library(ggplot2)
library(gridExtra)
p1 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p2 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p2 <- p2 + facet_grid(cyl ~ .)
grid.arrange(p1, p2, ncol=1)
For this I need the x axes of the top and bottom graphs to line up, however because of the strip to the left, the faceted graph is narrower than the top graph. I can make the strip invisible using:
theme(strip.text.y = element_blank())
theme(strip.background = element_blank())
However this does not get rid of the space that the strip takes up. So I either need a way to get rid of the strip entirely, or have a way to split my faceted graph into separate graphs, yet somehow sharing the same y-axis label across them. In my graph I have two faceted panels that are not very tall, and there isn't enough space for them to each have a decent-sized y-axis.
Any suggestions?
My solution would be to find the width of the strip and then set the margins of both plots to be zero, but shrink the one without the strip to be slightly smaller (the width of the strip) so they appear to be the same size. By trial and error it seems the strip is about 0.5 lines wide (but I guess you could figure this out programatically). Therefore just make sure the right plot margin in the plot without the strip text is 0.5 lines greater than the one with the invisible strip:
# Add a line of width 0.5 on the left but set all other margins to zero
p1 <- p1 + theme( plot.margin = unit( c(0,0.5,0,0) , units = "lines" ) )
# Set all margins to zero, the strip will take up a phantom amount of invisible space
p2 <- p2 + theme(strip.text.y = element_blank() ,
strip.background = element_blank(),
plot.margin = unit( c(0,0,0,0) , units = "lines" ) )
grid.arrange(p1, p2, ncol=1)
Obviously you can adjust the margins as you wish (e.g. add 1 to the first position in each numeric vector in plot.margin
to get a border of one line along the top of each plot), as long as you keep 0.5 lines more margin in the right border of the second plot they will look the same.
Another solution using functions from the gtable
package. It aligns the plots but keeps the strip text. It uses a gtable
function to insert a column to the right of p1
equal to the width of the strip text of p2
.
library(ggplot2)
library(gridExtra)
library(gtable)
p1 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p2 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p2 <- p2 + facet_grid(cyl ~ .)
g1 = ggplotGrob(p1)
# gtable_show_layout(g1) # View the layout
# g1$widths # Get the widths of g1
g2 = ggplotGrob(p2)
# gtable_show_layout(g2) # View the layout
# g2$widths # Check the widths of g2
# Add new column to the right of g1 equal in width the strip width of g2.
# In g2, strip width is the 6th element the vector g2$widths
g1 <- gtable_add_cols(g1, g2$widths[6])
grid.arrange(g1, g2, ncol=1)
## But note that if the y-axis titles and/or labels take up different widths,
# the two plots are not aligned
p1 <- ggplot(mtcars, aes(mpg, wt)) + geom_point() +
theme(axis.title.y = element_text(vjust = .5, angle = 0, size = 30))
p2 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p2 <- p2 + facet_grid(cyl ~ .)
g1 = ggplotGrob(p1)
g2 = ggplotGrob(p2)
g1 <- gtable_add_cols(g1, g2$widths[6]) # New column added to the right
grid.arrange(g1, g2, ncol=1) # Plots are not aligned
# Need to set widths to the maximums in the two plots,
# i.e., set g2 widths to be the same as g1 widths
g2$widths <- g1$widths
grid.arrange(g1, g2, ncol=1) # Plots are aligned
EDIT: Or as suggested by baptiste, use gtable
's rbind()
function:
g1 = ggplotGrob(p1)
g2 = ggplotGrob(p2)
g1 <- gtable_add_cols(g1, g2$widths[6], 5) # New column added to the right
library(grid)
grid.draw(rbind(g1, g2, size = "first"))
Here another solution using viewport
and grid.layout
. I creates 2 viewports with 2 differents layouts.Then I place ggplot2 plots using argument vp.
library(grid)
pushViewport(plotViewport(c(1,1,1,1),layout = grid.layout(2, 1)))
print(p2, vp = viewport(layout.pos.row = 2, layout.pos.col = 1))
pushViewport(viewport(layout.pos.row=1,
layout = grid.layout(1, 2,widths = unit(c(1,1),c("null",'lines')))))
print(p1, vp = viewport(layout.pos.row = 1, layout.pos.col = 1))
upViewport(2)
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