mbroadribb
mbroadribb

Reputation: 125

How to create a stacked bar chart with 2 numeric variables in R using ggplot, grouped by 1 factor variable?

I'm fairly new to R and this is my first question on here so apologies if I write it in a confusing way!

Basically I have a dataframe with 4 columns, month and site which are factors, and organic % and inorganic % which are numeric:

df<-data.frame(month = c("Mar", "Apr", "May", "Jun", "Jul", "Mar", "Apr", "May", "Jun", "Jul"), site = c("Borth", "Borth", "Borth", "Borth", "Borth", "Clarach", "Clarach", "Clarach", "Clarach", "Clarach"), organic = c(10,20,30,40,50), inorganic = c(90,80,70,60,50))

I would like to make a bar chart on ggplot which has "organic / inorganic %" on the y axis, with organic and inorganic percent stacked ontop of eachother in each bar, and the bars grouped by site, with "month" on the x axis (so 2 stacked bars per month). So far from what I've seen stacked only works with a single variable, and you have to pick between grouped and stacked for position...

I'm guessing the graph would end up with a legend that had organic % borth, organic % clarach, inorganic % borth, inorganic % clarach.

I'm not sure if what I've written makes sense but if someone could offer any help that would be so great!

Upvotes: 1

Views: 1105

Answers (2)

akash87
akash87

Reputation: 3994

This is another way than the above answer to consider how to present your data. Using facet_wrap allows you to panel your data:

library(tidyverse)

# can also use library(dplyr); library(ggplot2); library(tidyr)

f %>% 
pivot_longer(c("organic", "inorganic")) %>% 
ggplot(aes(x = site, y = value, fill = name)) + 
geom_bar(position = "fill", stat = "identity") + 
facet_grid(~month) +     
scale_y_continuous(labels = scales::percent_format())

enter image description here

Upvotes: 2

Duck
Duck

Reputation: 39595

Try this. Your data is in wide format, so you can reshape to long using pivot_longer(). As you want legend combined by two variables you can create a common variable that contains that information and then use as fill option in the initial aes(). The bars you wanted as percentages, so you can enable position=fill to reach the desired plot. Here the code:

library(ggplot2)
library(dplyr)
library(tidyr)
#Code
df %>% mutate(month=factor(month,levels = unique(month),ordered = T)) %>%
  pivot_longer(-c(month,site)) %>%
  #Combine site and org/inorg
  mutate(Class=paste0(name,'.',site)) %>%
  ggplot(aes(x=month,y=value,fill=Class))+
  geom_bar(stat = 'identity',color='black',position='fill')+
  scale_y_continuous(labels=scales::percent)+
  theme_bw()+
  theme(axis.text = element_text(color='black',face='bold'),
        axis.title = element_text(color='black',face='bold'),
        legend.title = element_text(color='black',face='bold'),
        legend.text = element_text(color='black',face='bold'))

Output:

enter image description here

Upvotes: 1

Related Questions