Thursday, October 30, 2014

10 30 2014 Dual Y Axis Graph (ggplot2) % Brooding vs Temperature Oyster Bay

Here I'm showing how to produce a dual Y axis graph with ggplot2 package in R. If you've tried to do this before you know it downright impossible. I found a great work around in the rpubs from a user named Hadley. Below is my code to produce a dual axis bar and line graph. I'm doing this to show the percent of animals brooding at each time point along with the associated temperature at that time point.  Broodperctemp.R
require(plyr)
## Loading required package: plyr
require(ggplot2)
## Loading required package: ggplot2
require(scales)
## Loading required package: scales
require(grid)
## Loading required package: grid
require(gtable)
## Loading required package: gtable
grid.newpage()
p1<-ggplot(data=oysbay, aes(x=Date, weight=Percent, colour=Pop, fill=Pop))+
  geom_bar(binwidth=10, position=position_dodge())+
  theme(axis.text.x=element_text(angle=90, size=10, vjust=0.5))+
  scale_colour_manual(values=c("blue","purple","orange"),labels=c("Dabob","Fidalgo","Oyster Bay"))+
  scale_fill_manual(values=c("blue","purple","orange"),labels=c("Dabob","Fidalgo","Oyster Bay"))+
  labs(x="Sample Date", y="Percent Brooding",title="Percent Brooding vs. Temperature")+
  theme_bw()+
  theme(legend.justification=c(0,1),
        legend.position=c(0,1),
        plot.title=element_text(size=30,vjust=1),
        axis.text.x=element_text(size=20),
        axis.text.y=element_text(size=20),
        axis.title.x=element_text(size=20),
        axis.title.y=element_text(size=20))
oysy1edit<-read.csv("TempData/oysY1fixed.csv")
oysy1edit$Date<-as.Date(oysy1edit$Date, "%m/%d/%Y")
oysmintemp<-ddply(oysy1edit,.(Date),summarise,min_temp=min(Temp,na.rm=T))
oysmintemprep<-subset(oysmintemp, Date>="2014-05-01"& Date<="2014-08-07")
p2<-ggplot()+geom_line(data=oysmintemprep,
            aes(x=Date, y=min_temp), color="red")+
  geom_hline(yintercept=12.5, color="forestgreen")+
  theme_bw() %+replace% 
  theme(panel.background = element_rect(fill = NA),
        panel.grid.major.x=element_blank(),
        panel.grid.minor.x=element_blank(),
        panel.grid.major.y=element_blank(),
        panel.grid.minor.y=element_blank(),
        axis.text.y=element_text(size=20,color="red"),
        axis.title.y=element_text(size=20))

g1<-ggplot_gtable(ggplot_build(p1))
g2<-ggplot_gtable(ggplot_build(p2))

pp<-c(subset(g1$layout,name=="panel",se=t:r))
g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]],pp$t,pp$l,pp$b,pp$l)

ia<-which(g2$layout$name=="axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)

grid.draw(g)
plot of chunk unnamed-chunk-1


It's really important to note that I have subset the temperature data for only the daily minimums and  only from the date of the first sampling to the date of the last sampling. If you don't do this, the temp graph will be fit onto the graph regardless of whether it correlates to the dates on the x axis. My first version was really screwy because of this. Also note that for some reason when using this method you cannot create a legend for the line graph nor can you generate a title for the right hand y axis. It's not the best but it will make a good looking graph for you if you know these limitations. 

13 comments:

  1. How can I add the second y axis label?

    ReplyDelete
    Replies
    1. Sadl, I have been able to figure out how to create a second Y axis label using this code. The way I do it is I export the graph as a jpeg or TIFF and add the label manually in MSPaint.

      Delete
    2. No worries, I did it in power point, thanks for the script, it is really useful.

      Delete
  2. HI Jake,
    It's pretty work! thanks. I have only a problem. I have a similar scale for the Y axes, but appears in negative values (left axis) . Do you know how I could fix that problem? thanks in advance.....

    ReplyDelete
    Replies
    1. Hi r,

      I'm not sure what your asking for but with some simple modifications using ggplot you should be able to set the second axis to whatever you'd like. You just need to make sure that you are editing the P1 graph instead of the P2 graph.

      Delete
  3. Hi Jake,
    This is great! I am trying to do this for multi-panel figure using facet_grid, but I get an error at the following line:
    g<-gtable_add_grob(g1,g2$grobs[[which(g2$layout$name=="panel")]],pp$t,pp$l,pp$b,pp$l)

    Error in g2$grobs[[which(g2$layout$name == "panel")]] :
    no such index at level 2

    Any suggestions? Thanks!
    Matt

    ReplyDelete
    Replies
    1. I haven't tried to use the facet_grid function with these graphs. Since the code it self needs to render each individual graph before combining them into a single graph, the facet_grid function will probably not work as it renders multiple versions of each graph. You could try running facet_grid on the p1 and p2 graph to ensure that both are being created with equal number of graphs to overlay but that could get messy and complicated really quick. This bit of code can be pretty finnicky when it comes to producing the graphs, the best option would probably be to run the code without facet_grid producing individual plots and then stitch them together in an image editor. Sorry I couldn't be more helpful.

      Delete
    2. Oh no this has been incredibly helpful! I will probably go with stitching them together but figured I'd see if there was quick fix. Thanks again for sharing your code and responding so quickly!
      Matt

      Delete
  4. Hello Jake,

    This is pretty awesome script. Thanks a lot!!!

    I have been replicating the same with two line graphs. But I keep on getting the following error:
    Error in Ops.unit(ax$grobs[[1]]$x, unit(1, "npc")) :
    both operands must be units

    Can you please help. I haven't really changed the script.

    ReplyDelete
  5. Hi Jake,

    thanks for the script, It is working good so far. However, unfortunately the themes for the second y-axis (your red axis) are not taken for the merged graph. Is that a general issue? Thanks!

    ReplyDelete
  6. Hi there, thanks a lot for your script! I have a problem, though, which consists in the fact that after running the script I see no data at all within the panel. My idea was to have a bar plot and a line plot, each with an individual Y axis.

    I keep getting these two errors:

    g1 <- ggplot_gtable(ggplot_build(p1))
    Error: stat_count() must not be used with a y aesthetic.
    > g2 <- ggplot_gtable(ggplot_build(p2))
    geom_path: Each group consists of only one observation. Do you need to adjust the group aesthetic?

    Any ideas? Thanks!

    ReplyDelete
  7. make sense, I had not think of it before, well anyways, thanks for sharing mate! keep posted! naveed ahmed

    ReplyDelete
  8. I heard about this naming agency from several people that it gives online courses in making company names. With their information-rich lessons, you will never run out of creative ideas. daycare photography

    ReplyDelete