rggplot2

add legend manually to facet gridded ggplot2


I made a facet gridded figure and have changed the background color of the facet strips to match specific groups. In this example those specific groups are where a car manufacturer is located (i.e., Mercedes and Fiat = Europe and Toyota = Japan). How can I add a legend to the facet gridded plot to indicate that the orange fill color means Europe and blue means Japan?

The ideal output would have a legend above the plot with an orange and blue box that says Europe and Japan next to it, respectively.

library(tidyverse)
library(ggh4x)

# Get car make from mtcars and subset
dat <- mtcars |> 
  mutate(
    vehicle = rownames(mtcars)
  ) |> 
  separate(
    col = vehicle,
    into = c('make', 'trash'),
    sep = ' '
  ) |> 
  filter(make %in% c('Merc', 'Fiat', 'Toyota')) |> 
  select(make, mpg, cyl) |> 
  relocate(make)

# facet_grid fill colors based on car make
make_cols <- c(
  Merc = "orange",
  Fiat = "orange",
  Toyota = "dodgerblue"
)

# make figure
dat |> 
  pivot_longer(
    cols = 2:3,
    names_to = 'variable',
    values_to = 'value'
  ) |> 
  ggplot(aes(x = make, y = value)) +
  geom_point() +
  labs(x = NULL,
       y = NULL) +
  theme_bw(base_size = 18) +
  theme(
    strip.background.y = element_rect(fill = 'white'),
    axis.text.x = element_blank()
  ) +
  ggh4x::facet_grid2(
    rows = vars(variable),
    cols = vars(make),
    strip = ggh4x::strip_themed(
      background_x = ggh4x::elem_list_rect(
        fill = make_cols
      )
    )
  )

Created on 2025-08-14 with reprex v2.1.1


Solution

  • One option would be to fake a legend using an unused aesthetic, e.g. I use fill:

    library(tidyverse)
    library(ggh4x)
    
    # make figure
    p <- dat |>
      pivot_longer(
        cols = 2:3,
        names_to = "variable",
        values_to = "value"
      ) |>
      ggplot(aes(x = make, y = value)) +
      geom_point() +
      labs(
        x = NULL,
        y = NULL
      ) +
      theme_bw(base_size = 18) +
      theme(
        strip.background.y = element_rect(fill = "white"),
        axis.text.x = element_blank()
      ) +
      ggh4x::facet_grid2(
        rows = vars(variable),
        cols = vars(make),
        strip = ggh4x::strip_themed(
          background_x = ggh4x::elem_list_rect(
            fill = make_cols
          )
        )
      )
    
    p +
      geom_point(
        aes(fill = make %in% c("Fiat", "Merc")),
        x = NA, y = NA,
        na.rm = TRUE,
        key_glyph = "rect"
      ) +
      scale_fill_manual(
        values = c("dodgerblue", "orange"),
        labels = c("Japan", "Europe"),
        name = NULL,
        guide = guide_legend(reverse = TRUE)
      ) +
      theme(
        legend.position = "top"
      )