Search code examples
rggplot2bar-chartstacked-bar-chart

Showing data values on stacked bar chart in ggplot2


I'd like to show data values on stacked bar chart in ggplot2. Here is my attempted code

library(ggplot2)

Data <- data.frame(
  Year = c(rep(c("2006-07", "2007-08", "2008-09", "2009-10"), each = 4)),
  Category = c(rep(c("A", "B", "C", "D"), times = 4)),
  Frequency = c(168, 259, 226, 340, 216, 431, 319, 368, 423, 645, 234, 685, 166, 467, 274, 251)
)

ggplot(Data, aes(Year, Frequency, fill = Category)) +
  geom_col() +
  geom_text(aes(label = Frequency), size = 3, hjust = 0.5, vjust = 3, position = "stack")

Created on 2023-04-07 with reprex v2.0.2

I'd like to show these data values in the middle of each portion. Any help in this regard will be highly appreciated. Thanks


Solution

  • From ggplot 2.2.0 labels can easily be stacked by using position = position_stack(vjust = 0.5) in geom_text.

    ggplot(Data, aes(x = Year, y = Frequency, fill = Category, label = Frequency)) +
      geom_bar(stat = "identity") +
      geom_text(size = 3, position = position_stack(vjust = 0.5))
    

    enter image description here

    Also note that "position_stack() and position_fill() now stack values in the reverse order of the grouping, which makes the default stack order match the legend."


    Answer valid for older versions of ggplot:

    Here is one approach, which calculates the midpoints of the bars.

    library(ggplot2)
    library(plyr)
    
    # calculate midpoints of bars (simplified using comment by @DWin)
    Data <- ddply(Data, .(Year), 
       transform, pos = cumsum(Frequency) - (0.5 * Frequency)
    )
    
    # library(dplyr) ## If using dplyr... 
    # Data <- group_by(Data,Year) %>%
    #    mutate(pos = cumsum(Frequency) - (0.5 * Frequency))
    
    # plot bars and add text
    p <- ggplot(Data, aes(x = Year, y = Frequency)) +
         geom_bar(aes(fill = Category), stat="identity") +
         geom_text(aes(label = Frequency, y = pos), size = 3)
    

    Resultant chart