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