如何在tidyverse的ggplot2中修改箱线图分位数为20%和80%
问题
使用tidyverse的ggplot2绘制箱线图时,如何将默认的25%/75%分位数(Q1/Q3)替换为20%和80%分位数?目前已能通过qboxplot包的probs参数实现,但ggplot2中尝试多种方法未成功,需要绘制7个分组的箱线图。
样本数据
dataset <- structure( list( PM1 = c(0.4, 6.2, 5.1, 7.8, 8, NA, NA, 5.2), PM2 = c(2, 8, 5.6, 8, NA, 6.4, 10.3, 7), PM3 = c(NA, 7.2, 4.8, 4.4, NA, NA, 10.3, 5.9), PM4 = c(1.2, 8.7, 5.4, NA, NA, NA, NA, NA), PM5 = c(3.5, NA, 1.9, 2.2, NA, 3.5, 9.4, 0.3), PM6 = c(1.3, NA, 1.1, NA, NA, 2.8, NA, NA), PM7 = c(NA, NA, NA, 0.4, NA, NA, 8.8, 0.6)), row.names = c(NA, -8L), class = c("tbl_df", "tbl", "data.frame") )
已实现的qboxplot代码
library(qboxplot) dataset %>% qboxplot( main = "Dissolved Oxygen", probs = c(0.20, 0.50, 0.80), ylim = c(0, 12), ylab = "mg/L", xlab = "Monitoring Points" )
现有ggplot2代码(未实现自定义分位数)
library(tidyverse) dataset %>% pivot_longer( cols = everything(), names_to = "monitoring_point", values_to = "oxigenio_dissolvido" ) %>% ggplot( aes(x = monitoring_point, y = oxigenio_dissolvido) )+ stat_boxplot( geom = "errorbar", width = 0.3, position = position_dodge(width = 0.65) )+ geom_boxplot()+ labs(title = "Dissolved Oxygen", y = "oxigenio_dissolvido (mg/L)")+ scale_y_continuous( expand = expansion(mult = c(0,0)), limits = c(0, 12) )+ theme_bw()+ theme( plot.title = element_text(hjust = 0.5) )
解决方案
ggplot2的geom_boxplot()和stat_boxplot()默认使用boxplot.stats()计算分位数,要替换为20%/80%分位数,需自定义统计函数,并在两个图层中指定该函数来统一计算逻辑。
修改后的完整代码
library(tidyverse) # 自定义箱线图统计量计算函数,返回20%/50%/80%分位数及须的范围 custom_boxplot_stats <- function(x) { x <- na.omit(x) # 计算指定分位数 qs <- quantile(x, probs = c(0.2, 0.5, 0.8), na.rm = TRUE) # 基于自定义IQR计算须的上下限(沿用1.5*IQR逻辑) iqr <- qs[3] - qs[1] lower_whisker <- max(min(x), qs[1] - 1.5*iqr) upper_whisker <- min(max(x), qs[3] + 1.5*iqr) # 返回ggplot2要求的结构 tibble( ymin = lower_whisker, lower = qs[1], middle = qs[2], upper = qs[3], ymax = upper_whisker ) } dataset %>% pivot_longer( cols = everything(), names_to = "monitoring_point", values_to = "oxigenio_dissolvido" ) %>% ggplot( aes(x = monitoring_point, y = oxigenio_dissolvido) )+ # 给误差线指定自定义统计函数 stat_boxplot( geom = "errorbar", width = 0.3, position = position_dodge(width = 0.65), fun.data = custom_boxplot_stats )+ # 给箱线图指定自定义统计函数,保持分组对齐 geom_boxplot( position = position_dodge(width = 0.65), fun.data = custom_boxplot_stats )+ labs(title = "Dissolved Oxygen", y = "oxigenio_dissolvido (mg/L)", x = "Monitoring Points")+ scale_y_continuous( expand = expansion(mult = c(0,0)), limits = c(0, 12) )+ theme_bw()+ theme( plot.title = element_text(hjust = 0.5) )
关键说明
- 必须同时修改
stat_boxplot()和geom_boxplot()的fun.data参数:两者会独立计算统计量,只有同时指定才能让误差线和箱线图的分位数保持一致。 - 自定义函数中保留了默认的须部计算逻辑(1.5*IQR),但IQR替换为80%分位数与20%分位数的差值,若需调整须部规则可修改这部分代码。
- 两个图层的
position_dodge(width)参数需保持一致,避免箱线与误差线错位。
内容的提问来源于stack exchange,提问作者leonardofwink
相关产品推荐
相关产品推荐

