Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you order stacked bar categories by size in ggplot?

Tags:

r

ggplot2

I am trying to reorder categories in a ggplot bar chart by the size of the variables, with the biggest categories first, followed by increasingly minor ones. I've tried playing with the order in a few ways but only seem to be able to set the order manually which isn't very helpful for big data sets.

For example: Let's say I have the following data:

mydata <- read.table(header=TRUE, text="
shop    fruit   varieties   km_away
shop1   apple   0   12
                     shop1  banana  0   12
                     shop1  pear    2   12
                     shop1  melon   1   12
                     shop1  orange  1   12
                     shop1  peach   3   12
                     shop1  apricot 6   12
                     shop1  lime    1   12
                     shop2  apple   1   1
                     shop2  banana  0   1
                     shop2  pear    2   1
                     shop2  melon   2   1
                     shop2  orange  5   1
                     shop2  peach   4   1
                     shop2  apricot 11  1
                     shop2  lime    0   1
                     shop3  apple   0   2
                     shop3  banana  1   2
                     shop3  pear    2   2
                     shop3  melon   1   2
                     shop3  orange  4   2
                     shop3  peach   1   2
                     shop3  apricot 11  2
                     shop3  lime    1   2
                     shop4  apple   0   5
                     shop4  banana  0   5
                     shop4  pear    3   5
                     shop4  melon   2   5
                     shop4  orange  6   5
                     shop4  peach   1   5
                     shop4  apricot 9   5
                     shop4  lime    0   5
                     ")

I can usefully visualise it like this:

library(ggplot2)
library(RColorBrewer)
p <- ggplot(data = mydata, aes(x=reorder(shop, km_away), y=varieties, fill=fruit))+
  geom_bar(stat="identity") + coord_flip()+scale_fill_brewer(palette="Accent")
p

But how do I tell ggplot to plot the apricots first, then the oranges, etc? This will make it much easier to visually compare different categories across shops.

like image 235
setbackademic Avatar asked Oct 15 '25 16:10

setbackademic


1 Answers

You can first obtain a vector of the categories, ordered by your quantity of interest:

fruit_levels <- names(sort(tapply(mydata$varieties, mydata$fruit, sum)))

Then, in your call to ggplot, map fill to a factor variable with the corresponding levels:

p <- ggplot(data = mydata, 
    aes(x=reorder(shop, km_away), y=varieties, 
        fill=factor(fruit, levels = fruit_levels)))+
  geom_bar(stat="identity") + coord_flip()+
  scale_fill_brewer(name = "fruit", palette="Accent") 
p

Output:

enter image description here


Update. A more direct route is to re-order the factor levels in your original dataframe, and call ggplot as in your original code:

mydata$fruit <- reorder(mydata$fruit, mydata$varieties, sum)
p <- ggplot(data = mydata, aes(x=reorder(shop, km_away), y=varieties, fill=fruit))+
  geom_bar(stat="identity") + coord_flip()+scale_fill_brewer(palette="Accent")
p

Update 2. On older versions of ggplot2 (pre version 2), try specifying the order aesthetic:

p <- ggplot(data = mydata, aes(x=reorder(shop, km_away), 
                               y=varieties, 
                               fill=fruit, order=fruit)) +
  geom_bar(stat="identity") + coord_flip()+scale_fill_brewer(palette="Accent")
p

And if you want to reverse the ordering, add a negative sign in front of the ordering variable:

reorder(mydata$fruit, -mydata$varieties, sum)
like image 186
Weihuang Wong Avatar answered Oct 18 '25 11:10

Weihuang Wong



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!