I've spent quite a bit of time trying to develop a specific geom_bar plot with 2 y-axes (the dual-axes are a work requirement).
I've made the plots look acceptable, except there are some inaccuracies with the bar width and bar placement that I can't explain/fix.
The current plot looks like this:
I realize it's hard to see, but some of the biggest issues are as follows:
(1) The bar widths vary. For example, in the N2T_1 facet, the green bars are different widths. I've tried setting width in geom_bar, which I found out was actually using a proportion of the space. I also tried adjusting the width in combination with position_dodge, which is my current code.
(2) The bars are not located exactly where they should be. In N2U_2, the tallest green bar occurs in 1999 according to the data, but when zoomed in on the ggplot, it shows up in 1998, while the 2000 value shows up in 1999.
(3) The shifted bars are not consistently shifted. In N2U_6,the tallest green bar should occur in 2008, but it is appearing in 2009 in the graph.
I'm not sure if I've made an error in my code, or if I'm missing something that should be in there. I'd appreciate any suggestions for how to fix these issues.
Current code:
# Left y-axis
p1 <- ggplot(data=DSCORE_CankDamage_N2, aes(x=Year, y=Dscore, group=Unique_ID_Tree))
p1 <- p1 + geom_rect(data=DSCORE_CankDamage_N2, aes(xmin=1965, xmax=1967, ymin=min(Dscore, na.rm=T), ymax=max(Dscore, na.rm=T)), alpha=0.1, fill="light goldenrod")
p1 <- p1 + geom_rect(data=DSCORE_CankDamage_N2, aes(xmin=1995, xmax=1997, ymin=min(Dscore, na.rm=T), ymax=max(Dscore, na.rm=T)), alpha=0.1, fill="light goldenrod")
p1 <- p1 + geom_rect(data=DSCORE_CankDamage_N2, aes(xmin=1999, xmax=2001, ymin=min(Dscore, na.rm=T), ymax=max(Dscore, na.rm=T)), alpha=0.1, fill="light goldenrod")
p1 <- p1 + geom_rect(data=DSCORE_CankDamage_N2, aes(xmin=2007, xmax=2009, ymin=min(Dscore, na.rm=T), ymax=max(Dscore, na.rm=T)), alpha=0.1, fill="light goldenrod")
p1 <- p1 + geom_hline(color="blue", linetype="dashed", aes(yintercept=0))
p1 <- p1 + geom_line(color="black")
p1 <- p1 + scale_x_continuous(limits=c(1945,2015), breaks=seq(1950,2010,10))
p1 <- p1 + ylab("Dscore")
p1 <- p1 + ggtitle("Annual Tree Decline (Dscore) and Total Canker Width (cm) per Year, Site N2")
p1 <- p1 + theme_bw() + theme(plot.margin=unit(c(1,1,1,1), "lines"),
plot.title=element_text(hjust=0.5, face="bold", family="Times New Roman", size=12, color="black"),
axis.title=element_text(size=12, family="Times New Roman", color="black"),
axis.text.y=element_text(size=10, family="Times New Roman", color="black"),
axis.text.x=element_text(size=10, family="Times New Roman", color="black", angle=90, vjust=0.5),
strip.text=element_text(size=9, family="Times New Roman"),
strip.background=element_rect(fill="azure2", colour="black",size=0.5),
strip.text.x=element_text(margin=margin(.1, 0, .1, 0, "cm")))
p1 <- p1 + facet_wrap(~Unique_ID_Tree, ncol=3, nrow=4)
# Right y-axis
p2 <- ggplot(data=DSCORE_CankDamage_N2, aes(x=Year, y=Cank_Width_cm))
p2 <- p2 + geom_bar(fill="darkgreen", alpha=0.6, width=0.6, position=position_dodge(width=0.9), stat="identity")
p2 <- p2 + facet_wrap(~Unique_ID_Tree, ncol=3, nrow=4)
p2 <- p2 + theme(plot.margin=unit(c(1,1,1,1), "lines"),
axis.title.y=element_text(size=12, color="black"),
axis.text=element_text(size=10, family="Times New Roman", color="black"),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.background = element_rect(fill="transparent", colour = NA),
plot.background = element_rect(fill = "transparent", colour = NA))
# Combine left y-axis with right y-axis
p <- ggplot_dual_axis_facet(p1, p2)
grid.newpage()
png("DscoreWidthCankersClimate_N2.png", width=1000, height=600, units="px")
grid.draw(p)
grid.text("Width of Cankers (cm) per Year, per Tree", x=unit(0.95, "npc"), y=unit(0.5, "npc"), rot=90, gp=gpar(col="black", fontsize=12, fontfamily="Times New Roman"))
dev.off()
Dual-axis function developed by another user from an earlier question:
#Plotting 2 axes, writing a dual axis plot function WITH FACET_WRAP!:
ggplot_dual_axis_facet <- function(p1, p2) {
#Extract gtable
library(gtable) # loads the grid package
g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))
#Overlap the panel of the 2nd plot on that of the 1st plot
pp <- c(subset(g1$layout, grepl("panel",name), se = t:r))
g <- gtable_add_grob(g1, g2$grobs[grep("panel",g2$layout$name)],
pp$t, pp$l, pp$b, pp$l)
#Tweak axis position and labels
ia <- which(grepl("axis_l",g2$layout$name) | grepl("axis-l",g2$layout$name))
ga <- g2$grobs[ia]
axis_idx <- as.numeric(which(sapply(ga,function(x) !is.null(x$children$axis))))
for(i in 1:length(axis_idx)){
ax <- ga[[axis_idx[i]]]$children$axis
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[axis_idx[i]], ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t[axis_idx[i]], length(g$widths) - i, pp$b[axis_idx[i]])
}
# Display plot with arrangeGrob wrapper arrangeGrob(g)
library(gridExtra)
grid.newpage()
return(arrangeGrob(g))
}
Reproducible sample (reduced to 1990-2012 and just 3 samples to save space):
DSCORE_CankDamage_N2 <- structure(list(Year = c(1990, 1990, 1990, 1991, 1991, 1991, 1992,
1992, 1992, 1993, 1993, 1993, 1994, 1994, 1994, 1995, 1995, 1995,
1996, 1996, 1996, 1997, 1997, 1997, 1998, 1998, 1998, 1999, 1999,
1999, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2003,
2003, 2003, 2004, 2004, 2004, 2005, 2005, 2005, 2006, 2006, 2006,
2007, 2007, 2007, 2008, 2008, 2008, 2009, 2009, 2009, 2010, 2010,
2010, 2011, 2011, 2011, 2012, 2012, 2012), Unique_ID_Tree = c("N2T_1",
"N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2",
"N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6",
"N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1",
"N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2",
"N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6",
"N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1",
"N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2",
"N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6",
"N2T_1", "N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6", "N2T_1",
"N2U_2", "N2U_6", "N2T_1", "N2U_2", "N2U_6"), Dscore = c(-3.88097140918747,
-1.61672655331958, -0.800904163207618, -1.63987714337736, -1.27356679469661,
-0.123389213996389, -1.67470063459416, -1.53446926434865, 1.41432216204886,
-2.93976791454954, -2.22110579039093, 0.179787740964598, -0.496345860693154,
-2.25219836976259, 0.283128654684994, -1.02422222229106, -4.13093925848588,
-2.00025863911258, -1.42277115507557, -2.20286053942706, -1.59680054370485,
-4.67382100536604, -2.37506096226093, -2.8807566057491, -3.3382779475486,
-1.64425464849276, -3.27011139841957, -3.69418205392501, -2.786090370905,
-2.15312648161092, -2.03541950882678, -0.236513361147938, -1.080355218023,
-0.744061467812739, -0.51452406800711, -2.13834789020542, 1.28548134814991,
0.102783247605922, -8.60943620132279, 0.552638091261848, -2.6016685191023,
-2.00359494680614, 1.09364751195267, 0.0228740916470703, -0.727749095761693,
2.45361880473052, -0.700263607694208, 0.992436651274041, 5.55685390970607,
0.0126595727091467, -0.885094834004169, 0.286395340453474, -0.674875047272186,
-2.56290086784948, -1.6992770884242, 0.0858528219338089, -4.68307024987756,
-7.19053429537607, -0.688092915132032, -1.90683437925634, -3.31079202975985,
-2.00738870428399, -1.28966583325364, -1.35761860429989, -0.517228296926095,
-2.49977175344713, 0.558525687352873, 0.855141372994123, -1.00932485695081
), Cank_Width_cm = c(0, 0, 0.09398, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.90068, 0, 0, 0, 0, 0, 11.05916,
33.24606, 0.1397, 0.7112, 2.54508, 2.06248, 0, 0.4572, 3.11404,
0.86106, 0, 4.9784, 0, 0, 0, 0, 0, 0, 0, 3.27152, 0.09906, 0,
0.78994, 0, 0, 0, 0, 0, 0.61722, 29.5402, 0, 1.88722, 0, 0.08382,
2.43332, 0.25654, 0, 0.28956, 0, 0, 0.79756, 0), Canks_Per_Year = c(0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 3, 11, 1, 2, 3, 3, 0, 1, 4, 1, 0, 5, 0, 0, 0,
0, 0, 0, 0, 4, 1, 0, 1, 0, 0, 0, 0, 0, 2, 17, 0, 5, 0, 1, 6,
1, 0, 1, 0, 0, 2, 0)), .Names = c("Year", "Unique_ID_Tree", "Dscore",
"Cank_Width_cm", "Canks_Per_Year"), row.names = c(333L, 340L,
344L, 345L, 352L, 356L, 357L, 364L, 368L, 369L, 376L, 380L, 381L,
388L, 392L, 393L, 400L, 404L, 405L, 412L, 416L, 417L, 424L, 428L,
429L, 436L, 440L, 441L, 448L, 452L, 453L, 460L, 464L, 465L, 472L,
476L, 477L, 484L, 488L, 489L, 496L, 500L, 501L, 508L, 512L, 513L,
520L, 524L, 525L, 532L, 536L, 537L, 544L, 548L, 549L, 556L, 560L,
561L, 568L, 572L, 573L, 580L, 584L, 585L, 592L, 596L, 597L, 604L,
608L), class = "data.frame")