Search code examples
rggplot2geom-bargeom-text

How to adjust position of geom_text() with counts of zero for bars of barplot with geom_bar() in different groups?


I'm trying to add values at the top of my bars of a barchart with two groups. It works fine for values above zero. But I have also levels where there were no counts, so bars with the hight of 0. Then the text on top of the bar with counts is in the middle instead of right above the bar. And the place with count 0 has no indication.

Here's a data set:

vec.feed1.sorted <- c(rep(2,1), rep(3,2), rep(4,7), rep(5,15), rep(6,30), rep(7,40))
vec.feed1 <- sample(vec.feed1.sorted)
set.seed(001)
vec.feed1

df.feedback <- data.frame(
    study = factor(c(rep(1,62),rep(2,33)), levels=c("1","2")),
    feed1 = factor(vec.feed1, levels=as.character(c(1:7)))
  )
df.feedback

And this is what I did so far:

ggplot(data = df.feedback, 
       aes(x = factor(feed1, levels = 1:7, labels = labels.feed1),
           fill = factor(study))) +
  geom_bar(aes(y = after_stat(count / ave(count, fill, FUN = sum))), 
           position = position_dodge(preserve="single")) +
  scale_fill_manual(
    values = c("grey40", "grey60"),
    name = "event location",
    labels = c("university", "cinema")) +
  geom_text(aes(y = after_stat(count / ave(count, fill, FUN = sum)),
                label = after_stat(scales::percent(count / ave(count, fill, FUN = sum), accuracy = 1))),
            stat = "count", position = position_dodge(width=0.9), vjust = -0.5) +
  ylab("percent of audience relative to location") +
  xlab("How did you like this event?") +
  theme(axis.text.x = element_text(angle = 45, hjust = .9)) +
  #theme(axis.ticks.x = element_blank()) +
  scale_y_continuous(labels = scales::percent, limits = c(0, 0.51)) +
  scale_x_discrete(drop = FALSE) +
  theme(
    panel.border = element_rect(linetype = "solid", colour = "black", linewidth = .5, fill = NA),
    panel.grid.minor = element_line(colour = "grey93", linewidth = .3),
    panel.grid.major.y = element_line(colour = "grey93", linewidth = .3),
    panel.background = element_rect(fill = "grey97")
  ) +
  theme(axis.title.x.bottom = element_text(margin = margin(t = .15, unit = "in")))

This is the plot I get:

enter image description here

I would like to have the "2%" and "3%" right in the middle above the bar.

I would love if you could help me with this. Best, H.


Solution

  • You can use annotate to manually add labels where you want.

    library(tidyverse)
    
    set.seed(001)
    
    vec.feed1.sorted <- c(rep(2,1), rep(3,2), rep(4,7), rep(5,15), rep(6,30), rep(7,40))
    vec.feed1 <- sample(vec.feed1.sorted)
    
    df.feedback <- data.frame(
      study = factor(c(rep(1,62),rep(2,33)), levels=c("1","2")),
      feed1 = factor(vec.feed1, levels=as.character(c(1:7)))
    )
    
    ggplot(data = df.feedback, 
           aes(x = factor(feed1, levels = 1:7),
               fill = factor(study))) +
      geom_bar(aes(y = after_stat(count / ave(count, fill, FUN = sum))), 
               position = position_dodge(preserve="single")) +
      scale_fill_manual(
        values = c("grey40", "grey60"),
        name = "event location",
        labels = c("university", "cinema")) +
      annotate('text',
               x = c(1.8,2.8,3.8,4.2,4.8,5.2,5.8,6.2,6.8,7.2),
               y = c(0.05,0.05,0.09,0.11,0.18,0.17,0.28,0.44,0.50,0.32),
               label = c('3%','3%','6%','9%','16%','15%','26%','42%','48%','30%')) + # make adjustments to position and labels here
      ylab("percent of audience relative to location") +
      xlab("How did you like this event?") +
      theme(axis.text.x = element_text(angle = 45, hjust = .9)) +
      scale_y_continuous(labels = scales::percent, limits = c(0, 0.51)) +
      scale_x_discrete(drop = FALSE) +
      theme(
        panel.border = element_rect(linetype = "solid", colour = "black", linewidth = .5, fill = NA),
        panel.grid.minor = element_line(colour = "grey93", linewidth = .3),
        panel.grid.major.y = element_line(colour = "grey93", linewidth = .3),
        panel.background = element_rect(fill = "grey97")
      ) +
      theme(axis.title.x.bottom = element_text(margin = margin(t = .15, unit = "in")))
    

    Created on 2024-07-01 with reprex v2.1.0