Mia
Mia

Reputation: 95

How do I add a character object to a numeric label in ggplot2: adding the % symbol to the percentage label in a bar chart

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

enter image description here I've tried this

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

enter image description here

Any help appreciated, thanks!

Upvotes: 2

Views: 3861

Answers (1)

camille
camille

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

Related Questions