2

I am trying to create a box plot with labels for some of the individal data. The box plot is separated by two variables, mapped to x and colour. However when I add labels using geom_text_repel from the ggrepel package (necessary for the real data) they separate by x but not colour. See this minimal reproducible example:

library(ggplot2)
library(ggrepel)

## create dummy data frame
rep_id <- c("a", "a", "b", "b", "c", "c", "d", "d", "e", "e")
dil <- c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2)
bleach_time <- c(0, 24, 0, 24, 0, 24, 0, 24, 0, 24)
a_i <- c(0.1, 0.2, 0.35, 0.2, 0.01, 0.4, 0.23, 0.1, 0.2, 0.5)
iex <- data_frame(rep_id, dil, bleach_time, a_i)
rm(rep_id, dil, bleach_time, a_i)

## Plot bar chart of a_i separated by bleach_time and dil
p <- ggplot(iex, aes(x = as.character(bleach_time), y = a_i, fill = as.factor(dil))) +
geom_boxplot() +
geom_text_repel(aes(label = rep_id, colour = as.factor(dil)), na.rm = TRUE, segment.alpha = 0)

p

enter image description here

As you can see the labels are colour coded, but they are all lined up around the centre of each pair of plots rather than separated by the plots. I've tried nudge_x but that moves all the labels together. Is there a way I can move each set of labels individually?

For comparison here is the plot of my full data set with the outliers labelled - you can see how each set of labels isn't centred around the points it's labelling, complicating interpretation:

enter image description here

Lucy Wheeler
  • 271
  • 3
  • 17
  • 2
    You assigned the color outside the `aes` in your `geom_text_repel`; it needs to go inside to be mapped to an aesthetic – camille May 31 '18 at 12:18
  • You're also missing a comma in that line – camille May 31 '18 at 12:20
  • Thanks for spotting the typo @camille - I've fixed it now. – Lucy Wheeler May 31 '18 at 12:23
  • 2
    Cool, now try giving the text a `position = "dodge"`. Boxplots get dodged automatically--they would just be on top of each other if they didn't--but text doesn't necessarily – camille May 31 '18 at 12:29
  • That threw up an error, but I managed to get it to work with `position = position_dodge(width = 0.9)`. Thank you for your help! If you want to submit that as an answer I can accept it and give you the reputation. – Lucy Wheeler May 31 '18 at 12:39

1 Answers1

1

It looks like geom_text_repel needs position = position_dodge(width = __), not just the position = "dodge" shorthand I'd suggested, hence the error. You can mess around with setting the width; 0.7 looked okay to me.

library(tidyverse)
library(ggrepel)

ggplot(iex, aes(x = as.character(bleach_time), y = a_i, fill = as.factor(dil))) +
  geom_boxplot() +
  geom_text_repel(aes(label = rep_id, colour = as.factor(dil)), na.rm = TRUE, 
    segment.alpha = 0, position = position_dodge(width = 0.7))

Since you're plotting distributions, it might be important to keep positions along the y-axis the same, and only let geom_text_repel jitter along the x-axis, so I repeated the plot with direction = "x", which made me notice something interesting...

ggplot(iex, aes(x = as.character(bleach_time), y = a_i, fill = as.factor(dil))) +
  geom_boxplot() +
  geom_text_repel(aes(label = rep_id, colour = as.factor(dil)), na.rm = TRUE, 
    segment.alpha = 0, position = position_dodge(width = 0.7), direction = "x")

There are a couple texts being obscured by the fact that they have the same color as the fill of the boxplots! You can fix this with a better combination of color + fill palettes. The quick fix I did was turning down the luminosity of the color and turning up the luminosity of the fill in the scale_*_discrete calls to make them distinct (but also pretty ugly).

ggplot(iex, aes(x = as.character(bleach_time), y = a_i, fill = as.factor(dil))) +
  geom_boxplot() +
  geom_text_repel(aes(label = rep_id, colour = as.factor(dil)), na.rm = TRUE, 
    segment.alpha = 0, position = position_dodge(width = 0.7), direction = "x") +
  scale_color_discrete(l = 30) +
  scale_fill_discrete(l = 100)

Note that you can also adjust the force used in the repel, so if you need the labels to not overlap but to also hug closer to the middles of the boxplots, you can mess around with that setting as well.

camille
  • 16,432
  • 18
  • 38
  • 60