Lisa P
Lisa P

Reputation: 21

Add text to legend symbols in ggplot

Using geom_rect I am separating my data into classes in a ggplot. These classes (v high, high, medium, low, v low) are denoted in the legend. Is there a possibility to add the lower and upper limits of the classes from the data.frame to the legend symbols?

Here is my set up:

library(ggplot2)
library(viridis)

dat <- data.frame(x = seq(1,100,by=2), y = seq(1,300,by=3))

df <- data.frame(class = c("very high", "high", "medium", "low", "very low"),
            lwr = c(90, 75, 35, 15, 0),
            upr = c(100, 90, 75, 35, 15))

ggplot(dat) + 
  geom_rect(data = df, aes(xmin = lwr, xmax = upr, ymin = -Inf, ymax = Inf, fill = class), alpha = 0.4)+
  geom_point(aes(x, y)) +
  theme_bw()+
  scale_fill_viridis("Classes", discrete = TRUE, option = "viridis", 
                     limits = c("very high", "high", "medium", "low", "very low"))

I would like the legend to follow the following principle: Legend depicting the classes as well as their ranges.

So far, I have only found ways to change the label itself, but no indication on how to add information from the data frame to the legend or how to widen the symbols enough for text to fit in. Do you have any suggestions?

Upvotes: 2

Views: 830

Answers (1)

stefan
stefan

Reputation: 123783

TBMK there is no easy way to achieve your desired result. One option would be to make use of a custom key glyph to add you labels to the legend keys.

To this end

  1. Create a color palette as a named vector and a named vector of key labels. These vectors are used inside the custom key glyph to select the key label based on the value of the fill color via match.

  2. For the custom key glyph I adapted the code from ggplot2::draw_key_label. Basically I added the code to select the key label via match and do some data manipulation on the data object passed to draw_key_text, i.e. I remove the fill column, set the font colour to "black", set the alpha for the text to 1 and the font size to 11pt.

  3. Finally, I use strwidth to compute the width of the legend keys which I set via guide_legend.

library(ggplot2)
library(dplyr)

# Color palette
pal <- scales::viridis_pal(option = "viridis")(5)
names(pal) <- c("very high", "high", "medium", "low", "very low")

# Legend key labels
key_label <- df |>
  mutate(key_label = case_when(
    upr == 100 ~ paste(">", lwr),
    lwr == 0 ~ paste("<", upr),
    TRUE ~ paste(lwr, upr, sep = "-")
  )) |>
  select(class, key_label) |>
  tibble::deframe()

# Legend key width = maximum label * 1.10 to add some padding
width <- unit(max(sapply(key_label, strwidth, units = "inches")) * 1.10, "in")

# Custom key glyph
draw_key_cust <- function(data, params, size) {
  data_text <- data
  data_text$label <- key_label[names(pal)[match(data$fill, pal)]]
  data_text[c("fill")] <- NULL
  data_text$colour <- "black"
  data_text$alpha <- 1
  data_text$size <- 11 / .pt

  grid::grobTree(
    draw_key_rect(data, list()),
    draw_key_text(data_text, list())
  )
}

ggplot(dat) +
  geom_rect(data = df, aes(xmin = lwr, xmax = upr, ymin = -Inf, ymax = Inf, fill = class), alpha = 0.4, key_glyph = "cust") +
  geom_point(aes(x, y)) +
  theme_bw() +
  scale_fill_manual("Classes", values = pal, limits = c("very high", "high", "medium", "low", "very low")) +
  guides(fill = guide_legend(keywidth = width))

Upvotes: 3

Related Questions