Search code examples
rggplot2ggrepel

ggrepel together with geom_smooth


ggplot(gapminder::gapminder,aes(x=year,y=lifeExp,label=continent,color=continent))+
geom_line(size=.1,alpha=.2)+
guides(color="none")+
theme_minimal()+
geom_smooth(aes(color=continent),se=F,method="loess")+
ggrepel::geom_label_repel(direction = "y",stat="smooth",nudge_x = 5)

Results in the following: enter image description here

I only want one label for each smoothed aggregate for each continent.

I´ve tried tweaking the parameters, but to no help. If I skip the stat="smooth" term from geom_label_repel It goes all haywire and tries to label all the individual lines - not the smoothed lines. Any ideas?


Solution

  • One way you could do this is to get the last (or first etc. as desired) fitted value for each continent in a summary label data frame, then use that in ggrepel:

    library(tidyverse)
    library(gapminder)
    library(ggrepel)
    library(broom)
    
    label_df <- gapminder |> 
      nest(data = -continent) |> 
      mutate(model = map(data, ~loess(lifeExp ~ year, .x)),
             augmented = map(model, augment),
             fitted = map(augmented, ".fitted") |> map_dbl(last),
             year = map(data, "year") |> map_int(last)) |> 
      select(continent, fitted, year)
    
    ggplot(gapminder, aes(year, lifeExp, color = continent)) +
      geom_line(size = .1, alpha = .2) +
      guides(color = "none") +
      theme_minimal() +
      geom_smooth(aes(color = continent), se = F, method = "loess") +
      geom_label_repel(aes(year, fitted, label = continent), data = label_df)
    
    

    Created on 2022-07-03 by the reprex package (v2.0.1)