R语言小提琴图:如何保留均值实线并将分位数设为虚线?
Hey there! I totally get where you're coming from—working with @jan-glx's custom split violin function can lead to accidentally uniform line styles for all statistical lines. Let's fix that so your mean line stays solid, and the quartile lines switch to dashed. Here's how to do it step by step:
1. First, Make Sure You Have the Split Violin Function
First, let's include the full GeomSplitViolin definition from @jan-glx (since you mentioned using it):
# Define the split violin geom from @jan-glx 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, ...)) }
2. Plot with Custom Line Styles
The key issue is that the draw_quantiles parameter in the split violin function applies the same line style to all quantiles. Instead, we'll use stat_summary separately to add the mean (solid) and quartiles (dashed) with distinct styles:
library(ggplot2) library(plyr) # Required for the split violin function's arrange step # Create the plot with iris dataset ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) + # Draw split violin (no draw_quantiles here) geom_split_violin(trim = FALSE) + # Add solid mean line stat_summary(fun = mean, geom = "crossbar", width = 0.2, color = "black", linetype = 1, size = 0.5) + # Add dashed 25th quartile line stat_summary(fun = quantile, fun.args = list(probs = 0.25), geom = "crossbar", width = 0.2, color = "black", linetype = 2, size = 0.5) + # Add dashed 75th quartile line stat_summary(fun = quantile, fun.args = list(probs = 0.75), geom = "crossbar", width = 0.2, color = "black", linetype = 2, size = 0.5) + theme_minimal() + labs(title = "Split Violin Plot: Solid Mean, Dashed Quartiles", y = "Sepal Length", x = "Iris Species")
3. Alternative: Use draw_quantiles for Quartiles + Separate Mean
If you prefer to use the draw_quantiles parameter for quartiles, you can set those to dashed first, then overlay a solid mean line:
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) + geom_split_violin(trim = FALSE, draw_quantiles = c(0.25, 0.75), linetype = 2) + stat_summary(fun = mean, geom = "crossbar", width = 0.2, color = "black", linetype = 1, size = 0.5) + theme_minimal()
This works because the mean line is drawn on top of the violin and quartile lines, ensuring it's visible as a solid line.
内容的提问来源于stack exchange,提问作者Y.Coch

