Question

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 ...
Was it helpful?

Solution 3

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

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

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

OTHER TIPS

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

In some cases I don't think this is possible:

layerCake<-data.frame(group=c(rep("normal",4),rep("tumor",4)),
                      class=factor(rep(c("exon","intron","intergenic","unmapped"),2),levels=rev(c("exon","intron","intergenic","unmapped")),ordered=TRUE),
                      fraction=c(.02,.25,.50,.23,.015,.20,.555,.23)
)
layerCake[layerCake$group=='normal',"reads"]<-130948403*layerCake[layerCake$group=='normal',"fraction"]
layerCake[layerCake$group=='tumor',"reads"]<-200948403*layerCake[layerCake$group=='tumor',"fraction"]
g<-ggplot(layerCake, aes(x=factor(group),y=reads, fill=factor(class),order = as.numeric(class)))+xlab("Group")+scale_fill_discrete(name="Anno Class",breaks=c("exon","intron","intergenic","unmapped"))

correct order in stacked:
g+geom_bar(stat="identity",position="stack") enter image description here

incorrect order in dodge:

g+geom_bar(stat="identity",position="dodge")

enter image description here

let's try to reverse the order in ggplot:

g<-ggplot(lc, aes(x=factor(group),y=reads, fill=factor(class),order = -as.numeric(class)))+xlab("Group")+scale_fill_discrete(name="Anno Class",breaks=c("exon","intron","intergenic","unmapped"))
g+geom_bar(stat="identity",position="dodge")

no dice

let's try to reorder the data frame

lc <- with(lc, lc[order(-as.numeric(class)), ])
g<-ggplot(lc, aes(x=factor(group),y=reads, fill=factor(class),order = -as.numeric(class)))+xlab("Group")+scale_fill_discrete(name="Anno Class",breaks=c("exon","intron","intergenic","unmapped"))
g+geom_bar(stat="identity",position="dodge")

nope

Changing factor levels really does change the order of dodged bars! Common pitfall: the colors still stay at a certain position, so taking a quick glance makes it look like the order has not changed. But if you look at the values you will see that the order really has changed.

Edit: My previous answer below only changes order of color scheme given to bars. This is still useful, as we may often want to reverse the color scheme at the same time as changing the order of the bars:

I was using scale_fill_manual because I wanted to manually fill the colors of my bars.

ggplot(data, aes_string(x = "countries", y = "population", fill = "agegroups")) +
scale_fill_manual(values = CustomColorFunction(), limits = (levels(data$agegroups)))

Spent 5 hours tinkering with changing factor levels and arranging the dataframe hopes this helps someone!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top