R – Add percentage labels to stacked bar chart ggplot2

ggplot2labelsr

I'm stuck on creating a graph in ggplot2. I'm trying to create a stacked bar chart with percentages, similar to the graph on this page, but I am struggling to add percentage labels in the bars: How to draw stacked bars in ggplot2 that show percentages based on group?

All of the answers I've found to try and add percentage labels use something similar to the code

geom_text(aes(label = label), position = position_stack(vjust = 0.5),
size = 2)

but it is not working for me.

My data looks like this:

County  Group   Plan1   Plan2   Plan3   Plan4   Plan5   Total
County1 Group1  2019    597 513 5342    3220    11691
County2 Group1  521 182 130 1771    731 3335
County3 Group1  592 180 126 2448    1044    4390
County4 Group1  630 266 284 2298    937 4415
County5 Group1  708 258 171 2640    1404    5181
County6 Group1  443 159 71  1580    528 2781
County7 Group1  492 187 157 1823    900 3559
County8 Group1  261 101 84  1418    357 2221

My graph without the percentages looks like this:
graph1

Code:

melt(df[df$Group=="Group1",],measure.vars = c("Plan1","Plan2","Plan3","Plan4", "Plan5"),variable.name = "Counties",value.name = "value") %>% 
ggplot(aes(x=County,y=value,fill=Counties))+
  geom_bar(stat = "identity",position="fill", color="black", width=0.9) + 
  labs(y="Percent", fill="Plan Type") + ylab("Percentage") + coord_flip() + scale_y_continuous(labels=scales::percent)

After using the geom_text() code above, it turns into this mess:
graph2

Code:

melt(df[df$Group=="Group1",],measure.vars = c("Plan1","Plan2","Plan3","Plan4", "Plan5"),variable.name = "Counties",value.name = "value") %>% 
ggplot(aes(x=County,y=value,fill=Counties))+
  geom_bar(stat = "identity",position="fill", color="black", width=0.9) + 
  labs(y="Percent", fill="Plan Type") + ylab("Percentage") + coord_flip() + scale_y_continuous(labels=scales::percent)+ 
geom_text(aes(label=paste0(round(value/100),"%")), position=position_stack(vjust=0.5))

Any suggestions? Any advice/guidance is greatly appreciated! Thank you!!

Best Answer

Your approach did not work because the labels are not in % but the raw values. You have to do the stats on your own:

df <- read.table(text="County  Group   Plan1   Plan2   Plan3   Plan4   Plan5   Total
County1 Group1  2019    597 513 5342    3220    11691
                 County2 Group1  521 182 130 1771    731 3335
                 County3 Group1  592 180 126 2448    1044    4390
                 County4 Group1  630 266 284 2298    937 4415
                 County5 Group1  708 258 171 2640    1404    5181
                 County6 Group1  443 159 71  1580    528 2781
                 County7 Group1  492 187 157 1823    900 3559
                 County8 Group1  261 101 84  1418    357 2221", header = TRUE)

library(tidyverse)
df %>% 
  filter(Group == "Group1") %>% 
  select(-Total) %>% 
  gather(key = `Plan Type`, value = value, -County, -Group) %>% 
  group_by(County, Group) %>% 
  mutate(Percentage = value/sum(value)) %>% 
  ggplot(aes(x = County, y = Percentage, fill = `Plan Type`, label = paste0(round(Percentage*100), "%"))) +
  geom_col(position = position_stack(), color = "black") +
  geom_text(position = position_stack(vjust = .5)) +
  coord_flip() +
  scale_y_continuous(labels = scales::percent_format())

Edit:

The code above works as well for more plans as well as for more groups, but the plot will not account for that. Just add facet_wrap to produce also a flexible plot regarding the groups:

df %>% 
      filter(Group == "Group1") %>% 
      select(-Total) %>% 
      gather(key = `Plan Type`, value = value, -County, -Group) %>% 
      group_by(County, Group) %>% 
      mutate(Percentage = value/sum(value)) %>% 
      ggplot(aes(x = County, y = Percentage, fill = `Plan Type`, label = paste0(round(Percentage*100), "%"))) +
      geom_col(position = position_stack(), color = "black") +
      geom_text(position = position_stack(vjust = .5)) +
      coord_flip() +
      scale_y_continuous(labels = scales::percent_format()) +
      facet_wrap(~Group)
Related Topic