Search code examples
rggplot2geom-bargeom-text

Adding proportions to a bar chart


I've used my df to create a filled bar chart (Code used below). I want to have the proportions of each "race" printed within the bar chart.

Demo_17 <- tidyr::pivot_longer(Race_17, -c("State",), names_to = "Race", values_to = "num") %>% 
  ggplot(aes(x=State, y=num, fill = Race)) + 
  geom_bar(position="fill", stat="identity")

  Demo_17 + 
  labs(x = "Population", y = "State", title = "US State Demographics 2017")

This is the df I'm using: US Demographic Data

I've looked at other similar questions but the code is long and hard to follow, particularly if it doesn't relate to your own data.

Can anyone lead me in the right direction?


Solution

  • Try this. Simply compute shares before plotting. Use scales::percent for nice formatting:

    Demo_17 <- tidyr::pivot_longer(Race_17, -c("State",), names_to = "Race", values_to = "num") %>% 
      # compute pct share of race by state
      group_by(State) %>% 
      mutate(pct = num / sum(num)) %>% 
      ggplot(aes(x=State, y=num, fill = Race)) + 
      geom_bar(position="fill", stat="identity") +
      geom_text(aes(label = scales::percent(pct)), position = "fill")
    
    Demo_17 + labs(x = "Population",
                   y = "State",
                   title = "US State Demographics 2017")
    

    An example of this approach using mtcars:

    library(ggplot2)
    library(dplyr)
    
    mtcars %>% 
      count(cyl, gear, name = "num") %>% 
      group_by(cyl) %>% 
      mutate(pct = num / sum(num)) %>% 
      ggplot(aes(x=cyl, y=num, fill = gear)) + 
      geom_bar(position="fill", stat="identity") +
      geom_text(aes(label = scales::percent(pct)), position = "fill", vjust = 1.5, color = "white")
    

    Created on 2020-04-20 by the reprex package (v0.3.0)

    ADDITIONALLY: If you prefer to only show a label for shares over 10% (just an example, adjust as wished) then you add an ifelse() inside the label argument of geom_text:

    mtcars %>% 
      count(cyl, gear, name = "num") %>% 
      group_by(cyl) %>% 
      mutate(pct = num / sum(num)) %>% 
      ggplot(aes(x=cyl, y=num, fill = gear)) + 
      geom_bar(position="fill", stat="identity") +
      geom_text(aes(label = ifelse(pct>0.10, scales::percent(pct), "")), position = "fill", vjust = 1.5, color = "white")
    

    enter image description here

    As you notice the 9% label is not showing anymore.