如何在ggplot2分面小提琴图中添加分组观测数标注?
给分面小提琴图的每个小提琴添加观测数标注
需求:在分面小提琴图的每个小提琴旁标注绘制该小提琴所用的观测数量,现有未添加标注的示例代码:
library(ggplot2) library(dplyr) library(tidyverse) data("iris") c <- rep(c('r', 'g', 'b'), 50) c <- sample(c) facet_row <- rep(c('row1', 'row2', 'row3', 'row4', 'row5'), 30) facet_col <- rep(c('col1', 'col2', 'col3'), 50) iris$facet_rows <- facet_row iris$facet_cols <- facet_col iris$color <- c iris$count <- sample(1:10, size = 150, replace = T) p <- ggplot(iris, aes(x=Species, y=Petal.Length, fill=color)) + geom_violin(alpha = 0.7, na.rm = T) + coord_flip() + facet_grid(rows = vars(facet_rows), cols = vars(facet_cols)) print(p)
尝试两种方法均存在问题:
- 方法一:使用
stat_summary自定义函数,仅显示Species分组的总数,无法区分不同color子分组的观测数:
count_data <- function (y){ df <- data.frame(y = min(y) - 0.2, label = length(y)) return(df) } p <- ggplot(iris, aes(x=Species, y=Petal.Length, fill=color)) + geom_violin(alpha = 0.7, na.rm = T) + stat_summary(fun.data = count_data, geom = "text", aes(group = Species)) + coord_flip() + facet_grid(rows = vars(facet_rows), cols = vars(facet_cols)) print(p)
问题原因:group = Species参数强制按物种分组统计,忽略了color的子分组维度。
- 方法二:直接用
geom_text添加预计算的count字段,存在两个问题:同组小提琴的标注重叠在同一行、每个观测会重复绘制一次标注:
p <- ggplot(iris, aes(x=Species, y=Petal.Length, fill=color)) + geom_violin(alpha = 0.7, na.rm = T) + geom_text(aes(label=count, y=Petal.Length), nudge_y = -0.1) + coord_flip() + facet_grid(rows = vars(facet_rows), cols = vars(facet_cols)) print(p)
问题原因:原数据集每行对应一个观测,geom_text会逐行渲染;且未针对color分组调整位置,导致标注重叠。
正确实现方法
核心思路:先按分面维度(facet_rows、facet_cols)、Species、color全维度分组,计算每个小提琴对应的观测数,再用汇总后的数据集添加文本标注,同时通过位置对齐避免重叠。
步骤1:预计算分组观测数
# 按所有分组维度汇总,计算每个小提琴的观测数,同时确定标注的y轴位置 label_data <- iris %>% group_by(facet_rows, facet_cols, Species, color) %>% summarise( n = n(), y_pos = min(Petal.Length) - 0.3, # 标注固定在小提琴下方 .groups = "drop" )
步骤2:绘制带标注的小提琴图
p <- ggplot(iris, aes(x=Species, y=Petal.Length, fill=color)) + geom_violin(alpha = 0.7, na.rm = T, position = position_dodge(width = 0.8)) + # 添加观测数标注,使用汇总后的数据集,位置与小提琴对齐 geom_text( data = label_data, aes(x=Species, y=y_pos, label = paste0("n=", n), group = color), position = position_dodge(width = 0.8), # 和小提琴的分组位置匹配 size = 3 ) + coord_flip() + facet_grid(rows = vars(facet_rows), cols = vars(facet_cols)) print(p)
关键说明:
group_by包含所有维度,确保每个小提琴对应唯一的观测数统计结果。position_dodge(width = 0.8)让标注和小提琴的分组位置完全对齐,避免同组内的标注重叠。- 用
y_pos固定标注在小提琴下方,避免标注随观测值波动。
内容的提问来源于stack exchange,提问作者Muslimbek Abduganiev
相关产品推荐
相关产品推荐

