Search code examples
rggplot2geom-barstacked-bar-chart

Percent stacked barchart: from Excel to ggplot2 in R


My question is pretty simple. I'm trying to create a percent stacked barchart in ggplot2. I know exactly how I want it to be like because I created the same chart in Excel already, but I don't know how to obtain the same graph in R.

My issue is that the "fill" in my code corresponds to two sets of data: my x axis are nest box numbers, my y axis is a percentage (0%-100%), and the filling should be divided into males and females (e.g., in nest box number 5(b) there were 3 parasites, 2 females and 1 male, so the column should be divided into 67% FF and 33% MM).

This is my dataset:

> dput(broods_2020)
structure(list(`Age.(days)` = c("7-10 days", "15-20 days", "5-7 
days", 
"5-7 days", "5-7 days", "15-20 days", "6-8 days", "5-7 days", 
"13-15 days", "10-12 days", "7-10 days", "8-10 days", "5-7 days", 
"8-10 days", "20-25 days", "7-10 days", "8-10 days", "10-12 days", 
"15-20 days", "15-20 days", "10-12 days", "12-15 days"), `Nest- 
box.number.(x.brood)` = c(" 5 (a)", 
"5 (b)", "7", "10", "11 (a)", "12", "27", "31", "37 (a)", "40", 
"41", "200", "202", "205", "1 west", "5 west", "A3", "B7", "B8", 
"B11", "C18", "C21"), `N.(Carnus)` = c(4, 3, 13, 36, 10, 8, 8, 
17, 6, 3, 13, 8, 8, 9, 5, 10, 22, 28, 8, 8, 1, 3), MM = c(2, 
1, 5, 13, 5, 3, 2, 8, 2, 2, 5, 4, 3, 4, 3, 5, 10, 9, 1, 3, 1, 
1), FF = c(2, 2, 8, 23, 5, 5, 6, 9, 4, 1, 8, 4, 5, 5, 2, 5, 12, 
19, 7, 5, 0, 2)), row.names = c(NA, 22L), class = "data.frame")

This is my code:

ggplot(broods_2020, aes(x=broods_2020$"Nest-box.number.(x.brood)",y=broods_2020$"MM",broods_2020$"FF",fill=broods_2020$"N.(Carnus)",)) + geom_col() +
  geom_bar(position="fill", stat="identity") +
  geom_bar(fill="#290DFB","#FF0000") +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) 
+
  xlab("Nest box") + ylab("Collected Carnus hemapterus (%)") +
  ggtitle("2020 - PARASITE SEX RATIO (per brood)") +
  theme(axis.line.x = element_line(colour = 'black', size=0.5, 
linetype='solid'),
        axis.line.y = element_line(colour = 'black', size=0.5, 
linetype='solid')) +
  theme(title = element_text(face="plain", size = 12)) +
  theme(plot.title = element_text(hjust = 0.5, vjust =2)) +
  theme(axis.text.x = element_text(angle = 45, hjust=1)) +
  theme(panel.background = element_blank()) 

Is there an issue in my dataset? How do I create this chart?


Solution

  • Is this closer to what you're looking for?

    If involves a few steps:

    • pivot_wider puts sex as one variable and n as another - this is what allows you to set a colour to represent each sex
    • n is passed as the y value to aes and sex as the fill value
    • geom_col(position = "fill") then fills the bar up to 100% for each x value (Nest-box.number.(x.brood))
    • You only need one geom_ layer for this - geom_bars are not needed
    • Setting the fill colours to match MM and FF is done in scale_fill_manual(values = ...)
    library(ggplot2)
    library(tidyr)
    
    
    broods_2020 |>
      pivot_longer(c(MM, FF), names_to = "sex", values_to = "n") |>
      ggplot(aes(x = `Nest-box.number.(x.brood)`, y = n, fill = sex)) + 
      geom_col(position = "fill") +
      scale_fill_manual("Sex", values = c("MM" = "#290DFB", "FF" = "#FF0000")) +
      scale_y_continuous("Percent", labels = scales::percent_format(accuracy = 1)) +
      xlab("Nest box") + ylab("Collected Carnus hemapterus (%)") +
      ggtitle("2020 - PARASITE SEX RATIO (per brood)") +
      theme(
        axis.line.x = element_line(
          colour = 'black',
          size = 0.5,
          linetype = 'solid'
        ),
        axis.line.y = element_line(
          colour = 'black',
          size = 0.5,
          linetype = 'solid'
        )
      ) +
      theme(title = element_text(face = "plain", size = 12)) +
      theme(plot.title = element_text(hjust = 0.5, vjust = 2)) +
      theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
      theme(panel.background = element_blank())