2

Here is my script (example inspired from here and using the reorder option from here):

library(ggplot2)
Animals <- read.table(
  header=TRUE, text='Category        Reason Species
1   Decline       Genuine      24
2  Improved       Genuine      16
3  Improved Misclassified      85
4   Decline Misclassified      41
5   Decline     Taxonomic       2
6  Improved     Taxonomic       7
7   Decline       Unclear      10
8  Improved       Unclear     25
9  Improved           Bla     10
10  Decline         Hello     30')

fig <- ggplot(Animals, aes(x=reorder(Animals$Reason, -Animals$Species), y=Species, fill = Category)) + 
  geom_bar(stat="identity", position = "dodge")

This gives the following output plot: enter image description here

What I would like is to order my barplot only on condition 'Decline', and all the 'Improved' would not be inserted in the middle. Here is what I would like to get (after some svg editing):

enter image description here

So now all the whole 'Decline' condition is sorted and the 'Improved' condition comes after. Besides, ideally, the bars would all be at the same width, even if the condition is not represented for the value (e.g. "Bla" has no "Decline" value).

Any idea on how I could do that without having to play with SVG editors? Many thanks!

Community
  • 1
  • 1
tlorin
  • 1,100
  • 6
  • 17
  • 30

4 Answers4

4

First let's fill your data.frame with missing combinations like this.

library(dplyr)
Animals2 <- expand.grid(Category=unique(Animals$Category), Reason=unique(Animals$Reason)) %>% data.frame %>% left_join(Animals)

Then you can create an ordering variable for the x-scale:

myorder <- Animals2 %>% filter(Category=="Decline") %>% arrange(desc(Species)) %>% .$Reason %>% as.character

An then plot:

ggplot(Animals2, aes(x=Reason, y=Species, fill = Category)) + 
  geom_bar(stat="identity", position = "dodge") + scale_x_discrete(limits=myorder)

enter image description here

agenis
  • 8,069
  • 5
  • 53
  • 102
  • 1
    Providing the output graph is a good 'try my solution' argument! ;) – tlorin Aug 11 '16 at 13:26
  • Thanks. If i were you i would modify the title of your question to include the "missing combinations" theme, or the problem of the width of the bars different if one of the coloring variables is missing. – agenis Aug 11 '16 at 13:53
  • I just fixed it. Let me know if you want me to change it again. – tlorin Aug 11 '16 at 15:10
2

Define new data frame with all combinations of "Category" and "Reason", merge with data of "Species" from data frame "Animals". Adapt ggplot by correct scale_x_discrete:

Animals3 <-  expand.grid(Category=unique(Animals$Category),Reason=unique(Animals$Reason))
Animals3 <- merge(Animals3,Animals,by=c("Category","Reason"),all.x=TRUE)
Animals3[is.na(Animals3)] <- 0
Animals3 <- Animals3[order(Animals3$Category,-Animals3$Species),]
ggplot(Animals3, aes(x=Animals3$Reason, y=Species, fill = Category)) + geom_bar(stat="identity", position = "dodge") + scale_x_discrete(limits=as.character(Animals3[Animals3$Category=="Decline","Reason"]))
sebastiann
  • 163
  • 10
  • Similar to the solution i suggested, but with base R commands (no additionnal package). Nice. – agenis Aug 11 '16 at 13:46
1

To achieve something like that I would adjust the data frame when working with ggplot. Add the missing categories with a value of zero.

Animals <- rbind(Animals, 
                 data.frame(Category = c("Improved", "Decline"), 
                            Reason = c("Hello", "Bla"), 
                            Species = c(0,0)
                            )
)
Alex
  • 4,925
  • 2
  • 32
  • 48
  • +1 for this answer, but the problem is that you need to do it manually (and this is not what you want for a high and variable number of categories ;) ). I'll still give it a try! – tlorin Aug 11 '16 at 12:54
1

Along the same lines as the answer from user Alex, a less manual way of adding the categories might be

d <- with(Animals, expand.grid(unique(Category), unique(Reason)))
names(d) <- names(Animals)[1:2]
Animals <- merge(d, Animals, all.x=TRUE)
Animals$Species[is.na(Animals$Species)] <- 0
Weihuang Wong
  • 12,868
  • 2
  • 27
  • 48