3
votes

I want to create grouped bar plot while keeping order. If it was single column and not a grouped bar plot use of reorder function is obvious. But not sure how to use it on a melted data.frame.

Here is the detail explanation with code example:

Lets say we have following data.frame:

d.nfl <- data.frame(Team1=c("Vikings", "Chicago", "GreenBay", "Detroit"), Win=c(20, 13, 9, 12))

plotting a simple bar plot while flipping it.

ggplot(d.nfl, aes(x = Team1, y=Win)) + geom_bar(aes(fill=Team1), stat="identity") + coord_flip()

above plot will not have an order and if I want to order the plot by win I can do following:

d.nfl$orderedTeam <- reorder(d.nfl$Team1, d.nfl$Win)
ggplot(d.nfl, aes(x = orderedTeam, y=Win)) + geom_bar(aes(fill=orderedTeam), stat="identity") + coord_flip()

Now lets say we add another column (to original data frame)

d.nfl$points <- c(12, 3, 45, 5)

     Team1 Win points
1  Vikings  20     12
2  Chicago  13      3
3 GreenBay   9     45
4  Detroit  12      5

to generate grouped bar plot, first we need to melt it:

library(reshape2)
> d.nfl.melt <- melt(d.nfl[,c('Team1','Win','points')],id.vars = 1)
> ggplot(d.nfl.melt,aes(x = Team1,y = value)) + geom_bar(aes(fill = variable),position = "dodge", stat="identity") + coord_flip()

enter image description here

above ggplot is unordered.

but how I do ordered group bar plot (ascending manner)

2
You reordered the factor levels the first time, and it worked. Maybe try setting the factor level order on the melted data frame...?joran
Possible duplicate of Order Bars in ggplot2 bar graphalistaire
Something related here. With stacking, you just need to order the dataset before plotting but that doesn't appear to work for dodging.aosmith
@joran tried didn't work: > melted.theTable <- within(d.nfl.melt, Team1 <- factor(Team1, levels = names(sort(table(Team1), decreasing=FALSE)))) > ggplot(melted.theTable,aes(x = Team1,y = value)) + geom_bar(aes(fill = variable),position = "dodge", stat="identity") + coord_flip()add-semi-colons
Recheck your attempt to set the level order; it is wrong.joran

2 Answers

4
votes

This is a non-issue.

The easiest way is to not discard your ordered team in the melt:

d.nfl.melt <- melt(d.nfl,id.vars = c("Team1", "orderedTeam"))

Alternatively, we can use reorder after melting and just only use the Win elements in computing the ordering:

d.nfl.melt$ordered_after_melting = reorder(
    d.nfl.melt$Team1,
    X = d.nfl.melt$value * (d.nfl.melt$variable == "Win")
)

Yet another idea is to take the levels from the original ordered column and apply them to a melted factor:

d.nfl.melt$copied_levels = factor(
    d.nfl.melt$Team1,
    levels = levels(d.nfl$orderedTeam)
)

All three methods give the same result. (I left out the coord_flips because they don't add anything to the question, but you can of course add them back in.)

gridExtra::grid.arrange(
    ggplot(d.nfl.melt,aes(x = orderedTeam, y = value)) + 
        geom_bar(aes(fill = variable),position = "dodge", stat="identity"),
    ggplot(d.nfl.melt,aes(x = ordered_after_melting, y = value)) + 
        geom_bar(aes(fill = variable),position = "dodge", stat="identity"),
    ggplot(d.nfl.melt,aes(x = copied_levels, y = value)) + 
        geom_bar(aes(fill = variable),position = "dodge", stat="identity")
)

enter image description here

As to the easiest, I would recommend just keeping the orderedTeam variable around while melting. Your code seems to work hard to leave it out, it's quite easy to keep it in.

3
votes

The challenge your question presents is how to reorder a factor Team1 based on a subset values in a melted column.

The comments to your question from @alistaire and @joran link to great answers. The tl;dr answer is to just apply the ordering from your original, unmelted data.frame to the new one using levels().

library(reshape2)
#Picking up from your example code:
d.nfl.melt <- melt(d.nfl[,c('Team1','Win','points')],id.vars = 1)
levels(d.nfl.melt$Team1)
#Current order is alphabetical
#[1] "Chicago"  "Detroit"  "GreenBay" "Vikings" 

#Reorder based on Wins (using the same order from your earlier, unmelted data.frame)
d.nfl.melt$Team1 <- factor(d.nfl.melt$Team1, levels = levels(d.nfl$orderedTeam)) #SOLUTION
levels(d.nfl.melt$Team1)
#New order is ascending by wins
#[1] "GreenBay" "Detroit"  "Chicago"  "Vikings" 

ggplot(d.nfl.melt,aes(x = Team1,y = value)) + 
  geom_bar(aes(fill = variable),position = "dodge", stat="identity") + coord_flip()

enter image description here