Share x-axis and y-axis label on the same combo chart

124 Views Asked by At

I need to share x-axis and y-axis label on the same combo chart, using egg::ggarrange,

I tried:

library(ggplot2)
df <- data.frame(
  x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)

p1 <- ggplot(df, aes(x, y1)) + geom_point() + theme(axis.title.x = element_blank(),
                                                    axis.title.y = element_blank())
p2 <- ggplot(df, aes(x, y2)) + geom_point() + theme(axis.title.x = element_blank(),
                                                    axis.title.y = element_blank())
p3 <- ggplot(df, aes(x, y3)) + geom_point() + theme(axis.title.x = element_blank(),
                                                    axis.title.y = element_blank())
p4 <- ggplot(df, aes(x, y4)) + geom_point() + theme(axis.title.x = element_blank(),
                                                    axis.title.y = element_blank())

# Create a simple grid
p <- plot_grid(p1, p2, p3, p4, align = 'hv')

p + draw_figure_label(label = "Figure 1")




p <- Map(function(a, b) {
  a + 
    labs(caption = b) + 
    theme(plot.caption.position = 'panel',
          plot.caption = element_text(hjust = 0.5, size = 12, face = 2,
                                      margin = margin(10, 0, 30, 0)))
}, 
a = list(p1, p2, p3, p4),
b = list('(a) Figure 1', '(b) Figure 2', '(c) Figure 3', '(d) Figure 4'))


graph <- egg::ggarrange(p[[1]], p[[2]], p[[3]], p[[4]])


annotate_figure(graph, left = textGrob("axis-y", rot = 90, vjust = 1, gp = gpar(cex = 0.8)),
                bottom = textGrob("axis-x", gp = gpar(cex = 0.8)))

However, the x-axis and y-axis labels appear after the figure labels. Also, they are very far away.

1

There are 1 best solutions below

2
stefan On

Not 100% sure about your desired final result. But perhaps this is what your are looking for.

IMHO the tricky part is to switch the placement of the subfigure titles and the x-axis title. After playing around a bit with facetting the only approach I could come with is to create the plots and the subfigure titles as separate plots which I glue together using patchwork. Additionally I created a fifth plot to create the shared y-axis title. First step in my approach is to reshape your data to long format. Afterwards I use some custom functions to create the plots:

library(ggplot2)
library(patchwork)

df <- data.frame(
  x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)

df_long <- df |>
  tidyr::pivot_longer(-x, names_to = "y")

plot_fun <- function(which, x = "") {
  ggplot(subset(df_long, y %in% which), aes(x, value)) +
    geom_point() +
    facet_wrap(~y, scales = "free") +
    theme(
      strip.background.x = element_blank(),
      strip.text.x = element_blank(),
    ) +
    labs(x = x, y = NULL)
}

plot_tag <- function(which) {
  ggplot() +
    facet_wrap(~as.character(which),
               strip.position = "bottom") +
    theme_void() +
    theme(
      strip.placement = "outside",
      strip.background.x = element_blank(),
      strip.text.x = element_text(
        hjust = 0.5, size = 12, face = 2,
        margin = margin(0, 0, 11, 0),
        
      ),
      strip.clip = "off"
    )
}

plot_y <- function(y) {
  ggplot() +
    theme_void() +
    labs(y = y) +
    theme(axis.title.y = element_text(angle = 90))
}

p1 <- plot_fun(c("y1", "y2"))
p2 <- plot_tag(c("(a) Figure 1", "(b) Figure 2"))
p3 <- plot_fun(c("y3", "y4"), "axis-x")
p4 <- plot_tag(c("(c) Figure 3", "(d) Figure 4"))
p5 <- plot_y("axis-y")


design <- "
EA
EB
EC
ED
"
wrap_plots(list(p1, p2, p3, p4, p5))+ 
  plot_layout(heights = c(40, 1, 40, 1), widths = c(1, 80), design = design)