I have some ggplots which I have tweaked to make sure the annotations fit nicely within the bounds of the plot. For example:
Now I want to put two of these images side-by-side. I've tried to do this with grid.arrange and patchwork, but the layout of the graph changes, presumably because it's being fit into a smaller space:
Everything is more cramped, points are packed together so it's harder to read and the annotation boxes go off the side of the graph.
What I want to do is to expand the canvas by exactly enough that each graph looks exactly as it did when plotted alone (i.e. when plotted using the default canvas size). It would presumably need to be a little more than twice as wide, to allow for padding. How would I achieve this?
Example code:
library(ggplot2)
library(ggtext)
library(tidyverse)
library(patchwork)
N <- 10000
rho = 0.5
mu <- c(0, 0)
sigma <- matrix(c(1, rho,
rho, 1 ),
nrow = 2, ncol = 2, byrow = TRUE)
vs = MASS::mvrnorm(N, mu, sigma)
df = tibble(rMZall = vs[,1], rDZall = vs[,2], n_twin_pairs = runif(N, 5000, 50000))
plot <- function(min_twin_pairs) {
ggplot(data=df |> filter(n_twin_pairs > min_twin_pairs), aes(rMZall, rDZall)) +
ggtitle(sprintf("Studies with > %d twin pairs", min_twin_pairs)) +
theme(legend.position="none") +
# Bounds
scale_x_continuous(name = "rMZ", limits = c(-0.05, 1.1), breaks = seq(0,1,0.25)) +
scale_y_continuous(name = "rDZ", limits = c(-0.05, 1), breaks = seq(0,1,0.25)) +
coord_fixed() +
# Scatterplot
stat_density2d(aes(fill=..level.., alpha=..level..), geom='polygon', colour='black', linewidth = 0.1) +
scale_fill_continuous(low="green", high="red") +
geom_point(aes(size = sqrt(n_twin_pairs))) +
scale_size_continuous(range = c(0, 1)) +
# AE and AD lines
geom_abline(intercept = 0, slope = .5) +
annotate(geom = "richtext", x = 1, y = .5, label = "AE model", angle = 26.6) +
geom_abline(intercept = 0, slope = .25) +
annotate(geom = "richtext", x = 1, y = .25, label = "AD model", angle = 14.0)
}
plot1000 = plot(min_twin_pairs = 1000)
plot4000 = plot(min_twin_pairs = 4000)
plot1000
plot4000
plot1000 + plot4000
You could instead use geomtextpath, specifically geomtextpath::geom_labelabline()
. This handles the positioning automatically so you don’t need to futz with angles, canvas sizing, and the like.
library(tidyverse)
library(geomtextpath)
library(patchwork)
set.seed(13)
plot <- function(min_twin_pairs) {
ggplot(data=df |> filter(n_twin_pairs > min_twin_pairs), aes(rMZall, rDZall)) +
ggtitle(sprintf("Studies with > %d twin pairs", min_twin_pairs)) +
theme(legend.position="none") +
# Bounds
scale_x_continuous(name = "rMZ", limits = c(-0.05, 1.1), breaks = seq(0,1,0.25)) +
scale_y_continuous(name = "rDZ", limits = c(-0.05, 1), breaks = seq(0,1,0.25)) +
coord_fixed() +
# Scatterplot
stat_density2d(aes(fill=..level.., alpha=..level..), geom='polygon', colour='black', linewidth = 0.1) +
scale_fill_continuous(low="green", high="red") +
geom_point(aes(size = sqrt(n_twin_pairs))) +
scale_size_continuous(range = c(0, 1)) +
# AE and AD lines
geom_labelabline(intercept = 0, slope = .5, label = "AE model", hjust = 0.85) +
geom_labelabline(intercept = 0, slope = .25, label = "AD model", hjust = 0.85)
}
plot1000 <- plot(min_twin_pairs = 1000)
plot4000 <- plot(min_twin_pairs = 4000)
plot1000 + plot4000