2
votes

I am using ggplot2 to create a stacked bar chart with negative values, and trying to add sum of the parts as label on top of each bar. The code works fine for bars without negative values, but the label when a negative value is present stays inside the bar.

Example:

test = c("Test1", "Test1", "Test1", "Test2", "Test2", "Test2", "Test3", "Test3", "Test3")  
student = c("A", "B", "C", "A", "B", "C", "A", "B", "C")  
value = c(5,5,5,3,3,3,-2,6,7)

dummy = data.frame(test, student, value)

g = ggplot(data=dummy, aes(x=student, y=value, fill=test)) +   
      geom_bar(stat="identity") +   
      scale_fill_manual(values=c("brown4", "steelblue", "goldenrod3")) +
      geom_text(aes(label=value), size =3, position=position_stack(vjust=0.5), colour="white") +
      theme_classic() + 
      theme(text=element_text(family="serif", size=15, colour="black")) +   
      theme(axis.title=element_text(family="serif", size=15, colour="black")) +   
      theme(legend.title = element_blank()) +   
      theme(legend.position = c(0.2, 0.7)) +
      stat_summary(fun.y = sum, aes(label = ..y.., group = student), geom = "text", vjust = -1) +
      scale_y_continuous(limits = c(-4,20))

g

The result is the following chart:

Chart with stacked bars and negative values The sum for the bars without negative value works fine on top of the bar, but the sum for the bar with the negative value (Student A) is in the middle of the red bar.

How can I fix this?

1
Sorry, first time posting here. Edited now.Andre Mazzetto
Major props for providing a nice reproducible example on your very first question. Makes it very easy to help.Gregor Thomas

1 Answers

2
votes

You use fun.y = sum as the summary function, which adds all the y values in the group, including negative values. This gives the correct sum for the label, but a bad position. For the position calculation, we want to calculate a sum of only the values greater than 0.

stat_summary let's us specify up to 3 functions, fun.y, fun.ymin, and fun.ymax. We'll modify fun.y, the position, to be the sum of positive values, and we'll add in a fun.ymax as the regular sum and use that for the label:

g = ggplot(data=dummy, aes(x=student, y=value, fill=test)) +   
      geom_bar(stat="identity") +   
      scale_fill_manual(values=c("brown4", "steelblue", "goldenrod3")) +
      geom_text(aes(label=value), size =3, position=position_stack(vjust=0.5), colour="white") +
      theme_classic() + 
      theme(text=element_text(family="serif", size=15, colour="black")) +   
      theme(axis.title=element_text(family="serif", size=15, colour="black")) +   
      theme(legend.title = element_blank()) +   
      theme(legend.position = c(0.2, 0.7)) +
      stat_summary(fun.y = function(y) sum(y[y > 0]), fun.ymax = sum,
                   aes(label = ..ymax.., group = student), geom = "text", vjust = -1) +
      scale_y_continuous(limits = c(-4,20))
g

enter image description here