Ordering stacked bar chart

83 views
Skip to first unread message

eipi10

unread,
Nov 30, 2014, 11:20:22 PM11/30/14
to ggp...@googlegroups.com
I'm creating a stacked bar plot, but can't get ggplot2 to stack the bars in the order I want, even though I've set the factor levels of the stacking variable to the desired order. The data frame I'm using for plotting is called numCty and is pasted in below using dput. Here's my plotting code:

ggplot(numCty, aes(County, count, fill=Status)) +
  geom_bar(stat="identity", colour="black", lwd=0.2) +
  geom_text(aes(label=count, y=pos), colour="grey30", size=2.4) +
  coord_flip() +
  xlab("County") + ylab("Number of Projects") +
  labs(fill="Project Status") +
  theme(axis.text=element_text(size=8),
        axis.title=element_text(size=9))

The plot looks exactly how I want it, with one exception: The ordering of the bars is currently (from left to right) green, blue, red (representing Status values of, respectively, Active, Inactive, and Completed). However, the ordering I want is red, green, blue (Status values of, respectively Completed, Active, Inactive).

As you can see in the numCty data frame pasted below, the factor levels of Status are in the order Completed, Active, Inactive, which (I would have thought) should result in ggplot stacking them in that order. Yet, ggplot is ignoring this ordering.

Thanks for any suggestions on how to get the desired ordering of the stacked bars.

Joel

numCty = structure(list(County = structure(c(19L, 19L, 19L, 1L, 2L, 15L,
10L, 10L, 10L, 18L, 18L, 18L, 11L, 11L, 11L, 16L, 16L, 20L, 20L,
20L, 12L, 17L, 17L, 17L, 13L, 3L, 14L, 4L, 21L, 21L, 21L, 5L,
6L, 7L, 9L, 8L), .Label = c("Butte", "Fresno", "San Joaquin",
"Santa Barbara", "Solano", "Stanislaus", "Tulare", "Yolo", "Ventura",
"Kern", "Merced", "Sacramento", "San Diego", "San Mateo", "Imperial",
"Monterey", "San Bernardino", "Los Angeles", "Alameda", "Orange",
"Santa Clara"), class = "factor"), Status = structure(c(2L, 3L,
1L, 2L, 2L, 2L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 3L, 1L, 2L,
3L, 1L, 2L, 2L, 3L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 1L, 2L, 2L, 2L,
2L, 2L), .Label = c("Completed", "Active", "Inactive"), class = "factor"),
    count = c(7L, 1L, 1L, 1L, 1L, 4L, 1L, 1L, 1L, 6L, 1L, 1L,
    1L, 1L, 1L, 2L, 2L, 1L, 4L, 4L, 3L, 3L, 1L, 1L, 3L, 1L, 3L,
    1L, 10L, 3L, 3L, 1L, 1L, 1L, 2L, 1L), pos = c(3.5, 7.5, 8.5,
    0.5, 0.5, 2, 0.5, 1.5, 2.5, 3, 6.5, 7.5, 0.5, 1.5, 2.5, 1,
    3, 0.5, 3, 7, 1.5, 1.5, 3.5, 4.5, 1.5, 0.5, 1.5, 0.5, 5,
    11.5, 14.5, 0.5, 0.5, 0.5, 1, 0.5)), .Names = c("County",
"Status", "count", "pos"), row.names = c(NA, -36L), class = "data.frame")

Ben Bond-Lamberty

unread,
Dec 1, 2014, 6:45:39 AM12/1/14
to ggplot2
You'll need to sort the data frame first:

numCty <- numCty[order(numCty$County, numCty$Status),]

...after which things plot correctly, except those geom_text labels, which are now out of position. You may want to compute them programatically, something like:

# assumes a sorted data frame
runningsum <- 0
for(i in 2:nrow(numCty)) {
     runningsum <- ifelse(numCty[i,"County"] == numCty[i-1,"County"], runningsum+numCty[i-1,"count"], 0)
     numCty[i,"pos"] <- runningsum + numCty[i,"count"]/2
}
numCty[1,"pos"] <- numCty[1,"count"]/2


Ben



--
--
You received this message because you are subscribed to the ggplot2 mailing list.
Please provide a reproducible example: https://github.com/hadley/devtools/wiki/Reproducibility
 
To post: email ggp...@googlegroups.com
To unsubscribe: email ggplot2+u...@googlegroups.com
More options: http://groups.google.com/group/ggplot2

---
You received this message because you are subscribed to the Google Groups "ggplot2" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ggplot2+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ista Zahn

unread,
Dec 1, 2014, 11:11:21 AM12/1/14
to Ben Bond-Lamberty, ggplot2
You can also force the order with

ggplot(numCty, aes(County, count, fill=Status, order = Status))

but you will still need to re-calculate the position of the labels.

Best,
Ista

eipi10

unread,
Dec 1, 2014, 12:44:28 PM12/1/14
to ggp...@googlegroups.com
Thanks Ista and Ben. One follow-up question: I don't think I understand why additional sorting is necessary. Shouldn't ggplot be able to list the counties in their factor order and stack the "Status" bars in their factor order without any further intervention?

Ben Bond-Lamberty

unread,
Dec 1, 2014, 1:03:45 PM12/1/14
to eipi10, ggplot2
I agree this behavior is not very intuitive, but don't have a good answer why. Generally, I guess if ggplot re-sorted dataframes based on a guess about the user's intent, a lot of things could go wrong.
Ben

--

Ista Zahn

unread,
Dec 1, 2014, 1:14:21 PM12/1/14
to Ben Bond-Lamberty, eipi10, ggplot2
It's a bug that never got fixed, see
https://github.com/hadley/ggplot2/issues/721

Best,
Ista

Yulie

unread,
Dec 1, 2014, 9:39:43 PM12/1/14
to ggp...@googlegroups.com

ggplot(transform(numCty,Status=factor(Status,levels=c("X5","X4","X3","X2","X1"))), aes(County, count, fill=Status))  ###you just order your Status by levels, like c("2L","1L"), or others, and don't need change other data

Ista Zahn

unread,
Dec 2, 2014, 12:14:04 PM12/2/14
to Yulie, ggplot2
Did you try this (using the OP's data and code)? It doesn't work for me.

--Ista

eipi10

unread,
Dec 2, 2014, 5:06:54 PM12/2/14
to ggp...@googlegroups.com
No, I haven't tried it.


On Sunday, November 30, 2014 8:20:22 PM UTC-8, eipi10 wrote:

Brandon Hurr

unread,
Dec 2, 2014, 6:35:01 PM12/2/14
to Ista Zahn, Yulie, ggplot2
Didn't work for me either. I was surprised but as you said, it's an outstanding bug. 

Pan, Yuanji (NIH/NCI) [C]

unread,
Dec 4, 2014, 2:14:57 PM12/4/14
to eipi10, ggp...@googlegroups.com

Based on following example

 

http://stackoverflow.com/questions/25512656/ggplot2-stacked-bar-not-ordering-by-manually-defined-factor-order?rq=1

 

It seems if you put “order=Status” in your code, you can order the bars in ordering red, green, blue.

 

ggplot(numCty, aes(County, count, fill=Status, order=Status)) +

  geom_bar(stat="identity", colour="black", lwd=0.2) +

  geom_text(aes(label=count, y=pos), colour="grey30", size=2.4) +

  coord_flip() +

  xlab("County") + ylab("Number of Projects") +

  labs(fill="Project Status") +

  theme(axis.text=element_text(size=8),

        axis.title=element_text(size=9))

 

the only thing mass up is the labels for each stack, you may have to fix the pos to label each stack correctly.

 

David

--

Reply all
Reply to author
Forward
0 new messages