pealco pealco - 4 months ago 14
R Question

Changing the order of dodged bars in ggplot2 barplot

I have a dataframe

df.all
and I'm plotting it in a bar plot with ggplot2 using the code below. I'd like to make it so that the order of the dodged bars is flipped. That is, so that the bars labeled "Singular" come before the bars labeled "Plural".

ggplot(df.all, aes(gram, V1, fill=number)) +
geom_bar(stat="identity", position="dodge") +
scale_x_discrete(labels=c("Grammatical","Ungrammatical")) +
scale_y_continuous(formatter="percent", limits=c(0,1)) +
facet_grid(. ~ experiment) +
scale_fill_hue("Attractor", breaks=c("S","P"), labels=c("Singular","Plural"))


I've tried doing
levels(df.all$number) = c("S", "P")
thinking that maybe ggplot uses the order of the levels to decide plotting order, but that didn't work. I'm not sure what else to try. Any ideas?

The contents of
df.all
, in case it's useful:

> df.all
number gram experiment V1
1 S G BERIMBAU_AGR_A 0.8133333
2 S G BERIMBAU_AGR_B 0.8658537
3 S U BERIMBAU_AGR_A 0.5436242
4 S U BERIMBAU_AGR_B 0.4597701
5 P G BERIMBAU_AGR_A 0.8580645
6 P G BERIMBAU_AGR_B 0.8536585
7 P U BERIMBAU_AGR_A 0.3087248
8 P U BERIMBAU_AGR_B 0.3975904

> str(df.all)
'data.frame': 8 obs. of 4 variables:
$ number : Factor w/ 2 levels "S","P": 2 2 2 2 1 1 1 1
..- attr(*, "scores")= num [1:2(1d)] 0 -1
.. ..- attr(*, "dimnames")=List of 1
.. .. ..$ : chr "P" "S"
$ gram : Factor w/ 2 levels "G","U": 1 1 2 2 1 1 2 2
$ experiment: Factor w/ 4 levels "BERIMBAU_AGR_A",..: 1 4 1 4 1 4 1 4
$ V1 : num 0.813 0.866 0.544 0.46 0.858 ...

Answer

Hadley has provided a solution. Here's a replication of the problem and the solution.

The goal is to get the bars labeled "S" to come before the bars labeled "P". This doesn't happen by default because R orders levels alphabetically.

df <- read.csv("http://pealco.net/code/ggplot_dodge/df.txt")
ggplot(df, aes(gram, V1, fill=number))
    + geom_bar(stat="identity", position="dodge")

alt text

As Hadley commented in another answer, "you need to reorder based on the x variables, not the y variable". Though I'm not sure why this works.

To flip the order of the factors in this example, you can convert the factor to numeric and multiply by -1.

df <- with(df, df[order(gram, -as.numeric(number)), ])

Plotting again shows that his works.

alt text

I'd still like so more explanation about why df <- with(df, df[order(gram, -as.numeric(number)), ]) works.

Comments