I'm using the patchwork
package in R to arrange 6 plots into a 3-row by 2-column layout, where each column has plots stacked vertically.
Each vertical column works when created independently, with fixed widths and heights using unit()
from the grid
package. But when I try to combine the two wrapped columns with wrap_plots()
, I get this error:
Error: index out of bounds ("unit" subsetting)
library(ggplot2)
library(patchwork)
library(grid)
# Dummy plots
p_tmp <- lapply(1:6, function(i) {
ggplot(
data = mtcars,
aes(mpg, wt)
) +
geom_point() +
labs(
subtitle = paste("Plot", i)
)
})
# Individual columns work fine
col1 <- wrap_plots(
p_tmp[1:3],
ncol = 1,
heights = unit(rep(2.5, 3), "cm"),
widths = unit(2.5, "cm")
) +
plot_annotation(
"col1"
)
col2 <- wrap_plots(
p_tmp[4:6],
ncol = 1,
heights = unit(rep(2.5, 3), "cm"),
widths = unit(9 / 16 * 2.5, "cm")
) +
plot_annotation(
"col2"
)
# Combining both results in error
wrap_plots(col1, col2, ncol = 2)
The individual column plots are working, but when combining them, I get the mentioned error.
How can I correctly combine multiple wrap_plots()
columns that use fixed unit() widths
and heights
?
Is there a way to keep fixed dimensions and still combine them in a larger layout without triggering this error?
Edit:
To clearify the aim of the question:
The first 3 plots are identical geom_raster()
plots and should share a common fill legend, while plots 4-6 remain the same. The position of the legend should be centered under the first column, which is not the case when combining all plots with one wrap_plots()
command.
library(ggplot2)
library(patchwork)
# Create raster plot
df <- expand.grid(x = 1:20, y = 1:20)
df$z <- as.vector(matrix(runif(400), nrow = 20, ncol = 20))
raster_plot <- ggplot(
data = df,
aes(x, y, fill = z)
) +
geom_raster(
interpolate = FALSE
) +
scale_fill_viridis_c() +
theme_minimal() +
theme(
legend.position = "bottom"
)
# Define plots
p_tmp <- c(
rep(list(raster_plot), 3),
lapply(1:3, function(i) {
ggplot(
data = mtcars,
aes(mpg, wt)
) +
geom_point() +
theme_minimal()
}))
heights <- unit(rep(2, 3), "cm")
# Column 1 – works alone
col1 <- wrap_plots(
p_tmp[1:3],
ncol = 1,
heights = heights,
widths = unit(2, "cm"),
guides = "collect"
)
# Column 2 – works alone
col2 <- wrap_plots(
p_tmp[4:6],
ncol = 1,
heights = heights,
widths = unit(9 / 16 * 2, "cm")
)
# Combining both → error
# wrap_plots(col1, col2, ncol = 2)
# Combining all → no error
wrap_plots(
p_tmp,
ncol = 2,
byrow = FALSE,
heights = heights,
widths = unit(c(2, 9 / 16 * 2), rep("cm", 2)),
guides = "collect",
axis_titles = "collect"
)
Instead of using multiple wrap_plot
s one option would be to use just one:
library(ggplot2)
library(patchwork)
p_tmp <- lapply(1:6, function(i) {
ggplot(
data = mtcars,
aes(mpg, wt)
) +
geom_point() +
labs(
subtitle = paste("Plot", i)
)
})
wrap_plots(
p_tmp,
ncol = 2,
byrow = FALSE,
heights = unit(rep(2.5, 3), "cm"),
widths = unit(c(2.5, 9 / 16 * 2.5), "cm")
)
EDIT To deal with the legend we can use guide_area
and plot_spacer
to add the legend to the first column:
library(ggplot2)
library(patchwork)
wrap_plots(
c(p_tmp[1:3], list(guide_area()), p_tmp[4:6], list(plot_spacer())),
ncol = 2,
nrow = 4,
byrow = FALSE,
heights = unit(c(rep(2.5, 3), 1), "cm"),
widths = unit(c(2.5, 9 / 16 * 2.5), "cm"),
guides = "collect"
)