Home > Blockchain >  How to arrange `ggplot2` objects side-by-side and ensure equal plotting areas?
How to arrange `ggplot2` objects side-by-side and ensure equal plotting areas?

Time:09-23

I am trying to arrange two ggplot2 plots side by side, i.e., in a two-column layout using the package gridExtra. I am interested in ensuring that both plots have equal plotting area (i.e., the gray plot panel is the same for both plots) regardless of the height of the x-axis labels. As you can see in the example below, when longer x-axis labels are used, gridExtra::grid.arrange() seems to compensate this by adjusting the plotting area (i.e., the grayed out part of the plot).

# Dummy data.
data <- data.frame(x = 1:10, y = rnorm(10))

# Dummy labels.
x_labels_short <- 1:10
x_labels_long <- 100001:100010

# Common settings for both `ggplot2` plots.
layers <- list(
    labs(
        x = "Plot title"
    ),
    theme(
        axis.text.x = element_text(
            angle = 90,
            vjust = 0.5,
            hjust = 1
        )
    )
)

# `ggplot2 plot (a).
plot_a <- ggplot(data, aes(x, y))  
    scale_x_continuous(breaks = 1:10, labels = x_labels_short)  
    layers

# `ggplo2` plot (b).
plot_b <- ggplot(data, aes(x, y))  
    scale_x_continuous(breaks = 1:10, labels = x_labels_long)  
    layers

# Showing the plots side by side.
gridExtra::grid.arrange(
    plot_a,
    plot_b,
    ncol = 2
)

Output:

ggplot2 plot

What I want is for both plots to (1) have equal plotting area and (b) the x-axis title of plot_a to be aligned with that of plot_b (i.e., the x-axis title of plot_a to be offset based on the length of of the x-axis labels of plot_b).

If this is not clear, this is what I want to achieve would look like with base R.

# Wrapper for convenience.
plot_gen <- function(data, labels) {
    plot(
        NULL,
        xlim = c(1, 10),
        ylim = c(min(data$y), max(data$y)),
        xlab = "",
        ylab = "y",
        xaxt = "n"
    )
    axis(
        side = 1,
        at = 1:10,
        labels = labels,
        las = 2
    )
    title(
        xlab = "Plot title",
        line = 4.5
    )
}

# Get `par`.
old_par = par(no.readonly = TRUE)

# Set the two-column layout.
layout(matrix(1:2, ncol = 2))

# Adjust margins.
par(mar = old_par$mar   c(1.5, 0, 0, 0))

# Plot base plot one.
plot_gen(data, x_labels_short)

# Plot base plot two.
plot_gen(data, x_labels_long)

# Restore `par`.
par(old_par)

# Restore layout.
layout(1:1)

Output:

base R plot

Quick mention. I found a similar question on SO (i.e., ggplot side-by-side with similar axis spacing

It also works for more complex layouts, e.g.:

(plot_a | plot_b) / plot_a

enter image description here

  • Related