Search code examples
rggplot2ggrepel

How do I get this label to point to the leftmost bar?


I tried the following code but instead of showing the label in middle, I want to point it to leftmost (you can see my picture under). Thanks for the help!

library(tidyverse)
library(ggrepel)

mtcars %>% 
  group_by(am, cyl) %>% 
  slice(1) %>% 
  ggplot(aes(x = am, y = mpg, group = cyl, fill = cyl, label = mpg)) + 
  geom_bar(position = "dodge", stat = "identity") +
  geom_label_repel(data = mtcars %>% filter(am == 0, 
                                            cyl == 4) %>% 
                     slice(1),
                   nudge_x = 0.2,
                   nudge_y = 0.3,
                   aes(fill = NULL))

Created on 2019-01-22 by the reprex package (v0.2.1)


Solution

  • This solution will work generally, for any combination of labels.

    First, it seems as if the am variable is a binary factor, so I code it as a factor so the x axis is a little cleaner. In your case, you are looking for position_dodge(width = 1) for your labels, which automatically lines the labels up on top of the corresponding bars. The way I thought was best for subsetting to only the one label you want us ti define a column mpg_lab which is NA for all the labels you don't want. If you change the conditions in the last mutate row you can isolate different labels, or delete that row altogether for all the labels.

    df <- mtcars %>% 
      mutate(am = factor(am)) %>% 
      group_by(am, cyl) %>% 
      slice(1) %>% 
      mutate(mpg_lab = ifelse(am == 0 & cyl == 4, mpg, NA))
    
    df %>% 
      ggplot(aes(x = am, y = mpg, group = cyl, fill = cyl)) + 
      geom_bar(position = "dodge", stat = "identity") + 
      geom_label_repel(data = df, 
                 aes(label = mpg_lab, fill = NULL), position = position_dodge(width = 1), point.padding = NA, ylim = max(df$mpg_lab, na.rm = T) * 1.02)
    

    enter image description here

    A couple of optional things I added was turning off point.padding in geom_label_repel to keep the labels from randomly moving around side-to-side. I also bumped the label up so you can see the arrow by using the ylim argument in there. You can play around with those options if you want something different.