Search code examples
rggplot2ggrepel

how to control the color of ggrepel segments


Going to try this again with a better MRE...for context, here's the product I'm currently trying to improve

enter image description here

What I'm trying to do is get the lines from the endpoints to the labels to be the same color as the data lines.

For purposes of this question we can work with this script

library(ggplot2)
library(babynames)
library(dplyr)
library(ggrepel)
library(ggsci)

data <- babynames %>%
  filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
  filter(sex=="F")

data <- data %>% group_by(name) %>%
  mutate(change = n - lag(n)) %>% 
  mutate(meanC = mean(change, na.rm = TRUE)) %>%
  ungroup()

data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )  

minYear = min(data$year)
maxYear = max(data$year)

#endpoint layer
Endpoints <- data %>% 
  group_by(name) %>%
  filter(year == max(year)) %>%
  select(year, name, n, label) %>%
  ungroup()
         
namePlot <- data %>%
  ggplot(mapping = aes(x=year, y=n)) +
  geom_line(aes(color=name), show.legend = FALSE) +
  coord_cartesian(xlim = c(minYear, maxYear+10)) +
  scale_color_ucscgb() +
  geom_point(data = Endpoints, size=1.5, shape=21,
            aes(color=name, fill=name), show.legend=FALSE) +
  geom_label_repel(data=Endpoints, aes(label=label),
                  color = c("forestgreen","red")[1+grepl("\\-\\d",Endpoints$label)],
                  show.legend = FALSE,
                  vjust = 0, xlim=c(maxYear+3,maxYear+10), size=3, direction='y')
         
print(namePlot)

which produces this plot

enter image description here

The colors of the labels is controlled by color = c("forestgreen","red")[1+grepl("\\-\\d",Endpoints$label)], so that, in this case, data with a positive value in the label is green and data with a negative value is red. What I'd like to is make the connecting lines from the endpoints to the label boxes be the same color as the data lines, which are controlled by geom_line(aes(color=name),show.legend = FALSE

In the ggrepel docs there is a segment.color parameter that can control the color of the line segment, but it is not an aesthetic. So it appears it has to be "hard-coded" like segment.color="red" which doesn't really help me. I also found this discussion about the issue that seemed to present a solution, but I have been unable to get it to work. Part of the issue there is that it involves scale_color_discrete(aesthetics = c("color", "segment.color")) and I already have scale_color_ucscgb() so I get a warning about replacing scales...

Any guidance would be most appreciated.


Solution

  • Working version based on guidance from @aosmith

    library(ggplot2)
    library(babynames)
    library(dplyr)
    library(ggrepel)
    library(ggsci)
    
    data <- babynames %>%
      filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
      filter(sex=="F")
    
    data <- data %>% group_by(name) %>%
      mutate(change = n - lag(n)) %>% 
      mutate(meanC = mean(change, na.rm = TRUE)) %>%
      ungroup()
    
    data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )  
    
    minYear = min(data$year)
    maxYear = max(data$year)
    
    #endpoint layer
    Endpoints <- data %>% 
      group_by(name) %>%
      filter(year == max(year)) %>%
      select(year, name, n, label) %>%
      ungroup()
    
    namePlot <- data %>%
      ggplot(mapping = aes(x=year, y=n)) +
      geom_line(aes(color=name), show.legend = FALSE) +
      coord_cartesian(xlim = c(minYear, maxYear+15)) +
      geom_point(data = Endpoints, size=1.5, shape=21,
                 aes(color=name, fill=name), show.legend=FALSE) +
      geom_label_repel(data=Endpoints, aes(label=label,
                                           segment.color=name),
                       color = c("forestgreen","red")[1+grepl("\\-\\d",Endpoints$label)],
                       show.legend = FALSE,
                       force = 50, 
                       vjust = 0, xlim=c(maxYear+5,maxYear+12), size=3, direction='y') +
      scale_color_discrete(aesthetics = c("color", "segment.color"))
    
    print(namePlot)
    

    produces

    enter image description here