annotate lines in ggplot using geom_text_repel

107 views Asked by At

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!

1

There are 1 answers

1
stefan On BEST ANSWER

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()`).