tags:

views:

699

answers:

3

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 ...
A: 

I think df.all$number needs to be an ordered factor. Try df.all$number <- ordered(df.all$number)

John Johnson
+1  A: 

This isn't an answer to the problem, but rather another example of the issue. Per Hadley's comment about reproducable code, here's an example where I am having the same struggle:

val <- read.csv("http://www.cerebralmastication.com/wp-content/uploads/2009/11/val.txt")
val<-with(val, val[order(-Value), ])
p <- ggplot(val)
p + geom_bar(aes(State, Value, fill=variable), stat = "identity", position="dodge") + scale_fill_brewer(palette = "Set1")

the data frame val is sorted but the output looks like this:

alt text

JD Long
You need to reorder based on the x variables, not the y variable: `val<-with(val, val[order(State, variable), ])`
hadley
But I'd consider a plot more like:`ggplot(val, aes(State, Value)) + geom_bar(stat = "identity", subset = .(variable == "estimate"), fill = "grey70") + geom_crossbar(aes(ymin = Value, ymax = Value), subset = .(variable == "actual"))`
hadley
nope. I really do want to sort based on the Y. I'm shooting for a classic Pareto Chart: http://en.wikipedia.org/wiki/Pareto_chart
JD Long
I thought we were talking about the same thing, but it appears not. As such, I have moved this question here: http://stackoverflow.com/questions/1735540/creating-a-pareto-chart-with-ggplot2-and-r
JD Long
A: 

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.

pealco