0

Assume the following data:

library(tidyverse)
library(ggrepel)
df <- data.frame(name   = rep(letters[1:3], 3),
                 points = c(5, 3, 7, 12, 13, 14, 20, 30, 40),
                 time = rep(c("day 1", "day 2", "day 3"), each = 3))

df2 <- df %>%
  group_by(name) %>%
  mutate(points_sum = cumsum(points)) %>%
  group_by(time) %>%
  mutate(rank = rank(desc(points_sum), ties.method = "min")) %>%
  ungroup() %>%
  mutate(name_colour = case_when(rank == 1 ~ "#336600",
                                 rank == 2 ~ "#339900",
                                 rank == 3 ~ "#66ff33"))

I now want to draw th following plot, i.e. give the names/labels the colour specified in the name_colour column:

df2 %>%
  ggplot(aes(x     = time,
             y     = points_sum,
             group = name,
             label = name)) +
  geom_point() +
  geom_text_repel(direction = "y", size = 10, colour = df2$name_colour) +
  theme_minimal()

Plot without legend

However, this plot is missing a legend for these colours, i.e. I want to add a legend that has the ranks next to the according colour.

I'm not sure how I could manually add such a legend here. I tried to change my code above by the one below (only chenge in the second to last line), but this completely changes the colours of the labels:

df2 %>%
  ggplot(aes(x     = time,
             y     = points_sum,
             group = name,
             label = name)) +
  geom_point() +
  geom_text_repel(direction = "y", size = 10, aes(colour = name_colour)) +
  theme_minimal() 

Plot with legend, but wrong colours

Any ideas?

deschen
  • 10,012
  • 3
  • 27
  • 50

2 Answers2

1

If you want to use the color codes from your dataframe then make use of scale_color_identity. By default this will not give you a legend so you have to add guide = guide_legend():

library(tidyverse)
library(ggrepel)
df <- data.frame(
  name = rep(letters[1:3], 3),
  points = c(5, 3, 7, 12, 13, 14, 20, 30, 40),
  time = rep(c("day 1", "day 2", "day 3"), each = 3)
)

df2 <- df %>%
  group_by(name) %>%
  mutate(points_sum = cumsum(points)) %>%
  group_by(time) %>%
  mutate(rank = rank(desc(points_sum), ties.method = "min")) %>%
  ungroup() %>%
  mutate(name_colour = case_when(
    rank == 1 ~ "#336600",
    rank == 2 ~ "#339900",
    rank == 3 ~ "#66ff33"
  ))

df2 %>%
  ggplot(aes(
    x = time,
    y = points_sum,
    group = name,
    label = name
  )) +
  geom_point() +
  geom_text_repel(aes(color = name_colour), direction = "y", size = 10) +
  scale_color_identity(labels = c("A", "B", "C"), guide = guide_legend()) +
  theme_minimal()

stefan
  • 90,330
  • 6
  • 25
  • 51
1

In general, I think a more typical ggplot approach would be to specify the colours in scale_colour_manual or equivalent, rather than coding them into the data frame itself. For example:

library(ggplot2)
library(dplyr)
library(ggrepel)

data.frame(
        name   = rep(letters[1:3], 3),
        points = c(5, 3, 7, 12, 13, 14, 20, 30, 40),
        time = rep(c("day 1", "day 2", "day 3"), each = 3)
    ) %>%
    group_by(name) %>%
    mutate(points_sum = cumsum(points)) %>%
    group_by(time) %>%
    mutate(rank = factor(rank(desc(points_sum), ties.method = "min"))) %>%
    ungroup() %>%
    ggplot(aes(
            x     = time,
            y     = points_sum,
            group = name,
            label = name)) +
        geom_point() +
        geom_text_repel(direction = "y", size = 10, aes(colour = rank)) +
        theme_minimal() +
        scale_colour_manual(
            values = c("1" = "#336600", "2" = "#339900", "3" = "#66ff33")
        )

plt

heds1
  • 3,203
  • 2
  • 17
  • 32
  • Thanks. Any idea, how I could a) change the names in the legend from 1, 2, 3 to e.g. "1st, 2nd, 3rd" and b) change the "a" symbol in the legend to e.g.a simple dot or a filled box or sth.? I spent the whole afternoon with trying to figure it out, but ggplot defeated me - as always. – deschen Jul 09 '21 at 19:16
  • Sure, if this post answered your question then you can label it as such, and if you have further questions (around legend formatting) then you should make a new question for it. – heds1 Jul 09 '21 at 21:07
  • Sorry, I thought I already upvoted. I know, I should create a new question, but it‘ so closely tied to my question above that I thought an update to my question/the answers might as well do the trick. – deschen Jul 09 '21 at 21:28
  • 1
    Okay, to change the labels you can add `labels = c("1st", "2nd", "3rd")` to the `scale_colour_manual` function. I'm not sure about how to change the "a" symbol though, that seems a bit more tricky. – heds1 Jul 09 '21 at 21:34
  • Yes, I tried like 50 different options. I guess the „a“ is there, because what is shown is text (geom_text_repel) rather than numbers. – deschen Jul 09 '21 at 22:19