1

To create a split violin plot in ggplot, I have used the geom_split_violin function created by jan-glx below. This function is very handy for two or more groups, and I was wondering if there was a way to utilize this function for only one group? I am aiming to create a split violin plot where the only categorical variable is gender (male/female).

GeomSplitViolin <- ggproto("GeomSplitViolin", GeomViolin, 
                           draw_group = function(self, data, ..., draw_quantiles = NULL) {
  data <- transform(data, xminv = x - violinwidth * (x - xmin), xmaxv = x + violinwidth * (xmax - x))
  grp <- data[1, "group"]
  newdata <- plyr::arrange(transform(data, x = if (grp %% 2 == 1) xminv else xmaxv), if (grp %% 2 == 1) y else -y)
  newdata <- rbind(newdata[1, ], newdata, newdata[nrow(newdata), ], newdata[1, ])
  newdata[c(1, nrow(newdata) - 1, nrow(newdata)), "x"] <- round(newdata[1, "x"])

  if (length(draw_quantiles) > 0 & !scales::zero_range(range(data$y))) {
    stopifnot(all(draw_quantiles >= 0), all(draw_quantiles <=
      1))
    quantiles <- ggplot2:::create_quantile_segment_frame(data, draw_quantiles)
    aesthetics <- data[rep(1, nrow(quantiles)), setdiff(names(data), c("x", "y")), drop = FALSE]
    aesthetics$alpha <- rep(1, nrow(quantiles))
    both <- cbind(quantiles, aesthetics)
    quantile_grob <- GeomPath$draw_panel(both, ...)
    ggplot2:::ggname("geom_split_violin", grid::grobTree(GeomPolygon$draw_panel(newdata, ...), quantile_grob))
  }
  else {
    ggplot2:::ggname("geom_split_violin", GeomPolygon$draw_panel(newdata, ...))
  }
})

geom_split_violin <- function(mapping = NULL, data = NULL, stat = "ydensity", position = "identity", ..., 
                              draw_quantiles = NULL, trim = TRUE, scale = "area", na.rm = FALSE, 
                              show.legend = NA, inherit.aes = TRUE) {
  layer(data = data, mapping = mapping, stat = stat, geom = GeomSplitViolin, 
        position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
        params = list(trim = trim, scale = scale, draw_quantiles = draw_quantiles, na.rm = na.rm, ...))
}

ggplot(my_data, aes(x, y, fill = m)) + geom_split_violin()
  • 1
    welcome to SO. Please always provide the link to where you got code from. Also please try to create a reroducible example, for example on an inbuilt data set. In its current form, this question is very difficult to answer, thus I suggest it be closed – tjebo Nov 25 '21 at 13:57
  • It should be from https://newbedev.com/split-violin-plot-with-ggplot2 – danlooo Nov 25 '21 at 14:54
  • @danlooo do you know anything about that site? The post you linked to seems to just plagiarize the answers from [this post](https://stackoverflow.com/q/35717353/5325862). Not accusing *you* of plagiarizing, I just don't know what's going on with that site – camille Nov 27 '21 at 00:54
  • @camille me neither. This was just a quick googleing for me to add bit of context to the question. – danlooo Nov 27 '21 at 09:30

1 Answers1

0

There is geom_violinhalf from the see package:

library(tidyverse)
library(see)

ggplot(iris, aes(x = "x", y = Sepal.Length, fill = Species)) +
  geom_violinhalf(
    data = iris %>% filter(Species == "setosa")
  ) +
  geom_violinhalf(
    data = iris %>% filter(Species == "versicolor"),
    flip = TRUE
  )

Created on 2021-11-25 by the reprex package (v2.0.1)

danlooo
  • 10,067
  • 2
  • 8
  • 22
  • Amazing! Thanks for that. One follow-up: do you know if there is a way to include mean and median lines, or quantiles into geom_violinhalf plots? I was able to add these elements to ordinary violin plots (according to syntax from http://www.sthda.com/english/wiki/ggplot2-violin-plot-quick-start-guide-r-software-and-data-visualization), but for a split violin plot, it seems to require something more advanced. – Volkerballoon Nov 26 '21 at 05:03
  • Try geom_point with position dodge. Or simulate another geom violin half e.g. only with median values. – danlooo Nov 26 '21 at 08:23