How do you order the fill-colours within ggplot2 geom_bar

80,976

Solution 1

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.

Solution 2

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

Solution 3

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

Solution 4

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

Solution 5

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.

Share:
80,976

Related videos on Youtube

Dave31415
Author by

Dave31415

Updated on July 09, 2022

Comments

  • Dave31415
    Dave31415 almost 2 years

    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")
    
    • Ben Bolker
      Ben Bolker about 11 years
      reproducible example please?
    • joran
      joran about 11 years
      BTW: Brian confirmed for me that this is in fact a (somewhat longstanding) bug.
    • Ken Williams
      Ken Williams over 6 years
      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.
  • joran
    joran about 11 years
    Does that look like consistent ordering to you? I'm having the same problem the OP is with his data. Something fishy is going on here.
  • csgillespie
    csgillespie about 11 years
    @joran Ahh, I see the problem now!
  • csgillespie
    csgillespie about 11 years
    @Dave31415 I think I've answered the question, however, my understanding of the why this work is a bit ropey.
  • joran
    joran about 11 years
    Ok, I agree, sorting the df seems to work. But this still feels very fishy to me.
  • Dave31415
    Dave31415 about 11 years
    @csgillespie. Thanks. That appears to work but does still seems a little strange. I wonder if the stat="identity" is the problem.
  • Etienne Low-Décarie
    Etienne Low-Décarie over 8 years
    This appears to work fine with stat="identity", but fails with geom_bar(stat="summary", fun.y=median). In this case I had to summarise the data and use stat="identity" to get appropriate ordering. I belive this is new since 2.0
  • aosmith
    aosmith over 8 years
    @EtienneLow-Décarie It may be that stat_summary_bin is the appropriate tool for this. Have you tried using stat = "summary_bin" instead of stat = "summary"?
  • fanli
    fanli about 8 years
    Ugh, this was quite annoying. Can anyone comment on why the order aesthetic was removed? For reference: github.com/hadley/ggplot2/issues/1593
  • Shadow
    Shadow almost 8 years
    Awesome! Thanks so much for the note and solution!
  • Eric
    Eric about 7 years
    For those that may want to change the order of the legend to match the stacking, adding e.g. guides(fill = guide_legend(reverse = T)) should work nicely.
  • Yan Foto
    Yan Foto about 4 years
    As of ggplot >= 2.0; Ignoring unknown aesthetics: order! (see bellow)