46
votes

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")
6
reproducible example please?Ben Bolker
BTW: Brian confirmed for me that this is in fact a (somewhat longstanding) bug.joran
Reader beware - this behavior has unfortunately changed several times in ggplot2's recent history, and some of the examples in the answers don't work anymore.Ken Williams

6 Answers

65
votes

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))
25
votes

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.

6
votes

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")
4
votes

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

1
votes

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.

1
votes

Since this exchange shows up first for "factor fill order", I will add one more solution, what I believe to be a bit more straight forward, and doesn't require altering your underlying data.

ggplot(data,aes(x,y,fill=factor(category, levels = c("Down-Down", "Down-Stable", "Down-Up", "Stable-Down", "Stable-Stable", "Stable-Down", "Up-Down", "Up-Stable", "Up-Up"))) + 
geom_col(position = position_stack(reverse = FALSE))

Or as I prefer, I first create a variable vector to simplify coding later and make it more easily editable:

v_factor_levels <- c("Down-Down", "Down-Stable", "Down-Up", "Stable-Down", "Stable-Stable", "Stable-Down", "Up-Down", "Up-Stable", "Up-Up")

ggplot(data,aes(x,y,fill=factor(category, levels = v_factor_levels)) + 
geom_col(position = position_stack(reverse = FALSE))

You don't need the reverse position element within geom_col(), I keep these as a reminder in case I want to reverse, but you could further simplify by eliminating that.