Overlay two bar plots with geom_bar()

metazoa picture metazoa · Feb 12, 2017 · Viewed 13.2k times · Source

I'm trying to overlay two bar plots on top of each other, not beside. The data is from the same dataset. I want 'Block' on the x-axis and 'Start' and 'End' as overlaying bar plots.

    Block   Start       End
1    P1L     76.80       0.0
2    P1S     68.87       4.4
3    P2L     74.00       0.0
4    P2S     74.28       3.9
5    P3L     82.22       7.7
6    P3S     80.82      17.9

My script is

 ggplot(data=NULL,aes(x=Block))+
    geom_bar(data=my_data$Start,stat="identity",position ="identity",alpha=.3,fill='lightblue',color='lightblue4')+
    geom_bar(data=my_data$End,stat="identity",position ="identity",alpha=.8,fill='pink',color='red')

I get Error: ggplot2 doesn't know how to deal with data of class numeric

I've also tried

    ggplot(my_data,aes(x=Block,y=Start))+
      geom_bar(data=my_data$End, stat="identity",position="identity",...)

Anyone know how I can make it happen? Thank you.

Edit:

How to get dodge overlaying bars?

I edit this post, because my next question is relevant as it's the opposite problem of my original post.

@P.merkle

I had to change my plot into four bars showing the mean values of all Blocks labeled L and S. The L stand for littoral, and S for Sublittoral. They were exposed for two treatments: Normal and reduced.

I've calculated the means, and their standard deviation. I need four bars with their respective error bars: Normal/Littoral , Reduced/Littoral , Normal/Sublittoral , Reduced/Sublittoral.

Problem is when I plot it, both the littoral bars and both the sublittoral bars overlay each other! So now I want them not to overlap! How can i make it happen? I've tried all sorts of position = 'dodge' andposition = position_dodge(newdata$Force), without luck...

My newdata contain this information:

Zonation Force N mean sd se 1 Litoral Normal 6 0.000000 0.000000 0.000000 2 Litoral Redusert 6 5.873333 3.562868 1.454535 3 Sublitoral Normal 6 7.280000 2.898903 1.183472 4 Sublitoral Redusert 6 21.461667 4.153535 1.695674

My script is this:

ggplot(data=cdata,aes(x=newdata$Force,y=newdata$mean))+
        geom_bar(stat="identity",position ="dodge",
                 alpha=.4,fill='red', color='lightblue4',width = .6)+
        geom_errorbar(aes(ymin=newdata$mean-sd,ymax=newdata$mean+sd),
                      width=.2, position=position_dodge(.9))

The outcome is unfortunately this

As of the error bars, it's clearly four bars there, but they overlap. Please, how can I solve this?

Answer

Philipp Merkle picture Philipp Merkle · Feb 12, 2017

If you don't need a legend, Solution 1 might work for you. It is simpler because it keeps your data in wide format.

If you need a legend, consider Solution 2. It requires your data to be converted from wide format to long format.

Solution 1: Without legend (keeping wide format)

You can refine your aesthetics specification on the level of individual geoms (here, geom_bar):

ggplot(data=my_data, aes(x=Block)) +
  geom_bar(aes(y=Start), stat="identity", position ="identity", alpha=.3, fill='lightblue', color='lightblue4') +
  geom_bar(aes(y=End), stat="identity", position="identity", alpha=.8, fill='pink', color='red')

plot without legend

Solution 2: Adding a legend (converting to long format)

To add a legend, first use reshape2::melt to convert your data frame from wide format into long format. This gives you two columns,

  • the variable column ("Start" vs. "End"),
  • and the value column

Now use the variable column to define your legend:

library(reshape2)
my_data_long <- melt(my_data, id.vars = c("Block"))
ggplot(data=my_data_long, aes(x=Block, y=value, fill=variable, color=variable, alpha=variable)) +
  geom_bar(stat="identity", position ="identity") +
  scale_colour_manual(values=c("lightblue4", "red")) +
  scale_fill_manual(values=c("lightblue", "pink")) +
  scale_alpha_manual(values=c(.3, .8))

enter image description here