Home > OS >  How to include labels for a segmented geom_smooth in r?
How to include labels for a segmented geom_smooth in r?

Time:10-30

I would like to label my geom_smooth in r but the labels are closer to the actual points, and not to the lines.

Data:

df <- structure(list(t = c(45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 
47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 
50, 50, 50, 50, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 
53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56, 56, 
56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 59, 59, 59, 59, 
59, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 
63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65), 
    x = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), name = c("P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4", "P1", "P2", "P2 ", "P3", "P4", "P1", "P2", 
    "P2 ", "P3", "P4"), value = c(48L, 132L, 111L, 115L, 2L, 
    58L, 126L, 82L, 74L, 0L, 45L, 119L, 78L, 87L, 0L, 56L, 106L, 
    105L, 88L, 1L, 52L, 78L, 91L, 107L, 1L, 35L, 96L, 86L, 98L, 
    1L, 61L, 118L, 90L, 108L, 2L, 45L, 114L, 93L, 98L, 2L, 55L, 
    108L, 78L, 76L, 7L, 44L, 97L, 94L, 96L, 0L, 40L, 111L, 93L, 
    88L, 1L, 43L, 78L, 66L, 113L, 2L, 20L, 57L, 84L, 41L, 0L, 
    17L, 51L, 81L, 34L, 0L, 40L, 55L, 64L, 32L, 0L, 25L, 67L, 
    71L, 37L, 0L, 16L, 67L, 60L, 57L, 0L, 23L, 46L, 62L, 47L, 
    1L, 34L, 75L, 68L, 39L, 0L, 34L, 60L, 85L, 24L, 0L, 20L, 
    58L, 63L, 37L, 1L)), row.names = c(NA, -105L), class = c("tbl_df", 
"tbl", "data.frame"))

My code:

df %>% 
  group_by(name) %>% 
  # New column to label the first and last values
  mutate(label =
           case_when(
             t == min(t) | t == max(t) ~ name,
             TRUE ~ NA_character_)) %>% 
  ggplot(aes(x = t, y = value, color = name, group = interaction(x, name), shape = name))  
  geom_smooth(se = F)  
  geom_vline(xintercept = 57, linetype = "dashed", lwd = 0.3)   
  scale_color_discrete(guide = 'none')  
  geom_label_repel(aes(label = label))

My graph: enter image description here

Also, is it possible to get rid of the lines pointing to the smoothed loess curves?

CodePudding user response:

One option to achieve your desired result would be to use stat="smooth" in ggrepel::geom_label_repel. Doing so will put the labels on the fitted points instead of on the data points. However, to make this work you have to add the labels on the fly inside geom_label_repel using e.g. after_stat(ifelse(x %in% range(x), color, NA_character_)):

library(ggplot2)
library(ggrepel)

ggplot(df, aes(x = t, y = value, color = name, group = interaction(x, name), shape = name))  
  geom_smooth(se = F)  
  geom_vline(xintercept = 57, linetype = "dashed", lwd = 0.3)  
  scale_color_discrete(guide = "none")  
  ggrepel::geom_label_repel(aes(label = after_stat(ifelse(x %in% range(x), color, NA_character_))), stat = "smooth")
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> Warning: Removed 790 rows containing missing values (geom_label_repel).

  • Related