How to use position_dodge with preserve = 'single' in geom_text?
I'm trying to label the bars with geom_text. It works in most cases with position_dodge, but for some cases I get plots that look like this. I use preserve = 'single'
to get around the wide bars, but the respective geom_text
does not move to match the bar. I've made it work with position_dodge2()
but I like how the bars are aligned in position_dodge
all the way to the left in this case.
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
geom_bar(aes(y = ..count..), stat = 'count', position = position_dodge(preserve = 'single')) +
geom_text(aes(label = ..count..), stat = 'count', position = position_dodge(width = 1))
The "14" on factor 8 is aligned to the middle instead of to the left. Is there a simple fix to this?
If I switch to position_dodge2
and use preserve = 'single'
it works, but the bar is centered on the x axis. In position_dodge
the bar is left aligned and the missing value is right aligned. If there is a way to use position_dodge2
without sacrificing alignment that would work as well.
Solution 1:
I don't love this, but one possibility is to enumerate the possibilities with tidyr::complete
so that any missing ones get an NA, which will plot with the spacing you want:
library(tidyverse)
mtcars %>%
count(cyl = factor(cyl), vs = factor(vs)) %>%
complete(cyl, vs) %>% # creates "8 cyl / 1 vs / NA n" row
ggplot(aes(cyl, n, fill = vs)) +
geom_col(position = position_dodge(preserve = 'single')) +
geom_text(aes(label = n), position = position_dodge(width = 1))