如何用ggplot2按分组变量实现分面分色直方图(无外部依赖)
分面直方图按组内阈值分色(不依赖ggplot外部环境)
需求:创建分面直方图,每个分面基于自身组的自定义阈值(以中位数为例)将直方图柱子分为不同颜色,且不能引用ggplot()外部的环境变量。单直方图已实现该效果,但分面尝试未成功。
单直方图成功实现示例
以下代码可实现单直方图按中位数分色:
set.seed(123) value = stats::rnorm(100, mean = 0, sd = 1) df = data.frame(value) df %>% { ggplot(data = ., aes(x = value, fill = ifelse(value > median(value), "0", "1"))) + geom_histogram(boundary = median(.$value), alpha = 0.5, position = "identity") + theme(legend.position = "none") }

分面尝试失败案例
尝试为每个分面使用组内中位数阈值,但boundary参数全局计算,导致分面未按组内阈值拆分:
set.seed(456) value = stats::rnorm(200, mean = 0, sd = 1) group = c(rep(1,100), rep(2,100)) df = data.frame(value, group) df %>% dplyr::mutate(value = ifelse(group == 2, value + 1, value)) %>% dplyr::group_by(group) %>% dplyr::mutate(above_median = value > median(value)) %>% { ggplot(data = ., aes(x = value, fill = above_median)) + facet_grid(rows = group) + geom_histogram(boundary = median(.$value), alpha = 0.5, position = "identity") + theme(legend.position = "none") }

解决方案
核心问题是geom_histogram的boundary参数默认全局计算,未按组拆分。以下两种方法均可实现需求,且不依赖ggplot外部环境:
方法1:按组生成图层后组合
利用group_split拆分数据,为每个组单独生成直方图图层,再组合到分面图中:
set.seed(456) value = stats::rnorm(200, mean = 0, sd = 1) group = c(rep(1,100), rep(2,100)) df = data.frame(value, group) %>% dplyr::mutate(value = ifelse(group == 2, value + 1, value)) %>% dplyr::group_by(group) %>% dplyr::mutate(above_median = value > median(value)) # 按组生成直方图图层 layer_list <- df %>% dplyr::group_split() %>% purrr::map(function(sub_df) { group_median <- median(sub_df$value) geom_histogram( data = sub_df, aes(x = value, fill = above_median), boundary = group_median, alpha = 0.5, position = "identity" ) }) # 组合图层并分面 ggplot() + layer_list + facet_grid(rows = vars(group)) + theme(legend.position = "none")
方法2:提前计算组内阈值,结合stat_bin
先为每个组计算阈值,再在stat_bin中绑定组内阈值作为boundary:
set.seed(456) value = stats::rnorm(200, mean = 0, sd = 1) group = c(rep(1,100), rep(2,100)) df = data.frame(value, group) %>% dplyr::mutate(value = ifelse(group == 2, value + 1, value)) %>% dplyr::group_by(group) %>% dplyr::mutate(group_median = median(value)) %>% ungroup() ggplot(df, aes(x = value, fill = value > group_median, group = group)) + facet_grid(rows = vars(group)) + stat_bin( boundary = aes(x = group_median), alpha = 0.5, position = "identity" ) + theme(legend.position = "none")
两种方法均能让每个分面独立使用自身组的阈值,实现柱子分色的效果,且未引用ggplot()外部的环境变量。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

