How to order bars in faceted ggplot2 bar chart

Richie Cotton Source

If I want to order the bars in a ggplot2 barchart from largest to smallest, then I'd usually update the factor levels of the bar category, like so

one_group <- data.frame(
  height   = runif(5),
  category = gl(5, 1)

o <- order(one_group$height, decreasing = TRUE)
one_group$category <- factor(one_group$category, levels = one_group$category[o])

p_one_group <- ggplot(one_group, aes(category, height)) +
  geom_bar(stat = "identity")

If have have several groups of barcharts that I'd like in different facets, with each facet having bars ordered from largest to smallest (and different x-axes) then the technique breaks down.

Given some sample data

two_groups <- data.frame(
  height   = runif(10),
  category = gl(5, 2),
  group    = gl(2, 1, 10, labels = letters[1:2])

and the plotting code

p_two_groups <- ggplot(two_groups, aes(category, height)) +
  geom_bar(stat = "identity") +
  facet_grid(. ~ group, scales = "free_x")

what do I need to do to get the bar ordering right?

If it helps, an equivalent problem to solve is: how do I update factor levels after I've done the faceting?



answered 7 years ago Ramnath #1

Here is a hack to achieve what you want. I was unable to figure out how to get the category values below the tick marks. So if someone can help fix that, it would be wonderful. Let me know if this works

# add a height rank variable to the data frame
two_groups = ddply(two_groups, .(group), transform, hrank = rank(height));

# plot the graph

p_two_groups <- ggplot(two_groups, aes(-hrank, height)) +
  geom_bar(stat = "identity") +
  facet_grid(. ~ group, scales = "free_x") +
  opts(axis.text.x = theme_blank()) +
  geom_text(aes(y = 0, label = category, vjust = 1.5))

answered 7 years ago kohske #2

here is a hack:

two_groups <- transform(two_groups, category2 = factor(paste(group, category)))
two_groups <- transform(two_groups, category2 = reorder(category2, rank(height)))

ggplot(two_groups, aes(category2, height)) +
  geom_bar(stat = "identity") +
  facet_grid(. ~ group, scales = "free_x") +
  scale_x_discrete(labels=two_groups$category, breaks=two_groups$category2)
  1. make UNIQUE factor variable for all entries (category2)
  2. reorder the variable based on the height
  3. plot on the variable: aes(x=category2)
  4. re-label the axis using original value (category) for the variable (category2) in scale_x_discrete.

comments powered by Disqus