rggplot2annotationsggrepel

annotate lines in ggplot using geom_text_repel


I am trying to annotate lines in ggplot using geom_text_repel. However, the annotation for some lines is not showing up. How to fix that?

Here is a reproducible example:

library(ggplot2)
library(ggrepel)
df.1 <-
  data.frame(
    id = rep(c(1, 2, 3),each = 4),
    time = c(1, 2, 3, 4),
    x = c(1, 2, 3, 4),
    y = c(10, 23, 25, 28),
    z = c(2, 4, NA, NA)
  )

df.long <- df.1 %>% pivot_longer(cols = c(x, y, z), names_to = "class", values_to = "score")

ggplot(df.long, aes(x = time, y = score, col = class, group = class)) +
  geom_line() +
  geom_point() +
  geom_text_repel(
    data = subset(df.long, time == max(time)),
    aes(label = class),
    size = 2,
    point.padding = 0.2, 
    nudge_x = .3,
    segment.curvature = -1e-20,
    arrow = arrow(length = unit(0.015, "npc"))
  )

enter image description here The annotation for z is not showing. Also, how can I reduce the annotation to one per line? Right now it has three. Many thanks!


Solution

  • You have to filter the data for the maximum time with a non-missing value per class. Also, as there are multiple values (one per id) per time and class you get multiple labels. Hence, if you only one label get rid of the duplicates using e.g. dplyr::distinct:

    library(dplyr, warn=FALSE)
    library(ggplot2)
    library(ggrepel)
    
    df_labels <- df.long |>
      drop_na() |> 
      filter(time == max(time), .by = class) |> 
      distinct(time, class, score)
    
    ggplot(df.long, aes(x = time, y = score, col = class, group = class)) +
      geom_line() +
      geom_point() +
      geom_text_repel(
        data = df_labels,
        aes(label = class),
        size = 2,
        point.padding = 0.2,
        nudge_x = .3,
        arrow = arrow(length = unit(0.015, "npc"))
      )
    #> Warning: Removed 6 rows containing missing values (`geom_line()`).
    #> Warning: Removed 6 rows containing missing values (`geom_point()`).