> p <- ggplot(mtcars, aes(mpg))
> p + geom_ribbon(aes(ymax = ..density.., ymin = - ..density..), stat =
> "density") + facet_grid(cyl ~ .)
>
Argh that' so cool!
Instead of being clever, as above, I created a clunky geom-like
function a while back. It used to work very well but now has some
display issues on some of my data. The only advantage relative to the
solution by learnr is that you get one x axis instead of facets which
probably looks cleaner when there are many levels. The main
disadvantages is less flexibility/integration within ggplot and
different scales for the density estimates: all violins are the same
width (you'll see what I mean when comparing with the plot by learnr).
Maybe someone can improve on that and provide the best of both worlds.
geom_violin <- function(data, mapping, bw="nrd0", adjust=1,
kernel="gaussian", ...)
#
# geom-like function to draw violin plots with ggplot2. Analogous to
boxplots
# default aesthetics:
# x grouping factor, on the x axis
# y variable
# arguments passed to density
# bw
# adjust
# kernel
# ... passed to density and to geom_polygon
#
{
x = deparse(mapping$x)
y = deparse(mapping$y)
molten = melt(data, measure.var=y)
nbByX = cast(molten, formula=paste(x, "~ variable"),
fun.aggregate=length)
# remove levels for which there are less thant 2 points because
density estimate fails
molten = molten[molten[[x]]%in%(nbByX[nbByX[y]>2,x]),]
molten[[x]] = factor(molten[[x]]) # remove potentially absent factor
levels?
# densities = cast(molten, formula=paste(x, "~ variable"),
fun.aggregate=density)
# why doesn't this work?
# do it 'by hand'
moltenL = split(molten$value, molten[[x]])
densities = lapply(moltenL, function(x, bw, adjust, kernel, ...){
# compute density
out = density(x, bw=bw, adjust=adjust, kernel=kernel, ...)
out = data.frame(y=out$x, dens=out$y)
# scale density
out$dens = out$dens/max(out$dens) * 0.45 # max is 0.45
# duplicate it to make a nice polygon
out2 = data.frame(y=rev(out$y), dens=-rev(out$dens))
out = rbind(out,out2,NA)
}, bw=bw, adjust=adjust, kernel=kernel, ...)
# x scale has step of 1
for (i in 1:length(densities)) {
densities[[i]]$dens = i + densities[[i]]$dens
}
xLabels = names(densities)
densities = do.call("rbind",densities)
# build geom and set correct scale
g = geom_polygon(data=densities, mapping=aes(x=dens, y=y), ...)
s = scale_x_continuous(breaks=1:length(xLabels), labels=xLabels)
return(list(g,s))
}
ggplot() + geom_violin(mtcars, aes(x=cyl, y=mpg))
JiHO
---
http://jo.irisson.free.fr/