1

I have a large dataset, which can be exemplified using the below mwe

df <- data.frame("x" = c(1,1,1,2),"value" = c(4,3,5,1), "groupA" = c("A","B","A","B"), "groupB" = c("X","Y","Y","Y"))
df$value <- ifelse(df$groupB == "Y", -df$value, df$value)

I need to plot this, where one group yields fill, another whether it is above or below the x-axis. This can be done as follows:

ggplot(df,aes(x=x,y=value,fill=groupA))+
    geom_bar(stat="identity")+

This yields the sum of values in each groupB above and below zero, and color codes the bars nicely:

mwe bar chart

enter image description here

However, I also need the count in each instance printed as labels above each bar. Using Aniko's suggestion like so:

 ggplot(df,aes(x=x,y=value,fill=groupA))+
      geom_bar(stat="identity")+
      geom_text(aes(label=..count..,group=x,y=..count..), vjust=0,stat="count")

yields this:

bar chart w. labels

enter image description here

As you can see the position of the label is defined by the count. I have tried to set y=value, or y=5 (as an example) but this results in an error message.

How can I solve this?

(edited after zx8754 responded)

zx8754
  • 52,746
  • 12
  • 114
  • 209
  • Update your value to negative when groupB is Y `df$value <- ifelse(df$groupB == "Y", -df$value, df$value)`, then you will need to call geom_bar only once: `ggplot(df,aes(x = x, y = value, fill = groupA)) + geom_bar(stat = "identity")`, then see linked post to add counts. – zx8754 Oct 20 '21 at 09:06
  • Thank you, zx8754. However, the solution in the linked post positions the labels incorrectly, they get positioned according to the count, not value or height of the bar. So far I have been unable to position them correctly. – Vegar Ottesen Oct 20 '21 at 09:41

3 Answers3

0

I mean, it's not pretty, but it works...

library(dplyr)
library(ggplot2)
df %>% 
  group_by(x) %>% 
  mutate(count = ifelse(row_number() == 1, n(), NA)) %>% 
  ggplot(aes(x = x, y = value,fill = groupA))+
    geom_col() +
    geom_text(aes(label = count, x = x, y = value))

Returns:

enter image description here

dario
  • 6,415
  • 2
  • 12
  • 26
0

If I understand the problem correctly we can use nudge:

ggplot(df,aes(x=x,y=value,fill=groupA))+
  geom_bar(stat="identity")+
  geom_text(aes(label=..count..,group=x,y=..count..),
  nudge_y = c(1.4,3.3), stat="count")

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209
user12256545
  • 2,755
  • 4
  • 14
  • 28
  • This would not help if values were much higher or lower than the count, and as you can see the 1 above bar 2 is quite high above the bar itself. – Vegar Ottesen Oct 20 '21 at 11:08
0

As we are flipping some values to negative, the count will not match with text position, so we manually define new y values for text:

library(ggplot2)
library(dplyr)

df %>% 
  group_by(X = as.factor(x)) %>% 
  mutate(Y = ifelse(groupB == "Y", -value, value),
         label = n(),
         Ylabel = sum(Y[ Y > 0 ])) %>% 
  ggplot(aes(x = X, y = Y, fill = groupA)) + 
  geom_bar(stat = "identity") +
  geom_text(aes(y = Ylabel, label = label), vjust = -0.5)

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209