rggplot2colorslegendfacet-grid

Split the legend into three rows with headings for a nested facet_wrap


The dataframe df0 below includes the following variables:

Question: Considering the facet_grid below, how to split the legend of the analyzers by site, in the given order of sites and in the order of the analyzers within each site, as shown on the (right) desired plot, while adding the names of sites on the left side?

Note: The objective is to select a given analyte, with the difficulty being that not all analytes are measured on all analyzers or at all sites, and that the number of QC levels can vary depending on the analyte (in the example, 2 QC levels for analyte AAA, 3 for BBB, and 4 levels for CCC).

Thanks for help

Initial (left) and desired (right) legends:

enter image description here

Initial plot code:

library(tidyverse)
library(scales)
library(ggh4x)

# select analyte
select_analyte <- "CCC"

# Combinations of facetting variables for nested panels (# https://stackoverflow.com/questions/77618900/how-to-implement-conditional-coloring-for-facet-nested-panels-in-r)
combos <- df0 |>
  distinct(qc, site, analyte) |>
  arrange(qc, site, analyte) |> 
  mutate(qc = as.character(qc)) |> 
  filter(analyte == select_analyte)

strip_background <- 
  strip_nested(
  bleed = FALSE,
  background_x =
    elem_list_rect(
      fill = c(
        case_match(
          unique(combos$qc),
          "" ~ "grey70",
          .default = "grey70"
        ),
        case_match(
          combos$site,
          "" ~ "grey85",
          .default = "grey85"
          ))))

# plot
df0 |> 
  filter(analyte == select_analyte) |> 
  ggplot(aes(x=year_month, y=cv, colour=analyzer, group=analyzer)) +
  ggtitle(paste0(select_analyte)) +
  facet_wrap2(
    vars(qc, site), ncol = 3,
    drop = FALSE,
    strip = strip_background) +
  scale_x_discrete(expand = expansion(mult = c(0.05, 0.05))) +
  scale_y_continuous(limits = c(0, NA), expand = expansion(mult = c(0, 0.1)), breaks = breaks_pretty()) +
  geom_line(linewidth=1) +
  labs(x = NULL, y = expression('cv')) +
  theme(
    plot.margin=unit(c(0.2, 0.8, 0.2, 0.5),"cm"), # trbl
    plot.title = element_text(size = 16, face = "bold", vjust = 1),
    plot.subtitle = element_text(size = 11, vjust = 1),
    panel.background = element_rect(fill = "white"),
    panel.grid.major = element_line(colour="grey80", linewidth = 0.3),
    panel.border = element_rect(colour = "grey10", fill = NA, linewidth = 0.4),
    strip.background = element_rect(color="black", linetype="solid"),
    strip.text.x = element_text(size = 13, color = "black"),
    strip.text.y = element_text(size = 13, color = "black", angle = -90),
    axis.title.x = element_text(vjust = -0.5, size = 13),
    axis.title.y = element_text(vjust = 4.8, size = 13),
    axis.text.x = element_text(margin = margin(b = 0.1), hjust= 1.12, vjust = 1.05, colour="black", size = 10, angle=60),
    axis.text.y = element_text(margin = margin(l = -5, r = 2.5), colour="black", size = 12),
    legend.margin = margin(unit(-2,"cm")),
    legend.title = element_blank(),
    legend.position = "top",
    legend.justification='left',
    legend.text = element_text(size = 14)) +
  guides(colour = guide_legend(
    override.aes = list(linewidth=1.3, label = ""))) +
  coord_cartesian(clip = "off")

Data:

df0 <-  
structure(list(site = c("SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", "SX", 
"SX", "SX", "SX", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", 
"SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", 
"SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", 
"SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", "SY", 
"SY", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", "SZ", 
"SZ"), analyte = c("AAA", "AAA", "AAA", "AAA", "AAA", "AAA", 
"AAA", "AAA", "AAA", "AAA", "AAA", "AAA", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "BBB", "BBB", "BBB", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", "CCC", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", 
"BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB", "BBB"
), qc = c("QC_A1", "QC_A2", "QC_A1", "QC_A2", "QC_A1", "QC_A2", 
"QC_A1", "QC_A2", "QC_A1", "QC_A2", "QC_A1", "QC_A2", "QC_C1", 
"QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", 
"QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", 
"QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", 
"QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", 
"QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", 
"QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", 
"QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_B1", "QC_B2", 
"QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", 
"QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", 
"QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", 
"QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_C1", "QC_C2", "QC_C3", 
"QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", 
"QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", 
"QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", 
"QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", 
"QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", 
"QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_C1", "QC_C2", "QC_C3", 
"QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", 
"QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", 
"QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", 
"QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", 
"QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", "QC_C2", 
"QC_C3", "QC_C4", "QC_C1", "QC_C2", "QC_C3", "QC_C4", "QC_C1", 
"QC_C2", "QC_C3", "QC_C4", "QC_B1", "QC_B2", "QC_B3", "QC_B1", 
"QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", 
"QC_B3", "QC_B1", "QC_B2", "QC_B3", "QC_B1", "QC_B2", "QC_B3"
), analyzer = c("X1_C", "X1_C", "X3_C", "X3_C", "X1_C", "X1_C", 
"X3_C", "X3_C", "X1_C", "X1_C", "X3_C", "X3_C", "X1_B1", "X1_B1", 
"X1_B1", "X1_B1", "X1_B2", "X1_B2", "X1_B2", "X1_B2", "X2_B", 
"X2_B", "X2_B", "X2_B", "X3_B", "X3_B", "X3_B", "X3_B", "X1_B1", 
"X1_B1", "X1_B1", "X1_B1", "X1_B2", "X1_B2", "X1_B2", "X1_B2", 
"X2_B", "X2_B", "X2_B", "X2_B", "X3_B", "X3_B", "X3_B", "X3_B", 
"X1_B1", "X1_B1", "X1_B1", "X1_B1", "X1_B2", "X1_B2", "X1_B2", 
"X1_B2", "X2_B", "X2_B", "X2_B", "X2_B", "X3_B", "X3_B", "X3_B", 
"X3_B", "X1_C", "X1_C", "X1_C", "X2_C", "X2_C", "X2_C", "X3_C", 
"X3_C", "X3_C", "X1_C", "X1_C", "X1_C", "X2_C", "X2_C", "X2_C", 
"X3_C", "X3_C", "X3_C", "X1_C", "X1_C", "X1_C", "X2_C", "X2_C", 
"X2_C", "X3_C", "X3_C", "X3_C", "Y1_B", "Y1_B", "Y1_B", "Y1_B", 
"Y2_B", "Y2_B", "Y2_B", "Y2_B", "Y1_B", "Y1_B", "Y1_B", "Y1_B", 
"Y2_B", "Y2_B", "Y2_B", "Y2_B", "Y1_B", "Y1_B", "Y1_B", "Y1_B", 
"Y2_B", "Y2_B", "Y2_B", "Y2_B", "Y1_C", "Y1_C", "Y1_C", "Y2_C", 
"Y2_C", "Y2_C", "Y1_C", "Y1_C", "Y1_C", "Y2_C", "Y2_C", "Y2_C", 
"Y1_C", "Y1_C", "Y1_C", "Y2_C", "Y2_C", "Y2_C", "Z1_B1", "Z1_B1", 
"Z1_B1", "Z1_B1", "Z1_B2", "Z1_B2", "Z1_B2", "Z1_B2", "Z2_B1", 
"Z2_B1", "Z2_B1", "Z2_B1", "Z2_B2", "Z2_B2", "Z2_B2", "Z2_B2", 
"Z1_B1", "Z1_B1", "Z1_B1", "Z1_B1", "Z1_B2", "Z1_B2", "Z1_B2", 
"Z1_B2", "Z2_B1", "Z2_B1", "Z2_B1", "Z2_B1", "Z2_B2", "Z2_B2", 
"Z2_B2", "Z2_B2", "Z1_B1", "Z1_B1", "Z1_B1", "Z1_B1", "Z1_B2", 
"Z1_B2", "Z1_B2", "Z1_B2", "Z2_B1", "Z2_B1", "Z2_B1", "Z2_B1", 
"Z2_B2", "Z2_B2", "Z2_B2", "Z2_B2", "Z1_C", "Z1_C", "Z1_C", "Z2_C", 
"Z2_C", "Z2_C", "Z1_C", "Z1_C", "Z1_C", "Z2_C", "Z2_C", "Z2_C", 
"Z1_C", "Z1_C", "Z1_C", "Z2_C", "Z2_C", "Z2_C"), year_month = c("2025-09", 
"2025-09", "2025-09", "2025-09", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-11", "2025-11", "2025-11", "2025-11", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-11", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-10", "2025-10", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11", "2025-09", "2025-09", "2025-09", "2025-09", 
"2025-09", "2025-09", "2025-10", "2025-10", "2025-10", "2025-10", 
"2025-10", "2025-10", "2025-11", "2025-11", "2025-11", "2025-11", 
"2025-11", "2025-11"), cv = c(2.64, 3.83, 2.66, 3.11, 1.63, 1.82, 
3.74, 3.81, 1.46, 2.07, 3.78, 3.17, 1.27, 1.05, 1.82, 2.84, 1.12, 
0.97, 1.36, 2.81, 1.16, 2.51, 1.66, 3.24, 1.03, 0.78, 1.11, 2.92, 
1.82, 0.87, 1.46, 2.56, 1.61, 1.24, 1.3, 2.45, 1.68, 1.69, 1.33, 
2.24, 2.11, 0.74, 1.38, 2.33, 1.14, 0.96, 1.23, 3.05, 1.34, 1.01, 
1.09, 2.35, 1.35, 1.06, 1.08, 2.2, 2.22, 0.68, 1.09, 2.56, 3.92, 
2.66, 2.59, 2.38, 2.83, 1.95, 2.26, 1.58, 1.68, 2.59, 1.61, 1.56, 
5.78, 2.05, 1.87, 3.68, 3.65, 1.21, 4.99, 1.23, 1.02, 2.63, 1.79, 
1.13, 2.21, 1.22, 1.37, 1.05, 1.17, 1.05, 4.82, 1.88, 1.07, 1.17, 
4.59, 2.64, 1.55, 1.87, 4.17, 1.87, 1.33, 1.38, 4.74, 1.51, 1.32, 
1.29, 4.05, 1.78, 1.73, 1.43, 3.86, 4.99, 4.02, 4.12, 3.09, 1.32, 
1.39, 4.52, 2.11, 2.97, 5.48, 2.31, 2.85, 2.89, 1.41, 1.31, 2.79, 
1.49, 1.51, 1.35, 1.37, 1.48, 2.91, 1.21, 1.25, 1.25, 2.93, 1.31, 
1.55, 1.41, 3.19, 1.34, 4.05, 1.36, 2.64, 1.24, 1.46, 1.42, 2.82, 
1.78, 1.41, 1.52, 3.01, 2.24, 1.37, 1.84, 3.95, 1.53, 1.21, 1.21, 
3.76, 2.49, 1.55, 1.26, 2.93, 2.39, 1.56, 1.26, 2.52, 2.06, 0.94, 
1.19, 2.25, 1.73, 1.02, 1.31, 2.72, 2.24, 1.08, 2.09, 5.57, 3.65, 
3.56, 3.19, 2.45, 2.14, 3.2, 1.8, 2.13, 2.56, 1.23, 1.21, 2.62, 
1.44, 1.37)), row.names = c(NA, -195L), class = c("tbl_df", "tbl", 
"data.frame"))

Solution

  • As suggested by @r2evans in the comments, the legendry package now offers an easy out-of-the-box option to

    keep groups in blocks with their own titles

    via guide_legend_group:

    library(tidyverse)
    library(scales)
    library(ggh4x)
    library(legendry)
    
    df0 |>
      filter(analyte == select_analyte) |>
      ggplot(aes(x = year_month, y = cv, group = analyzer)) +
      ggtitle(paste0(select_analyte)) +
      facet_wrap2(
        vars(qc, site),
        ncol = 3,
        drop = FALSE,
        strip = strip_background
      ) +
      scale_x_discrete(expand = expansion(mult = 0.05)) +
      scale_y_continuous(
        limits = c(0, NA),
        expand = expansion(mult = c(0, 0.1)),
        breaks = breaks_pretty()
      ) +
      geom_line(
        # Add the subgroup name and the seperator = "." used to split into
        # groups
        aes(color = paste0(site, ":.", analyzer)),
        linewidth = 1
      ) +
      labs(x = NULL, y = expression("cv")) +
      theme(
        plot.margin = unit(c(0.2, 0.8, 0.2, 0.5), "cm"), # trbl
        plot.title = element_text(size = 16, face = "bold", vjust = 1),
        plot.subtitle = element_text(size = 11, vjust = 1),
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "grey80", linewidth = 0.3),
        panel.border = element_rect(colour = "grey10", fill = NA, linewidth = 0.4),
        strip.background = element_rect(color = "black", linetype = "solid"),
        strip.text.x = element_text(size = 13, color = "black"),
        strip.text.y = element_text(size = 13, color = "black", angle = -90),
        axis.title.x = element_text(vjust = -0.5, size = 13),
        axis.title.y = element_text(vjust = 4.8, size = 13),
        axis.text.x = element_text(
          margin = margin(b = 0.1),
          hjust = 1.12, vjust = 1.05, colour = "black", size = 10, angle = 60
        ),
        axis.text.y = element_text(
          margin = margin(l = -5, r = 2.5),
          colour = "black", size = 12
        ),
        legend.margin = margin(),
        legend.position = "top",
        legend.justification = "left",
        legend.text = element_text(size = 14),
        legend.direction = "vertical"
      ) +
      coord_cartesian(clip = "off") +
      guides(colour = guide_legend_group(
        key = key_group_split(sep = "\\."),
        override.aes = list(linewidth = 1.3),
        nrow = 1,
        title = NULL
      )) +
      theme(
        legendry.legend.subtitle.position = "left",
        legendry.group.spacing = unit(0, "cm")
      )
    

    enter image description here

    A second option would be the ggnewscale package which however requires much more effort and as downside does not align the legend keys in columns across the legend groups:

    library(tidyverse)
    library(scales)
    library(ggh4x)
    library(ggnewscale)
    
    df1 <- df0 |>
      filter(analyte == select_analyte)
    
    # per site color palettes
    pal_color <- df1 |>
      distinct(site, analyzer) |>
      arrange(site, analyzer) |>
      mutate(
        color = scales::pal_hue()(n_distinct(analyzer))
      ) |>
      split(~site) |>
      lapply(
        function(x) {
          x |>
            select(-site) |>
            deframe()
        }
      )
    
    # plot
    df1 |>
      ggplot(aes(x = year_month, y = cv, group = analyzer)) +
      ggtitle(paste0(select_analyte)) +
      facet_wrap2(
        vars(qc, site),
        ncol = 3,
        drop = FALSE,
        strip = strip_background
      ) +
      scale_x_discrete(expand = expansion(mult = 0.05)) +
      scale_y_continuous(
        limits = c(0, NA),
        expand = expansion(mult = c(0, 0.1)),
        breaks = breaks_pretty()
      ) +
      purrr::imap(
        df1 |> split(~site),
        function(x, site) {
          list(
            geom_line(data = x, aes(color = analyzer), linewidth = 1),
            scale_color_manual(
              values = pal_color[[site]],
              guide = guide_legend(
                title = paste0(site, ":"),
                override.aes = list(linewidth = 1.3),
                order = which(names(pal_color) == site)
              )
            ),
            ggnewscale::new_scale_color()
          )
        }
      ) +
      labs(x = NULL, y = expression("cv")) +
      theme(
        plot.margin = unit(c(0.2, 0.8, 0.2, 0.5), "cm"), # trbl
        plot.title = element_text(size = 16, face = "bold", vjust = 1),
        plot.subtitle = element_text(size = 11, vjust = 1),
        panel.background = element_rect(fill = "white"),
        panel.grid.major = element_line(colour = "grey80", linewidth = 0.3),
        panel.border = element_rect(colour = "grey10", fill = NA, linewidth = 0.4),
        strip.background = element_rect(color = "black", linetype = "solid"),
        strip.text.x = element_text(size = 13, color = "black"),
        strip.text.y = element_text(size = 13, color = "black", angle = -90),
        axis.title.x = element_text(vjust = -0.5, size = 13),
        axis.title.y = element_text(vjust = 4.8, size = 13),
        axis.text.x = element_text(
          margin = margin(b = 0.1),
          hjust = 1.12, vjust = 1.05, colour = "black", size = 10, angle = 60
        ),
        axis.text.y = element_text(
          margin = margin(l = -5, r = 2.5),
          colour = "black", size = 12
        ),
        legend.margin = margin(),
        legend.position = "top",
        legend.justification = "left",
        legend.text = element_text(size = 14),
        legend.box = "vertical",
        legend.box.just = "left",
        legend.spacing = unit(0, "pt")
      ) +
      coord_cartesian(clip = "off")
    

    enter image description here