Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting Stacked Bar Plot by Factor in dataframe

Amateur R user here. I looked pretty hard online to see if this question has been answered/asked but I have not found a good answer. I can't post an image since I do not have 10 "reputations"

I want to have a stacked bar plot that orders the x variable based on the percent contribution of the ingestion route (in descending order).

Percent<-c(0.4,0.75,0.8, 0.3,0.1,0.6,0.25,0.5)
Inh<-data.frame(ID=c(rep(1,4),rep(2,4)),Age=factor(rep(1:4,2), label=c("0-1 year", "1-2 years", "2-3 years","3-6 years")), Route=factor(rep(1), label="Inhalation"),    Percent=Percent)

Ing<-data.frame(ID=c(rep(1,4),rep(2,4)),Age=factor(rep(1:4,2), label=c("0-1 year", "1-2 years", "2-3 years","3-6 years")), Route=factor(rep(1), label="Ingestion"),     Percent=1-Percent)

df<-data.frame(rbind(Inh,Ing))
ggplot(df,aes(x=ID,y=Percent,fill=Route))+ geom_bar(stat="identity")+ 
facet_wrap(~Age, scales = "free_x") +
ylab("Percent Contribution") +
labs(title = "Route Contribution to Exposure by Age Groups")

enter image description here

But I want it to look like this which I mocked up manually:

Percent<-c(0.1,0.6,0.25, 0.3,0.4,0.75,0.8,0.5)
Inh<-data.frame(ID=c(rep(1,4),rep(2,4)),Age=factor(rep(1:4,2), label=c("0-1 year", "1-2 years", "2-3 years","3-6 years")), Route=factor(rep(1), label="Inhalation"),    Percent=Percent)

Ing<-data.frame(ID=c(rep(1,4),rep(2,4)),Age=factor(rep(1:4,2), label=c("0-1 year", "1-2 years", "2-3 years","3-6 years")), Route=factor(rep(1), label="Ingestion"),     Percent=1-Percent)

df<-data.frame(rbind(Inh,Ing))
ggplot(df,aes(x=ID,y=Percent,fill=Route))+ geom_bar(stat="identity")+ 
facet_wrap(~Age, scales = "free_x") +
ylab("Percent Contribution") +
labs(title = "Route Contribution to Exposure by Age Groups")

enter image description here

Thank you in advance!

UPDATE: Thanks to Roland, I have a plot! Questions remain on clarity though. For those interested here's code and final product:

ggplot(df,aes(x=id2,y=Percent,fill=Route, width=1,order = -as.numeric(Route)))+ 
geom_bar(stat="identity")+ 
facet_wrap(~Age, scales = "free_x") +
xlab(" ")+
ylab("Percent Contribution") +
theme(axis.text.x = element_blank(), axis.ticks.x= element_blank() ) +
labs(title = "DEHP Route Contribution to Exposure by Age Groups")

enter image description here

like image 461
LeslieKish Avatar asked Aug 23 '26 01:08

LeslieKish


1 Answers

This changes the order without changing the data (as you do in your mock-up). The idea is to create an ordered (by Percent) factor giving the interaction of Age and ID and use this for plotting, but change the axis labels to match only the ID values.

df <- df[order(df$Route,df$Percent),]
df$id2 <- factor(paste(df$ID,df$Age),levels=unique(paste(df$ID,df$Age)),ordered=TRUE)

ggplot(df,aes(x=id2,y=Percent,fill=Route))+ 
  geom_bar(stat="identity")+ 
  scale_x_discrete(labels = setNames(regmatches(levels(df$id2),regexpr("[[:alnum:]]*",levels(df$id2))),levels(df$id2))) +
  facet_wrap(~Age, scales = "free_x") +
  xlab("ID") +
  ylab("Percent Contribution") +
  labs(title = "Route Contribution to Exposure by Age Groups")

enter image description here

However, I think the resulting plot is confusing and difficult to read.

like image 85
Roland Avatar answered Aug 25 '26 15:08

Roland