I have a very simple dataset (2 groups, n=15 per group). Using ggplot2, I can easily plot a violin plot or a box plot of the two groups. However, I would like to graph a violin plot, but have the fill shade correspond to the 3 quartiles of my data.
There is an example done in SAS here but I would like to do this in R.
1 Answer 1
Like this using ggplot_build() to get the outlines?
EDIT UPDATED TO SHOW QUANTILE OF THE ORIGINAL DATA
require(ggplot2) # for ggplot
require(dplyr) # for mutation
df<-data.frame( # make sample data
grp=rep(1:6,each=15),
val=c(rnorm(15,runif(1)*5,runif(1)),
rnorm(15,runif(1)*5,runif(1)),
rnorm(15,runif(1)*5,runif(1)),
rnorm(15,runif(1)*5,runif(1)),
rnorm(15,runif(1)*5,runif(1)),
rnorm(15,runif(1)*5,runif(1))
)
)
g<-ggplot(df)+geom_violin(aes(x=grp,y=val,group=grp),color="darkred",fill="darkred",size=2) # build the base violins
coords<-ggplot_build(g)$data # use ggbuild to get the outline co-ords
d<-coords[[1]] # this gets the df in a usable form
groups<-unique(d$group) # get the unique "violin" ids
# function to create geom_ploygon calls
fill_viol<-function(v,gr){
quants<-mutate(v,x.l=x-violinwidth/2,x.r=x+violinwidth/2,cuts=cut(y,quantile(df[df$grp==gr,"val"]))) # add 1/2 width each way to each x value
plotquants<-data.frame(x=c(quants$x.l,rev(quants$x.r)), # left x bottom to top, then right x top to bottom
y=c(quants$y,rev(quants$y)), # double up the y values to match
id=c(quants$cuts,rev(quants$cuts)))# cut by quantile to create polygon id
geom_polygon(aes(x,y,fill=as.factor(id)),data=plotquants) # return the geom_ploygon object
}
g + # plot g
lapply(groups,function(x)fill_viol(d[d$group==x,],x)) + # plus polygon objects for each violin
scale_fill_brewer(palette="Reds", # plus fill
name="Quantile\n",
labels=c("25","50","75","100")) +
coord_flip()
enter image description here
Sign up to request clarification or add additional context in comments.
3 Comments
Josh
Yes, thank you! This is what I was looking for. I'm not so sure how the code works exactly, but is it possible to break up the polygons by quantile(df$grp) instead of just breaking up the vertical space in 25% blocks?
Troy
Yes - I'd actually meant to do this, but calculated the quantile of the violin coords which are regularly spaced, rather than the original values - oops. I've corrected the code, and flipped the chart so it looks more like your example.
Jan Stanstrup
Any idea of how to get this to work with facets? It seems quite strambled if I just add a facet_grid or facet_wrap.
lang-r