21

How do I draw the sum value of each class (in my case: a=450, b=150, c=290, d=90) above the stacked bar in ggplot2? Here is my code:

#Data
hp=read.csv(textConnection(
"class,year,amount
a,99,100
a,100,200
a,101,150
b,100,50
b,101,100
c,102,70
c,102,80
c,103,90
c,104,50
d,102,90"))
hp$year=as.factor(hp$year)

#Plotting
p=ggplot(data=hp)  
p+geom_bar(binwidth=0.5,stat="identity")+  
aes(x=reorder(class,-value,sum),y=value,label=value,fill=year)+
theme()
David Robinson
  • 77,383
  • 16
  • 167
  • 187
swchen
  • 643
  • 2
  • 8
  • 24
  • 1
    You have a column `amount` in the data but `-value` in the aesthetics; shouldn't those be the same? – David Robinson Jun 05 '15 at 01:23
  • Indeed. I tried to edit to fix the example, but the edit was rejected... The `aes` call should be: `aes(x=reorder(class,-amount,sum),y=amount,label=amount,fill=year)+` – Keith Hughitt Jul 01 '16 at 15:54
  • [Very related](https://stackoverflow.com/questions/44691580/can-i-use-geom-text-or-similar-to-add-group-by-sum-rather-than-amending-original/44691975#44691975) – Axeman Oct 31 '19 at 19:20

2 Answers2

37

You can use the built-in summary functionality of ggplot2 directly:

ggplot(hp, aes(reorder(class, -amount, sum), amount, fill = year)) +
  geom_col() +
  geom_text(
    aes(label = after_stat(y), group = class), 
    stat = 'summary', fun = sum, vjust = -1
  )

enter image description here

Axeman
  • 32,068
  • 8
  • 81
  • 94
35

You can do this by creating a dataset of per-class totals (this can be done multiple ways but I prefer dplyr):

library(dplyr)
totals <- hp %>%
    group_by(class) %>%
    summarize(total = sum(value))

Then adding a geom_text layer to your plot, using totals as the dataset:

p + geom_bar(binwidth = 0.5, stat="identity") +  
    aes(x = reorder(class, -value, sum), y = value, label = value, fill = year) +
    theme() +
    geom_text(aes(class, total, label = total, fill = NULL), data = totals)

You can make the text higher or lower than the top of the bars using the vjust argument, or just by adding some value to total:

p + geom_bar(binwidth = 0.5, stat = "identity") +  
    aes(x = reorder(class, -value, sum), y = value, label = value, fill = year) +
    theme() +
    geom_text(aes(class, total + 20, label = total, fill = NULL), data = totals)

enter image description here

David Robinson
  • 77,383
  • 16
  • 167
  • 187