jerH
jerH

Reputation: 1299

Text color with geom_label_repel

Not specific to any particular piece of code, is there a relatively straightforward way to change the color of the text in a geom_label_repel box?

Specifically, I have code that produces the below chart

enter image description here

The percentage in the label box is the percent change in 7-day moving average for the most recent week over the week prior. I'd simply like to color the text red when the value is positive and green when it is negative.

The dataframe for this chart can be copied from here.

The plot code is

#endpoint layer
BaseEndpoints <- smDailyBaseData %>% filter(Base %in% AFMCbases) %>%
  group_by(Base) %>%
  filter(DaysSince == max(DaysSince)) %>%
  select(Base, abbv, DaysSince, newRate,label) %>%
  ungroup()

ZoomEndpoints <- BaseEndpoints %>% filter(Base != 'Edwards') %>%
  mutate(zoom = TRUE)
CAEndPoint <- BaseEndpoints %>% filter(Base == 'Edwards') %>%
  mutate(zoom = FALSE)

ZoomEndpoints <- rbind(ZoomEndpoints, CAEndPoint)

BasePlot <- smDailyBaseData %>% filter(Base %in% AFMCbases) %>%
  ggplot(mapping = aes(x = as.numeric(DaysSince), y = newRate)) +
  geom_line(aes(color=abbv),show.legend = FALSE) +
  scale_color_ucscgb() +
 geom_point(data = BaseEndpoints,size = 1.5,shape = 21, 
            aes(color = abbv,fill = abbv), show.legend = FALSE) +
 geom_label_repel(data=ZoomEndpoints, aes(label=label), show.legend = FALSE,
                   vjust = 0, xlim=c(105,200), size=3, direction='y') +
  labs(x = "Days Since First Confirmed Case", 
       y = "% Local Population Infected Daily") +
  theme(plot.title = element_text(size = rel(1), face = "bold"),
        plot.subtitle = element_text(size = rel(0.7)),
        plot.caption = element_text(size = rel(1))) +
  facet_zoom(xlim = c(50,120), ylim=c(0,0.011),zoom.data=zoom)



print(BasePlot)

Upvotes: 2

Views: 5879

Answers (2)

Ian Campbell
Ian Campbell

Reputation: 24770

Here's a bit of a hacky solution since you can't have two scale_color_*'s at the same time:

The approach centers on manually assigning the color outside of aes in the geom_label_repel call. Adding one to the grepl result that searches for the minus sign in the label allows you to subset the two colors. You need two colors for each label, I assume for the box and for the text, so I used rep.

smDailyBaseData %>% 
ggplot(mapping = aes(x = as.numeric(DaysSince), y = newRate)) +
  geom_line(aes(color=abbv),show.legend = FALSE) +
  scale_color_ucscgb() +
 geom_point(data = BaseEndpoints,size = 1.5,shape = 21, 
            aes(color = abbv,fill = abbv), show.legend = FALSE) +
 geom_label_repel(data=ZoomEndpoints, aes(label=label),
     color = rep(c("green","red")[1+grepl("\\-\\d",as.factor(ZoomEndpoints$label))],times = 2),
     show.legend = FALSE, vjust = 0, xlim=c(105,200),
     size=3, direction='y') +
 labs(x = "Days Since First Confirmed Case", 
       y = "% Local Population Infected Daily") +
 theme(plot.title = element_text(size = rel(1), face = "bold"),
        plot.subtitle = element_text(size = rel(0.7)),
        plot.caption = element_text(size = rel(1))) +
 facet_zoom(xlim = c(50,120), ylim=c(0,0.011),zoom.data=zoom)

enter image description here

Data Setup

#source("https://pastebin.com/raw/Vn2abQ4a")
BaseEndpoints <- smDailyBaseData %>% 
  group_by(Base) %>%
  dplyr::filter(DaysSince == max(DaysSince)) %>%
  dplyr::select(Base, abbv, DaysSince, newRate,label) %>%
  ungroup()
ZoomEndpoints <- BaseEndpoints %>% filter(Base != 'Edwards') %>%
  mutate(zoom = TRUE)
CAEndPoint <- BaseEndpoints %>% filter(Base == 'Edwards') %>%
  mutate(zoom = FALSE)
ZoomEndpoints <- rbind(ZoomEndpoints, CAEndPoint)

Upvotes: 3

Allan Cameron
Allan Cameron

Reputation: 173793

Yes, it's as simple as this:

library(ggplot2)

df <- data.frame(x = c(-1, -1, 1, 1), y = c(-1, 1, 1, -1), value = c(-2, -1, 1, 2))

ggplot(df, aes(x, y)) + 
  geom_point(size = 3) +
  ggrepel::geom_label_repel(aes(label = value, colour = factor(sign(value)))) +
  lims(x = c(-100, 100), y = c(-100, 100))  +
  scale_colour_manual(values = c("red", "forestgreen"))

enter image description here


EDIT

Now we have a more concrete example, I can see the problem more clearly. There are workarounds such as using ggnewscale or a hand-crafted solution such as Ian Campbell's thorough example. Personally, I would just note that you haven't used the fill scale yet, and this looks pretty good to my eye:

enter image description here

Upvotes: 5

Related Questions