Home > Enterprise >  geom_text label using nudge_y with reactive bar chart
geom_text label using nudge_y with reactive bar chart

Time:11-12

I have a simple bar chart I am using in a shiny application with some filters. I am using the following code.

ggplot(users_by_month(), aes(x = month, y = n))  
    geom_bar(stat = "identity")  
    geom_text(aes(label=n), nudge_y = 4) 

When no filters are being used this works and the sum of each month is above the bar. However when I use a filter and the values change the sums above the bars move to much higher above the bar. Is there a way to keep the nudge_y relative to the bar height so the text remains right above the bar as the underlying data changes?

CodePudding user response:

You can achieve it by overriding the y aes with a computed derived stat (here n 10% of the max n):

library(ggplot2)
library(dplyr)

iris %>% 
  group_by(length= cut(Petal.Length, seq(5))) %>% 
  count() %>% 
  ggplot(aes(x = length, y = n))  
  geom_bar(stat = "identity")  
  geom_text(aes(label=n, y=n   .1 * after_scale(max(n))))



iris %>% 
  group_by(length= cut(Petal.Length, seq(5))) %>% 
  count() %>% 
  filter(n < 10) %>%
  ggplot(aes(x = length, y = n))  
  geom_bar(stat = "identity")  
  geom_text(aes(label=n, y=n   .1 * after_scale(max(n))))

Created on 2022-11-12 with reprex v2.0.2

CodePudding user response:

We can see your problem very clearly by setting up an example that uses facets with very different ranges. There is a single geom_text layer with nudge_y = 4:

df <- data.frame(month = factor(c(1:3, 1:3)), 
                 n     = c(80, 21, 45, 8, 2, 1),
                 panel = rep(c("A", "B"), each = 3))

library(ggplot2)

ggplot(df, aes(month, n))  
  geom_col(fill = "deepskyblue4")  
  geom_text(aes(label = n), size = 6, nudge_y = 4)  
  facet_wrap(.~panel, scales = "free_y")  
  scale_y_continuous(expand = expansion(c(0, 0.1)))  
  theme_bw(base_size = 16) 

Obviously, the y axis scale is smaller on the right, so the 4-unit nudge is proportionately much greater and now doesn't sit nicely on the bars.

One way to solve this is to fix the y axis limits:

ggplot(df, aes(month, n))  
  geom_col(fill = "deepskyblue4")  
  geom_text(aes(label = n), size = 6, nudge_y = 4)  
  facet_wrap(.~panel, scales = "free_y")  
  scale_y_continuous(limits = c(0, 90), expand = expansion(c(0, 0.1)))  
  ylim(c(0, 90))  
  theme_bw(base_size = 16)

However, if you want the bars to fill the plotting area, the easiest way is probably to just use vjust instead of nudge_y. Remember, you need a negative vjust to shift the text upwards.

ggplot(df, aes(month, n))  
  geom_col(fill = "deepskyblue4")  
  geom_text(aes(label = n), size = 6, vjust = -0.5)  
  facet_wrap(.~panel, scales = "free_y")  
  scale_y_continuous(expand = expansion(c(0, 0.1)))  
  theme_bw(base_size = 16)

Created on 2022-11-12 with reprex v2.0.2

  • Related