rggplot2facetfacet-grid

Insert variable names and their specific values ​between the last column of facets and the strips of a facet_grid in R


The dataframe df includes the following variables:

For a selected bmk (select_bmk), I can represent almin and almax using geom_line (horizontal lines in red dashes) using the code below:

library(ggplot2)
library(dplyr)
    
# select bmk
select_bmk <- "bmk3"

# ggplot
df |> 
  filter(bmk == select_bmk) |> 
  ggplot(aes(x=x, y=y)) +
  geom_point() +
  facet_grid(qc ~ site, scales = "free_y") +
  geom_hline(aes(yintercept = almin, group = qc), linetype = "longdash", colour = "red3") +
  geom_hline(aes(yintercept = almax, group = qc), linetype = "longdash", colour = "red3")

enter image description here

However, I would like to insert a space between the last column of facets and the strips to display the names of the limits (here, almin and almax) followed by their specific values (in parentheses), as in the simulation below.

Is this possible?

Note: In my real data, there are more than 120 different bmk (hence the need to select only one), which have from 1 to 4 different qc levels, and about 12 different acceptable limits, each with specific qc level values.

enter image description here

Data:

library(ggplot2)
library(dplyr)

set.seed(123)

# bmk1
x <- 3 + rnorm(75)
y <- 15 + rnorm(75)
bmk <- as.factor(c(rep("bmk1",75)))
qc <- as.factor(c(rep("L1",75)))
site <- as.factor(rep(c(rep("A",25), rep("B",25), rep("C",25)), 1))
almin <- c(rep(13.5,75))
almax <- c(rep(16.5,75))
df1 <- data.frame(x,y,bmk,qc,site,almin,almax)

# bmk2
x <- 3 + rnorm(150)
y <- 20 + rnorm(150)
bmk <- as.factor(c(rep("bmk2",150)))
qc <- as.factor(c(rep("L1",75), rep("L2",75)))
site <- as.factor(rep(c(rep("A",25), rep("B",25), rep("C",25)), 2))
almin <- c(rep(19,150))
almax <- c(rep(21,150))
df2 <- data.frame(x,y,bmk,qc,site,almin,almax)
df2 <- df2 |> mutate(y = case_when(qc=="L2"~y+10, TRUE~y),
                     almin = case_when(qc=="L2"~almin+10, TRUE~almin),
                     almax = case_when(qc=="L2"~almax+10, TRUE~almax))

# bmk3
x <- 3 + rnorm(90)
y <- 30 + rnorm(90)
bmk <- as.factor(c(rep("bmk3",90)))
qc <- as.factor(c(rep("L1",30), rep("L2",30), rep("L3",30)))
site <- as.factor(rep(c(rep("A",10), rep("B",10), rep("C",10)), 3))
almin <- c(rep(29,90))
almax <- c(rep(31,90))
df3 <- data.frame(x,y,bmk,qc,site,almin,almax)
df3 <- df3 |> mutate(y = case_when(qc=="L2"~y+10, qc=="L3"~y+20, TRUE~y),
                     almin = case_when(qc=="L2"~almin+10, qc=="L3"~almin+20, TRUE~almin),
                     almax = case_when(qc=="L2"~almax+10, qc=="L3"~almax+20, TRUE~almax))
 
# rbind
df <- rbind(df1, df2, df3)
df$x <- round(df$x,2)
df$y <- round(df$y,2)

Thanks for help


Solution

  • One possible option would be to add the labels via a secondary axis where I use gg4hx::facetted_pos_scales to set the labels individually for each row of the facet grid:

    library(ggplot2)
    library(dplyr, warn = FALSE)
    library(ggh4x)
    
    select_bmk <- "bmk3"
    
    # Create a list of y scales per qc
    scales_y <- df |>
      filter(bmk == select_bmk) |>
      distinct(
        qc, almin, almax
      ) |>
      split(~qc) |>
      lapply(\(x) {
        scale_y_continuous(
          sec.axis = dup_axis(
            breaks = c(x$almin, x$almax),
            labels = paste0(
              c("almin", "almax"), " (", c(x$almin, x$almax), ")"
            )
          )
        )
      })
    
    df |>
      filter(bmk == select_bmk) |>
      ggplot(aes(x = x, y = y)) +
      geom_point() +
      facet_grid(qc ~ site, scales = "free_y") +
      geom_hline(
        aes(yintercept = almin, group = qc),
        linetype = "longdash", colour = "red3"
      ) +
      geom_hline(
        aes(yintercept = almax, group = qc),
        linetype = "longdash", colour = "red3"
      ) +
      ggh4x::facetted_pos_scales(
        y = scales_y
      ) +
      theme(
        strip.placement = "outside",
        axis.ticks.y.right = element_blank(),
        axis.text.y.right = element_text(
          colour = "red3"
        )
      )
    

    enter image description here