Here is some example data for a hypothetical meta-analysis on the effectiveness of sports-promotion interventions for which I would like to create a forest plot:
example.df = data.frame(Author = c("McAuliffe et al.", "Palen et al.", "Manning et al.", "Richters et al.", "Grello et al.","Mpofu et al.", "Kuo & St Lawrence", "Langstrom & Hanson", "Ompad et al.", "Abdullah et al.","Yan", "Peltzer & Pengpid", "Lo & Wei", "Haggstrom-Nordin et al.", "Mwaba & Naidoo", "Hughes et al.","Lydie et al.", "Zimmer-Gembeck et al.", "Babalola", "Garos et al.", "Pinkerton et al."),
Sport = c("Basketball", "Basketball", "Baseball", "Dance", "Baseball", "Dance", "Wrestling","Wrestling", "Dance", "Baseball", "Wrestling", "Dance", "Swimming", "Swimming","Basketball", "Basketball", "Basketball", "Basketball", "Basketball", "Swimming", "Wrestling"),
Gender = c("Male", "Female", "Male", "Male", "Female", "Male", "Male", "Male", "Male", "Female","Female", "Male", "Female", "Female", "Female", "Male", "Female", "Female", "Female", "Male", "Female"),
d = c(-0.12, 0.53, 0.11, 0.02, 0.32, 0.04, 0.03,0.04,0.26, 0.76, 1.11, 0.34, 0.77, 1.19, 0.59, 0.15, 0.30, 0.81, 0.12, 0.11, 1.01),
d_SE = c(.10, .04, .06, .01, .11, .08, .08, .04, .05, .05, .14, .07, .05, .08, .19, .16, .07, .16, .06, .18, .15))
The data frame contains author names, the sport, whether the sample was male or female, the effect size for the intervention, and the standard error of the effect size. I am hoping to create a dot plot mapping shape to gender, and faceting by the particular sport. After following examples in Chang's "cookbook" and this related query, I've come up with the following code that meets most of my formatting needs:
p<-ggplot(example.df, aes(x=Author, y=d, ymin=d-1.96*d_SE, ymax=d+1.96*d_SE,shape=Gender))+
geom_pointrange() +
coord_flip()+
scale_y_continuous(limits=c(-2,2),breaks=c(-2,-1.5,-1,-0.5,0,.5,1,1.5,2))+
geom_hline(yintercept=0, color="grey60",linetype="dashed")+
theme_bw()+
theme(panel.grid.major.x=element_blank(),panel.grid.minor.x=element_blank(),panel.grid.major.y=element_line(color="grey60",linetype="dashed"))+
facet_grid(Sport ~ ., scales="free_y")
p
My problem, however, is that the resulting plots for each facet (below) have every author in the entire data frame plotted on the y-axis (technically x-axis, but the axes are flipped). Instead, I only want the authors with data relevant to a given facet to be plotted on the author-associated axis of that facet, so each facet should have a different list of authors on the axis.
I had thought the scales="free_y"
component of the facet_grid
layer would ensure a unique author axis for each facet (I've also tried scales="free_x"
, given the inverted axes), but this is not having the intended effect.
Does anyone know of a way that I could ensure that the only author names that appear on each facet's axis are the ones with associated data for that facet?
Flip cartesian coordinates so that horizontal becomes vertical, and vertical, horizontal. This is primarily useful for converting geoms and statistics which display y conditional on x, to x conditional on y.
It allows drawing of data points anywhere on the plot, including in the plot margins. If limits are set via xlim and ylim and some data points fall outside those limits, then those data points may show up in places such as the axes, the legend, the plot title, or the plot margins.
Andrie's right, in that coord_flip()
seems to be the root of the issue. However, the convention for forest plot formatting is to have the author names on y-axis, so I wanted to find a way that still would meet this formatting requirement.
The accepted answer in the post that Gregor commented on actually solves my issue; the only required change was that I had to calculate columns for upper-bound/lower-bound values of the confidence intervals.
So now with the updated data frame:
example.df = data.frame(Author = c("McAuliffe et al.", "Palen et al.", "Manning et al.", "Richters et al.", "Grello et al.","Mpofu et al.", "Kuo & St Lawrence", "Langstrom & Hanson", "Ompad et al.", "Abdullah et al.","Yan", "Peltzer & Pengpid", "Lo & Wei", "Haggstrom-Nordin et al.", "Mwaba & Naidoo", "Hughes et al.","Lydie et al.", "Zimmer-Gembeck et al.", "Babalola", "Garos et al.", "Pinkerton et al."),
Sport = c("Basketball", "Basketball", "Baseball", "Dance", "Baseball", "Dance", "Wrestling","Wrestling", "Dance", "Baseball", "Wrestling", "Dance", "Swimming", "Swimming","Basketball", "Basketball", "Basketball", "Basketball", "Basketball", "Swimming", "Wrestling"),
Gender = c("Male", "Female", "Male", "Male", "Female", "Male", "Male", "Male", "Male", "Female","Female", "Male", "Female", "Female", "Female", "Male", "Female", "Female", "Female", "Male", "Female"),
d = c(-0.12, 0.53, 0.11, 0.02, 0.32, 0.04, 0.03,0.04,0.26, 0.76, 1.11, 0.34, 0.77, 1.19, 0.59, 0.15, 0.30, 0.81, 0.12, 0.11, 1.01),
d_SE = c(.10, .04, .06, .01, .11, .08, .08, .04, .05, .05, .14, .07, .05, .08, .19, .16, .07, .16, .06, .18, .15),
ci.low = c(-.30, .45, .00, -.01, .11, -.12, -.14, -.04, .16, .66, .84, .19, .68, 1.03, .22, -.17, .17, .50, .00, -.23, .72),
ci.high = c(.07, .62, .22, .05, .53, .20, .19, .11, .36, .87, 1.38, .47, .86, 1.35, .97,.47, .43, 1.11, .24, .46, 1.30))
#reorder Author based on value of d, so effect sizes can be plotted in descending order
example.df$Author<-reorder(example.df$Author, example.df$d, FUN=mean)
...and then for the plot (without any coord_flip()
usage):
p <- ggplot(example.df, aes(y = Author, x = d, xmin = ci.low, xmax = ci.high, shape=Gender)) +
geom_point() +
geom_errorbarh(height = .1) +
scale_x_continuous(limits=c(-2,2),breaks=c(-2,-1.5,-1,-0.5,0,.5,1,1.5,2))+
geom_vline(xintercept=0, color="grey60",linetype="dashed")+
facet_grid(Sport ~ ., scales = "free", space = "free") +
theme_bw() +
theme(strip.text.y = element_text(angle = 0))
p
Very nice--thanks for all the suggestions and help troubleshooting this plot!
It seems that coord_flip()
and free scales in the facets don't work well together. This is a known issue (number 95 in the ggplot2 issue log) and indications are that the fix is a huge rewrite and will not be done soon. Hadley says:
Free scales aren't going to be working with non-Cartesian coordinates systems for a long time :/
This means your only workaround may be to remove the coord_flip()
. For example:
Try this:
library(ggplot2)
ggplot(example.df, aes(x=Author, y=d, ymin=d-1.96*d_SE, ymax=d+1.96*d_SE, shape=Gender, col=Gender))+
geom_pointrange() +
# coord_flip()+
scale_y_continuous(limits=c(-2,2),breaks=c(-2,-1.5,-1,-0.5,0,.5,1,1.5,2))+
theme_bw()+
theme(
panel.grid.major.x=element_blank(),
panel.grid.minor.x=element_blank(),
axis.text.x = element_text(angle=90, hjust=1)
) +
facet_grid(. ~ Sport, scales="free_x", space="free_x", shrink=TRUE, drop=TRUE)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With