Skip to content

Instantly share code, notes, and snippets.

@dgrtwo
Last active April 3, 2024 10:55
Show Gist options
  • Save dgrtwo/eb7750e74997891d7c20 to your computer and use it in GitHub Desktop.
Save dgrtwo/eb7750e74997891d7c20 to your computer and use it in GitHub Desktop.
# somewhat hackish solution to:
# https://twitter.com/EamonCaddigan/status/646759751242620928
# based mostly on copy/pasting from ggplot2 geom_violin source:
# https://github.com/hadley/ggplot2/blob/master/R/geom-violin.r
library(ggplot2)
library(dplyr)
"%||%" <- function(a, b) {
if (!is.null(a)) a else b
}
geom_flat_violin <- function(mapping = NULL, data = NULL, stat = "ydensity",
position = "dodge", trim = TRUE, scale = "area",
show.legend = NA, inherit.aes = TRUE, ...) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomFlatViolin,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
trim = trim,
scale = scale,
...
)
)
}
#' @rdname ggplot2-ggproto
#' @format NULL
#' @usage NULL
#' @export
GeomFlatViolin <-
ggproto("GeomFlatViolin", Geom,
setup_data = function(data, params) {
data$width <- data$width %||%
params$width %||% (resolution(data$x, FALSE) * 0.9)
# ymin, ymax, xmin, and xmax define the bounding rectangle for each group
data %>%
group_by(group) %>%
mutate(ymin = min(y),
ymax = max(y),
xmin = x,
xmax = x + width / 2)
)
},
draw_group = function(data, panel_scales, coord) {
# Find the points for the line to go all the way around
data <- transform(data, xminv = x,
xmaxv = x + violinwidth * (xmax - x))
# Make sure it's sorted properly to draw the outline
newdata <- rbind(plyr::arrange(transform(data, x = xminv), y),
plyr::arrange(transform(data, x = xmaxv), -y))
# Close the polygon: set first and last point the same
# Needed for coord_polar and such
newdata <- rbind(newdata, newdata[1,])
ggplot2:::ggname("geom_flat_violin", GeomPolygon$draw_panel(newdata, panel_scales, coord))
},
draw_key = draw_key_polygon,
default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5,
alpha = NA, linetype = "solid"),
required_aes = c("x", "y")
)
### Example:
ggplot(diamonds, aes(cut, carat)) +
geom_flat_violin() +
coord_flip()
@mvuorre
Copy link

mvuorre commented Jan 4, 2017

Hi, are there any plans to include this in future versions of ggplot2? The geom is great and would be great to have it more easily accessible.

Thanks for sharing

@sahirmoosvi
Copy link

sahirmoosvi commented Jan 18, 2017

In case someone needs to find that comma... The mutate command has two end braces when it should just have one.

mutate(ymin = min(y),
    ymax = max(y), 
    xmin = x,
    xmax = x + width / 2)
)                      # <---- Take this one out

@Maja-Ilic-AquaEco
Copy link

This is so great! I will most definitely use this for a figure within a manuscript which I am preparing for publication. Please let me know if there is any need to cite the code and how. And thanks for this great contribution!

@gtw248
Copy link

gtw248 commented Mar 12, 2019

Has anyone managed to extend this example to include quantile bars?

@Zhangcambium2019
Copy link

One question, what does the vertical line inside the violin plot represents?

@annecar
Copy link

annecar commented Jan 7, 2020

I am running your script to produce Raincloud plots and receieve the following error:

Error in layer(data = data, mapping = mapping, stat = stat, geom = GeomFlatViolin, :
unused arguments (data = data, mapping = mapping, stat = stat, geom = GeomFlatViolin, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list(trim = trim, scale = scale, ...))

Any idea where this comes from?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment