Search code examples
rggplot2geom-bar

Ordering grouped geom_bar left to right by height


The following R script:

library(ggplot2)

data <- read.csv(text="x,value,version
foo,10,one
foo,12,two
bar,8,one
bar,7,two
baz,11,one
baz,14,two", header=TRUE)

png(filename="so.png")
ggplot(data,aes(data$x,data$value,fill=data$version)) + 
  geom_bar(stat="identity",position="dodge") + 
  scale_fill_brewer(palette="Set1") + 
  labs(x = "x",y="value") + 
  guides(fill=guide_legend(title="version"))
dev.off()

Produces the following graph:

enter image description here

They appear left to right according to the "x" column (foo, bar, baz) alphabetically. However, I'd like the "x" column-grouped bars to appear according one of the versions, left most being the highest "value" column value. E.g. left to right according to values of "one" version. Thus:

  • left most: baz (one:11,two:14)
  • middle: foo (one:10,two:12)
  • right most: bar (one:8,two:7)

How can I achieve this?


Solution

  • The general principle at the question I cited always holds: you control order by setting the factor level order. Many people get tripped up because the answer at that question doesn't always tell you in precise detail how to reorder your factor in every single circumstance. But the idea is always the same. Here are a variety of ways to approach setting the factor levels in that order:

    #Cleverly
    library(forcats)
    data$x <- fct_reorder2(.f = data$x,
                           x = data$value,
                           y = data$version,
                           fun = function(x,y) x[y == "one"])
    
    #Manually
    data$x <- factor(data$x,levels = c("baz","foo","bar"))
    
    #Tortuously
    levels(data$x) <- data$x[data$version == "one"][order(data$value[data$version == "one"],decreasing = TRUE)]
    
    #tidily
    library(dplyr)
    levels(data$x) <- data %>%
      filter(version == "one") %>%
      arrange(desc(value)) %>%
      pull(x)