Search code examples
rggplot2geom-bargeom-text

How to use stat="count" to label a bar chart with counts or percentages in ggplot2?


I'm trying to produce a stacked column chart with data labels.

I'm able to produce the chart, but was unable to find a way to input data labels. I have tried geom_text() but it keeps asking me to input a y label (which if you see the ggplot code is not there). I have also tried adding geom_text(stat = "count") but that also gives me an error saying

"Error: geom_text requires the following missing aesthetics: y and label".

PS - i'm aware I need to rename the y axis as percentage. I'm also trying to figure out how to have more contrasting colours

ggplot(property,
       aes(x=Bedrooms.New, fill=Property.Type.)) + 
  geom_bar(position = "fill") + 
  scale_x_discrete(name = "Number of Bedrooms", 
                   limits = sort(factor(unique(property$Bedrooms.New))))

I have added an image below to see what my output is right now!

enter image description here


Solution

  • As the error message is telling you, geom_text requires the label aes. In your case you want to label the bars with a variable which is not part of your dataset but instead computed by stat="count", i.e. stat_count.

    The computed variable can be accessed via ..NAME_OF_COMPUTED_VARIABLE... , e.g. to get the counts use ..count.. as variable name. BTW: A list of the computed variables can be found on the help package of the stat or geom, e.g. ?stat_count

    UPDATE: The dot-dot notation was deprecated in ggplot2 3.4.0. Instead we could or should use after_stat, i.e. use e.g. after_stat(count) instead of ..count..

    Using mtcars as an example dataset you can label a geom_bar like so:

    library(ggplot2)
    
    ggplot(mtcars, aes(cyl, fill = factor(gear))) +
      geom_bar(position = "fill") +
      geom_text(aes(label = after_stat(count)),
        stat = "count", position = "fill"
      )
    

    Two more notes:

    1. To get the position of the labels right you have to set the position argument to match the one used in geom_bar, e.g. position="fill" in your case.

    2. While counts are pretty easy, labelling with percentages is a different issue. By default stat_count computes percentages by group, e.g. by the groups set via the fill aes. These can be accessed via after_stat(prop). If you want the percentages to be computed differently, you have to do it manually.

    As an example if you want the percentages to sum to 100% per bar this could be achieved using after_stat and ave (to compute the percentage per group) like so:

    library(ggplot2)
    
    ggplot(mtcars, aes(cyl, fill = factor(gear))) +
      geom_bar(position = "fill") +
      geom_text(
        aes(label = after_stat(
          scales::percent(
            ave(count, x, FUN = function(x) x / sum(x))
          )
        )),
        stat = "count", position = "fill"
      )