How to use directlabels to label lines in ggplot2

176 Views Asked by At
library(ggplot2)
library(directlabels)
mydat <- structure(list(Name = c("Ana", "Josh", "Bart", "Ana", "Josh", 
"Bart"), color_line = c("purple", "purple", "orange", "purple", 
"purple", "orange"), x = c(0.864864864864865, 0.810810810810811, 
0.472972972972973, 0.851351351351351, 0.702702702702703, 0.648648648648649
), y = c(0.702702702702703, 0.675675675675676, 0.797297297297297, 
0.797297297297297, 0.72972972972973, 0.635135135135135), Class = c("A", 
"A", "A", "B", "B", "B")), class = c("data.table", "data.frame"
), row.names = c(NA, -6L))

mydat
   Name color_line         x         y Class
1:  Ana     purple 0.8648649 0.7027027     A
2: Josh     purple 0.8108108 0.6756757     A
3: Bart     orange 0.4729730 0.7972973     A
4:  Ana     purple 0.8513514 0.7972973     B
5: Josh     purple 0.7027027 0.7297297     B
6: Bart     orange 0.6486486 0.6351351     B

I have the above data set, and I plotted the results as follows:

g <- ggplot(mydat, aes(x = x, y = y, color = Class)) + 
       theme_classic() + 
       geom_line(mapping = aes(group = Name), color = mydat$color_line) + 
       geom_point() + 
       scale_color_manual(values=c("springgreen4", "royalblue3"))
g

enter image description here

Now, I would like to add the Name of each individual to each line. Something that might look like this:

enter image description here

The closest thing that I found is the angled.boxes in library(directlabels). You can see how it looks here.

However, when I tried the following, I got a different plot.

direct.label(g, "angled.boxes")

enter image description here

2

There are 2 best solutions below

2
On BEST ANSWER

One option to achieve your desired result would be to use the geomtextpath package which adds lots of options to add direct labels to lines and even allows for curved text. For your use case you could simply replace geom_line by geomtextpath::geom_textline to add your labels.

Note: Additionally I slightly adjusted your code to make use of the color aes for the lines and the fill aes to color the points.

library(ggplot2)
library(geomtextpath)

pal_color <- c("purple", "purple", "orange")
names(pal_color) <- c("Ana", "Josh", "Bart")

pal_fill <- c("springgreen4", "royalblue3")
names(pal_fill) <- c("A", "B")

base <- ggplot(mydat, aes(x = x, y = y)) + 
  scale_color_manual(values = pal_color) +
  scale_fill_manual(values= pal_fill) +
  theme_classic() +
  guides(color = "none")

base +
  geomtextpath::geom_textline(
    aes(group = Name, color = Name, label = Name), textcolour = "black") +
  geom_point(aes(fill = Class), shape = 21, stroke = 0, size = 2)

Or using the offset and gap arguments you could add the labels on top of the lines:

base +
  geomtextpath::geom_textline(
    aes(group = Name, color = Name, label = Name),
    offset = unit(5, "pt"), gap = FALSE, textcolour = "black") +
  geom_point(aes(fill = Class), shape = 21, stroke = 0, size = 2)

0
On

It's not ideal, but I did this a long time ago using some math and manual adjustments

mydat %>% 
  group_by(Name) %>% 
  mutate(
    posx = mean(x)*1.01,
    posy = mean(y)*1.01,
    angle = -60*diff(range(y))/diff(range(x))
    ) %>% 
  ggplot(aes(x = x, y = y, color = Class)) + theme_classic() +
  geom_line(mapping = aes(group = Name), color = mydat$color_line) +
  geom_point() + scale_color_manual(values=c("springgreen4", "royalblue3"))+
  geom_text(aes(x = posx, y = posy, group = Name, label = Name, angle = angle),
            size = 6, show.legend = FALSE, color = "black")

enter image description here