Reputation: 95
I'm trying to add the % symbol next to each label of a bar-plot showing count on the y-axis and factor levels on the x-axis. I have already calculated percentages values (pct) outside ggplot2 to use as labels, example here
My data
dat <-structure(list(GRADE = structure(1:5, .Label = c("0", "1", "2", "3",
"4"), class = "factor"), Count = c(151L, 31L, 31L,
9L, 2L), pct = c(67, 14, 14, 4, 1)), row.names = c(NA, 5L), class =
"data.frame")
Plot code
p <- dat %>%
ggplot(aes(x=GRADE, y=Count, fill=GRADE)) + geom_bar(stat="identity") +
geom_text(aes(label= pct), vjust=1.6, color="black", size=3.5) +
ggtitle("GRADE stage") + theme(plot.title = element_text(hjust = 0.5, size=14, face="bold")) +
scale_fill_brewer(palette="Blues") +
theme(legend.position="bottom")
p
Which gives this, but I want to add % next to 67, 14, 14, 4, 1 to show that these are percentages and not counts
p <- dat %>%
ggplot(aes(x=GRADE, y=Count, fill=GRADE)) + geom_bar(stat="identity") +
geom_text(aes(label= pct, "%"), vjust=1.6, color="black", size=3.5) +
ggtitle("GRADE stage") + theme(plot.title = element_text(hjust = 0.5, size=14, face="bold")) +
scale_fill_brewer(palette="Blues") +
theme(legend.position="bottom")
p
Which gives the wrong result here below
Any help appreciated, thanks!
Upvotes: 2
Views: 3861
Reputation: 16842
For your labels, you want to stick the text of pct
to a percent sign. The quickest way for something simple like this is paste0(pct, "%")
. For something more complicated, there are options like sprintf
, formatC
, or stringr::str_glue
. If you had the percentages in their decimal form, scales::percent(pct)
would create formatted labels for you.
You can adjust the alignment and placement of the labels using a combination of vjust
for alignment and nudge_y
for adding spacing. The recommendation in the ggplot2
docs is that vjust
and hjust
stay between 0 and 1; I try to usually heed this recommendation and use nudging if I need something beyond those bounds.
Setting vjust = 0
aligns your text at the bottom, i.e. for a label placed at y = 150, the bottom of the text will be at y = 150. This is the sort of thing I like to check before adjusting anything.
library(tidyverse)
dat %>%
ggplot(aes(x = GRADE, y = Count, fill = GRADE)) +
geom_col() +
geom_text(aes(label = paste0(pct, "%")), vjust = 0, color = "black", size = 3.5) +
scale_fill_brewer(palette = "Blues")
From there, you can add a nudge upwards. nudge_y
/ nudge_x
operate in the units along their axes, so nudge_y = 2
pushes the bottoms of the labels up by 2 with respect to the values of Count
.
dat %>%
ggplot(aes(x = GRADE, y = Count, fill = GRADE)) +
geom_col() +
geom_text(aes(label = paste0(pct, "%")), vjust = 0, color = "black", size = 3.5, nudge_y = 2) +
scale_fill_brewer(palette = "Blues")
If you nudge the labels much higher or set the text bigger, you'll want to add an expand
term to your y-scaling to give more space. Something like:
scale_y_continuous(expand = expand_scale(mult = c(0.05, 0.1)))
would add more empty space at the upper end of the y-scale and keep from cutting off the labels.
An aside worth noting is that in more recent versions of ggplot2
, geom_col()
takes the place of geom_bar(stat = "identity")
.
Upvotes: 3