'Consistent y-axis for insetting plots with different heights
I'm trying to inset several plots on the same graph with different heights but have the same y scales. In the example below I have two plots with different heights. When I plot them the y-axis don't correspond to one another. How can I programmatically 'align' these two graphs?
Thanks
library(dplyr)
library(gridExtra)
plot_1 = data.frame(x = 1:250,
y = 1:250) %>%
ggplot(aes(x = x, y = y)) +geom_point()+ scale_y_continuous(limits=c(0,250), expand = c(0, 0)) +
theme(legend.position="none",axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank())
plot_2 = data.frame(x = 1:250,
y = 1:250*3) %>%
ggplot(aes(x = x, y = y)) +geom_point()+ scale_y_continuous(limits=c(0,750), expand = c(0, 0)) +
theme(legend.position="none",axis.title.x=element_blank(),axis.text.x=element_blank(),axis.ticks.x=element_blank())
base <- ggplot(data.frame(x = 1:1000,
y = 1:1000), aes(x, y)) +
geom_blank() +
theme_bw()
base = base +
annotation_custom(grob = ggplotGrob(plot_1),
ymin = 0,
ymax = 250,
xmin = 0,
xmax = 200)
base = base +
annotation_custom(grob = ggplotGrob(plot_2),
ymin = 0,
ymax = 750,
xmin = 300,
xmax = 500)
base
Note that the graph below shows the y-axis aren't on the same scale.

Solution 1:[1]
OP notes the y axes are not on the same scale in the inset plot - presumably, they mean compared to the original plot. The reasoning behind this is that the plot itself is not defined only by the size of the area used for plotting, but also includes all the border elements around the plot + a margin. The inset plots have no x axis labels, so to have the y axes align, all that is needed is to remove the margin around the plot which is added by default:
base <-
ggplot(data.frame(x = 1:1000, y = 1:1000), aes(x, y)) +
geom_blank() +
theme_bw() +
annotation_custom(
grob = ggplotGrob(plot_1 + theme(plot.margin = margin())),
ymin = 0, ymax = 250,
xmin = 0, xmax = 200) +
annotation_custom(
grob = ggplotGrob(plot_2 + theme(plot.margin = margin())),
ymin = 0, ymax = 750,
xmin = 300, xmax = 500)
base
If you notice... it's not perfect. There's a bit of space below each inset plot, so the 0 values do not align completely. What's going on here? Well, even though OP applied theme(axis.ticks.x = element_blank()), "blanking" basically means "drawing them as nothing". The ticks are actually still there, just not drawn. This means, the total plot area includes the size of the ticks. To remove this little space below the plot, we have to set the size of the axis ticks to zero:
base <-
ggplot(data.frame(x = 1:1000, y = 1:1000), aes(x, y)) +
geom_blank() +
theme_bw() +
annotation_custom(
grob = ggplotGrob(plot_1 + theme(plot.margin = margin(), axis.ticks.length.x = unit(0,'pt'))),
ymin = 0, ymax = 250,
xmin = 0, xmax = 200) +
annotation_custom(
grob = ggplotGrob(plot_2 + theme(plot.margin = margin(), axis.ticks.length.x = unit(0,'pt'))),
ymin = 0, ymax = 750,
xmin = 300, xmax = 500)
base
That fixes it.
Solution 2:[2]
This isn't perfect but might work with some tweaking.
base <- ggplot(data.frame(x = 1:1000,
y = 1:1000), aes(x, y)) +
geom_blank() +
theme_bw()
y_scaling <- 0.8
y_border <- 50
y_max <- function(plot) {
(diff(range(plot$data$y)) + y_border) * y_scaling
}
y_max(plot_1)
base = base +
annotation_custom(grob = ggplotGrob(plot_1),
ymin = 0,
ymax = y_max(plot_1),
xmin = 0,
xmax = 200)
base = base +
annotation_custom(grob = ggplotGrob(plot_2),
ymin = 0,
ymax = y_max(plot_2),
xmin = 300,
xmax = 500)
base
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Jon Spring |



