Search code examples
rggplot2geom-textgghighlight

Add legend labels to the right of each line in a ggplot2 line chart


I'm building a line chart and I'd like the (markdown-formatted) legend labels to be displayed right next to the last data point for each line; something like this:

enter image description here

What I've tried:

First attempt: using geom_text but there are some issues:

  • the label is repeated along each data point
  • the label is part of the plot, rather than being a legend (so it won't extend past the panel)
  • the text is not formatted
dat <- data.frame(
    date = c(1:5, 1:5),
    type = rep(c("*Paella* eating", "*Pho* eating"), each = 5),
    value = c(15, 28, 36, 49, 47,
              25, 35, 31, 24, 24))

library(ggplot2)

dat |>
    ggplot(aes(date, value, colour = type)) +
    geom_line() +
    geom_text(aes(label = type)) +
    theme(legend.text = ggtext::element_markdown()) +
    gghighlight::gghighlight(type %in% dat$type)

Second strategy: using gghighlight, however

  • unable to format the text with md
  • the label is part of the plot, rather than being a legend (so it won't extend past the panel)
  • the label partially hides the line
dat |>
    ggplot(aes(date, value, colour = type)) +
    geom_line() +
    gghighlight::gghighlight(type %in% dat$type) +
    theme(strip.text = ggtext::element_markdown())

Created on 2022-10-26 with reprex v2.0.2


Solution

  • As you want markdown text IMHO the ggtext package is the way to go, i.e. use ggtext::geom_richtext instead of geom_text or geom_label. To avoid duplicated entries use a filtered dataset for the labels. The rest is styling and e.g. making some room for the labels by increasing the plot.margin.

    library(ggplot2)
    library(ggtext)
    
    dat_label <- subset(dat, date == max(date))
    
    dat |>
      ggplot(aes(date, value, colour = type)) +
      geom_line() +
      geom_richtext(data = dat_label, aes(label = type), color = "black", 
                    label.size = NA,
                    label.margin = unit(4, "pt"),
                    label.padding = unit(3, "pt"),
                    hjust = 0, show.legend = FALSE) +
      coord_cartesian(clip = "off") +
      theme(plot.margin = margin(5.5, 66, 5.5, 5.5)) +
      guides(color = "none")