How do you order the fill-colours within ggplot2 geom_bar

I am calling the ggplot function

ggplot(data,aes(x,y,fill=category)+geom_bar(stat="identity")

The result is a barplot with bars filled by various colours corresponding to category. However the ordering of the colours is not consistent from bar to bar. Say there is pink, green and blue. Some bars go pink,green,blue from bottom to top and some go green,pink,blue. I don't see any obvious pattern.

How are these orderings chosen? How can I change it? At the very least, how can I make ggplot choose a consistent ordering?

The class of (x,y and category) are (integer,numeric and factor) respectively. If I make category an ordered factor, it does not change this behavior.

Anyone know how to fix this?

Reproducible example:

dput(data)

structure(list(mon = c(9L, 10L, 11L, 10L, 8L, 7L, 7L, 11L, 9L, 
10L, 12L, 11L, 7L, 12L, 8L, 12L, 9L, 7L, 9L, 10L, 10L, 8L, 12L, 
7L, 11L, 10L, 8L, 7L, 11L, 12L, 12L, 9L, 9L, 7L, 7L, 12L, 12L, 
9L, 9L, 8L), gclass = structure(c(9L, 1L, 8L, 6L, 4L, 4L, 3L, 
6L, 2L, 4L, 1L, 1L, 5L, 7L, 1L, 6L, 8L, 6L, 4L, 7L, 8L, 7L, 9L, 
8L, 3L, 5L, 9L, 2L, 7L, 3L, 5L, 5L, 7L, 7L, 9L, 2L, 4L, 1L, 3L, 
8L), .Label = c("Down-Down", "Down-Stable", "Down-Up", "Stable-Down", 
"Stable-Stable", "Stable-Up", "Up-Down", "Up-Stable", "Up-Up"
), class = c("ordered", "factor")), NG = c(222614.67, 9998.17, 
351162.2, 37357.95, 4140.48, 1878.57, 553.86, 40012.25, 766.52, 
15733.36, 90676.2, 45000.29, 0, 375699.84, 2424.21, 93094.21, 
120547.69, 291.33, 1536.38, 167352.21, 160347.01, 26851.47, 725689.06, 
4500.55, 10644.54, 75132.98, 42676.41, 267.65, 392277.64, 33854.26, 
384754.67, 7195.93, 88974.2, 20665.79, 7185.69, 45059.64, 60576.96, 
3564.53, 1262.39, 9394.15)), .Names = c("mon", "gclass", "NG"
), row.names = c(NA, -40L), class = "data.frame") 

ggplot(data,aes(mon,NG,fill=gclass))+geom_bar(stat="identity")

Starting in ggplot2_2.0.0, the order aesthetic is no longer available. To get a graph with the stacks ordered by fill color, you can simply order the dataset by the grouping variable you want to order by.

I often use arrange from dplyr for this. Here I'm ordering the dataset by the fill factor within the ggplot call rather than creating an ordered dataset but either will work fine.

library(dplyr)

ggplot(arrange(data, gclass), aes(mon, NG, fill = gclass)) +
    geom_bar(stat = "identity")

This is easily done in base R, of course, using the classic order with the extract brackets:

ggplot(data[order(data$gclass), ], aes(mon, NG, fill = gclass)) +
    geom_bar(stat = "identity")

With the resulting plot in both cases now in the desired order: enter image description here

ggplot2_2.2.0 update

In ggplot_2.2.0, fill order is based on the order of the factor levels. The default order will plot the first level at the top of the stack instead of the bottom.

If you want the first level at the bottom of the stack you can use reverse = TRUE in position_stack. Note you can also use geom_col as shortcut for geom_bar(stat = "identity").

ggplot(data, aes(mon, NG, fill = gclass)) +
    geom_col(position = position_stack(reverse = TRUE))

You need to specify the order aesthetic as well.

ggplot(data,aes(mon,NG,fill=gclass,order=gclass))+
    geom_bar(stat="identity")

enter image description here

This may or may not be a bug.


To order, you must use the levels parameter and inform the order. Like this:

data$gclass
(data$gclass2 <- factor(data$gclass,levels=sample(levels(data$gclass)))) # Look the difference in the factors order
ggplot(data,aes(mon,NG,fill=gclass2))+geom_bar(stat="identity")

You can change the colour using the scale_fill_ functions. For example:

ggplot(dd,aes(mon,NG,fill=gclass)) + 
  geom_bar(stat="identity") + 
  scale_fill_brewer(palette="blues")

To get consistent ordering in the bars, then you need to order the data frame:

dd = dd[with(dd, order(gclass, -NG)), ]

In order to change the ordering of legend, alter the gclass factor. So something like:

dd$gclass= factor(dd$gclass,levels=sort(levels(dd$gclass), TRUE))

enter image description here


Building on @aosmith 's answer, another way to order the bars, that I found slightly more intuitive is:

ggplot(data, aes(x=mon, y=reorder(NG,gclass), fill = gclass)) +
    geom_bar(stat = "identity")

The beauty of the reorder function from the base stats package is that you can apply it in the reorder(based_on_dimension, y, function) wherein y is ordered based_on_dimension with a function like sum, mean, etc.