0

Data and Previous Content

This question is a continuation of a previous question with the same data but with a slight tweak.

Question

Same as before, this is the example I am looking to achieve, with the part I want now highlighted in green:

enter image description here

Instead of coloring a specific regression line, now I want to add a direct label to the plot window like above. I know that by faceting the data, we can achieve this with a legend, coloring the lines, etc. We can even manually add an annotation by selecting the x and y coordinates with annotate or geom_text.

But I want something that doesn't require a legend or manually figuring out where the exact geom coordinates are. Is there a way to simply add the label to a regression line within the plot window similar to other aes functions? This is the base plot I have so far, with the label now removed and regression lines colored:

ggplot(slack.work,
       aes(x=Coffee_Cups,
           y=Mins_Work,
           color=Month_Name))+
  geom_point(alpha = .4)+
  geom_smooth(method = "lm",
              se = F)+
  scale_colour_viridis_d()+
  theme_bw()+
  labs(title = "Coffee Cups x Minutes of Productivity",
       subtitle = "Pearson r = .30, p < .001",
       x="Cups of Coffee",
       y="Minutes of Work",
       color="Month")+
  theme(plot.title = element_text(face = "bold",
                                  size = 15,
                                  family = "mono"),
        plot.subtitle = element_text(face = "italic"),
        legend.position = "none")

Currently, it looks like this:

enter image description here

But I would like for it to look something like this:

enter image description here

Shawn Hemelstrand
  • 2,676
  • 4
  • 17
  • 30

1 Answers1

1

Adapting this answer to your case you could achieve your desired result by using stat="smooth" via geom_text or ggrepel::geom_text_repel. The tricky part is to get only one label for which I use an ifelse inside after_stat:

library(ggplot2)

# Levels of Month_Name. 
# Needed to get the month names.
# When using after_stat only get the level number via `group`
levels_month <- levels(factor(slack.work$Month_Name))

ggplot(
  slack.work,
  aes(
    x = Coffee_Cups,
    y = Mins_Work,
    group = Month_Name,
    color = Month_Name == "January"
  )
) +
  geom_point(alpha = .4) +
  geom_smooth(
    data = ~subset(.x, !Month_Name == "January"),
    method = "lm",
    se = F
  ) +
  geom_smooth(
    data = ~subset(.x, Month_Name == "January"),
    method = "lm",
    se = F
  ) +
  ggrepel::geom_text_repel(aes(label = after_stat(ifelse(x %in% range(x)[1], levels_month[group], NA_character_))), 
                            stat = "smooth", method = "lm",
                            nudge_x = -.5, direction = "y") +
  scale_x_continuous(expand = expansion(add = c(.5, 0), mult =.05)) +
  scale_colour_manual(values = c("TRUE" = "steelblue", "FALSE" = "grey65")) +
  annotate("text",
           x = 3,
           y = 800,
           label = "January had the strongest effect on productivity.",
           size = 4,
           color = "steelblue"
  ) +
  theme_bw() +
  labs(
    title = "Coffee Cups x Minutes of Productivity",
    subtitle = "Pearson r = .30, p < .001",
    x = "Cups of Coffee",
    y = "Minutes of Work",
    color = "Month"
  ) +
  theme(
    plot.title = element_text(
      face = "bold",
      size = 15,
      family = "mono"
    ),
    plot.subtitle = element_text(face = "italic")
  ) +
  guides(color = "none")

enter image description here

EDIT To get rid of the segments connecting the line and the label you could add min.segment.length = Inf to geom_text_repel:

... +
ggrepel::geom_text_repel(aes(label = after_stat(ifelse(x %in% range(x)[1], levels_month[group], NA_character_))), 
                            stat = "smooth", method = "lm", min.segment.length = Inf,
                            nudge_x = -.5, direction = "y") +
...

enter image description here

stefan
  • 90,330
  • 6
  • 25
  • 51
  • I like this answer. One minor thing...is there a way to remove the arrows linking the names to the regression lines? I'm assuming they are there because the lines are close to each other. Not the biggest issue in the world but just curious. – Shawn Hemelstrand Jul 15 '22 at 12:33
  • Hi Shawn. Yes. Of course could we get rid of the "segments". See my edit. – stefan Jul 15 '22 at 13:16