1
votes

I am working on a bar graph that shows counts of cats and dogs that differ across countries. Cats and dogs are levels stored in different factors/ variables. I want to plot the bars for each animal count on top of the other (i.e. 2 layers), and then I want to order the bars from the tallest (i.e. highest count) to lowest according to animal frequency per country.

Here is what I did:

  1. Order the data table according to animal counts per country

     plot <- within(plot, country <- factor(country, 
     levels=names(sort(table(country), decreasing=TRUE))))
    
  2. Plot the graph

    gg <- ggplot(data = plot, aes(x=country))
    
  3. Add bar for dogs

    dogs <- gg + 
    geom_bar(data = plot[plot$animal1 == 'dog',], #select dogs from animal1 variable
    stat="count")
    

If I do that, I get this (with one geom_bar):

img

So far, so good. Next, I add the second geom_bar for the cats:

dogs_cats <- gg + 
geom_bar(data = plot[plot$animal1 == 'dog',], #select dogs from animal1 variable
stat="count") +
geom_bar(data = plot[plot$animal2 == 'cat',], #select cats from animal2 variable
stat="count")

Now the order is changed and off-key (after the second geom_bar):

img

How can I maintain the order of the bars to follow the initial geom_bar?

Many thanks!

2

2 Answers

2
votes

I suggest you to use merge to create a new data frame:

1.Sum up (ddply and melt)

require(plyr) #ddply
require(reshape2) # melt

df = ddply(plot, "country", summarize, dogs = sum(animal1 == "dog"), 
cats = sum(animal2 == "cat"))
dogs_and_cats = melt(df, id = "country")

You might have a new data frame with 3 columns:

  • country
  • variable: "dog" or "cat"
  • value: number of dogs/cats (per country)

2.Plot

ggplot(dogs_and_cats , aes(x = reorder(country, -value), y = value, fill = variable)) +
geom_bar(stat = "identity", position = "dodge")

3.Example:

Here is an example with the diamonds dataset, without a reproducible example:

df = ddply(diamonds, "cut", summarize, J = sum(color == "J"), 
D = sum(color == "D"))
plot = melt(df, id = "cut")

ggplot(plot, aes(x = reorder(cut, -value), y = value, fill = variable)) +
geom_bar(stat = "identity", position = "dodge")

enter image description here

0
votes

Hoom, I did like your code but the order of bars didn't change. Perhaps you made a simple mistake somewhere.

library(ggplot2)
# make a sample data
set.seed(1); d <- data.frame(animal1 = sample(c("dog", "other"), replace=T, 10000, prob=c(0.7,0.3)), 
                             animal2 = sample(c("cat", "other"), replace=T, 10000, prob=c(0.3,0.7)), 
                             country = sample(LETTERS[1:15], replace=T, 10000, prob=runif(15,0,1)))
levels(d$country)     # [1] "A" "B" "C" "D" ...
plot <- within(d, country <- factor(country, levels=names(sort(table(country), decreasing=TRUE))))
levels(plot$country)  # [1] "N" "O" "L" "F" ...

gg <- ggplot(data = plot, aes(x=country))
dogs <- gg + geom_bar(data = plot[plot$animal1 == "dog",], stat="count", fill="darkblue")
dogs_cats <- gg + 
  geom_bar(data = plot[plot$animal1 == "dog",], stat="count", fill="darkblue") +
  geom_bar(data = plot[plot$animal2 == "cat",], stat="count", fill="blue")

print(dogs)
print(dogs_cats)     # I made below img using library(grid) to form two graphs.

plot