Search code examples
rggplot2titlefacet-grid

How to add titles on secondary axes in ggplot2 with discrete scale factors when using facet_grid?


Given the data and the ggplot2 code provided below, I'd like to add the blue titles "x1" and "y1" on secondary axes as follows:

enter image description here

Any idea?

Thanks for help

Data

dat <-
structure(list(x0 = c(15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 
30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 
45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 
15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 
30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 45, 15, 30, 
45, 15, 30, 45, 15, 30, 45), y0 = c(2, 2, 2, 7, 7, 7, 20, 20, 
20, 2, 2, 2, 7, 7, 7, 20, 20, 20, 2, 2, 2, 7, 7, 7, 20, 20, 20, 
2, 2, 2, 7, 7, 7, 20, 20, 20, 2, 2, 2, 7, 7, 7, 20, 20, 20, 2, 
2, 2, 7, 7, 7, 20, 20, 20, 2, 2, 2, 7, 7, 7, 20, 20, 20, 2, 2, 
2, 7, 7, 7, 20, 20, 20, 2, 2, 2, 7, 7, 7, 20, 20, 20), x1 = c(2, 
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 
4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 
3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4), y1 = c(50, 
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 250, 250, 250, 250, 250, 
250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 
250, 250, 250, 250, 250, 250, 250, 250, 250, 500, 500, 500, 500, 
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 
500, 500, 500, 500, 500, 500, 500, 500, 500, 500), percent = c(0.99, 
2.69, 4.91, -0.23, -0.22, 0.14, -1.5, -3.15, -4.61, 0.53, 1.65, 
3.43, -0.56, -0.81, -0.36, -0.34, -0.79, -1.21, -0.2, -0.29, 
-0.13, -0.64, -1.33, -1.59, 0.29, 0.68, 1.23, -1.16, -3.04, -4.94, 
-0.46, -1.23, -2.19, -1.06, -2.53, -3.88, 0.06, 0.11, 0.2, -0.42, 
-1.01, -1.38, -2.49, -5.71, -7.74, 0.09, 0.43, 1.4, -0.8, -1.38, 
-0.84, -2.13, -4.74, -6.41, -0.27, -0.64, -1.05, -0.27, -0.71, 
-1.22, -0.6, -1.46, -2.3, 0.12, 0.3, 0.43, 0.12, 0.46, 0.74, 
-0.44, -1, -1.61, 0.88, 2.04, 3.11, 0.68, 1.64, 2.48, -0.98, 
-2.14, -3.11)), class = "data.frame", row.names = c(NA, -81L))

Code

library(ggplot2)
ggplot(dat, aes(x = factor(x0), y = factor(y0))) + 
  geom_tile(aes(fill = percent)) +
  scale_fill_gradientn(
    colours=c("red2", "white", "green"),
    values = scales::rescale(c(-10, 0, 5)),
    limits=c(-10, 5)) +
  geom_text(aes(label = round(percent, 0))) + 
  facet_grid(y1 ~ x1) +
  theme_bw() +
  theme(axis.text.x = element_text(colour="black",size=13.1, angle=0, margin=margin(b=4), hjust = 0.5, vjust = 0.5)) +
  theme(axis.text.y = element_text(colour="black",size=13.1,  margin=margin(l=6), hjust = -0.1, vjust = 0.5)) +
  theme(panel.grid.major=element_line(colour="white",size=0.1))+
  theme(axis.ticks=element_blank()) +
  theme(plot.margin=unit(c(1.2,0.5,0.05,0.05),"cm")) +
  theme(legend.position = "right", legend.box.margin=margin(-10,-10,-10,-10)) +
  theme(strip.text = element_text(size = 12, color = "black")) +
  xlab(~paste("x0")) +
  ylab(~paste("y0")) +
  theme(axis.title=element_text(size=18))

Solution

  • One option to achieve your desired result would be to switch to a continuous x and y scale which allows to add your secondary axes titles via a secondary scale. To get the look of a discrete scale use as.numeric(factor(x)) to convert your x0 and y0 columns to numerics. Also, you have to explicitly set the breaks and labels.

    library(ggplot2)
    
    dat <- dat |>
      transform(
        x0_num = as.numeric(factor(x0)),
        y0_num = as.numeric(factor(y0))
      )
    
    breaks_x <- unique(dat$x0_num)
    labels_x <- unique(dat$x0)
    breaks_y <- unique(dat$y0_num)
    labels_y <- unique(dat$y0)
    
    ggplot(dat, aes(x = x0_num, y = y0_num)) +
      geom_tile(aes(fill = percent)) +
      scale_fill_gradientn(
        colours = c("red2", "white", "green"),
        values = scales::rescale(c(-10, 0, 5)),
        limits = c(-10, 5)
      ) +
      geom_text(aes(label = round(percent, 0))) +
      scale_x_continuous(
        breaks = breaks_x, labels = labels_x,
        sec.axis = dup_axis(name = "x1", labels = NULL)
      ) +
      scale_y_continuous(
        breaks = breaks_y, labels = labels_y,
        sec.axis = dup_axis(name = "y1", labels = NULL)
      ) +
      facet_grid(y1 ~ x1) +
      theme_bw() +
      theme(
        axis.title.x.top = element_text(color = "blue"),
        axis.title.y.right = element_text(hjust = 0, color = "blue")) +
      theme(axis.text.x = element_text(colour = "black", size = 13.1, angle = 0, margin = margin(b = 4), hjust = 0.5, vjust = 0.5)) +
      theme(axis.text.y = element_text(colour = "black", size = 13.1, margin = margin(l = 6), hjust = -0.1, vjust = 0.5)) +
      theme(panel.grid.major = element_line(colour = "white", size = 0.1)) +
      theme(axis.ticks = element_blank()) +
      theme(plot.margin = unit(c(1.2, 0.5, 0.05, 0.05), "cm")) +
      theme(legend.position = "right", legend.box.margin = margin(-10, -10, -10, -10)) +
      theme(strip.text = element_text(size = 12, color = "black")) +
      xlab(~ paste("x0")) +
      ylab(~ paste("y0")) +
      theme(axis.title = element_text(size = 18))
    

    enter image description here