如何在ggplot热图中为不同分组设置独立颜色渐变?
为ggplot热图的每个分组设置独立颜色渐变
要实现每个分组使用不同的颜色渐变,我们可以借助ggnewscale包来突破ggplot默认只能有一组填充映射的限制。下面是修改后的完整代码,以及关键步骤的解释:
完整代码
## dummy data ----------------------------------------------------------------------------- data <- data.frame( group = sample(c("Direct Patient Care", "Indirect Patient Care", "Education", "Rounds", "Handoff", "Misce"), 30, replace = T), pct = rnorm(30, mean = 50, sd = 8) ) ## generate group id data <- data %>% group_by(group) %>% mutate(id = row_number()) data$grpid <- with(data, ifelse(group == "Direct Patient Care", 1, ifelse(group == "Indirect Patient Care", 2, ifelse(group == "Education", 3, ifelse(group == "Rounds", 4, ifelse(group == "Handoff", 5,6 )))))) ## draw graph ------------------------------------------------------------------------------ library(ggplot2) library(dplyr) library(ggnewscale) # 先安装:install.packages("ggnewscale") p <- ggplot() + # Direct Patient Care:橙色渐变 geom_tile(data = filter(data, group == "Direct Patient Care"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "orange", high = "darkorange", limits = c(0, 80), name = "Direct Care\nTime, %") + new_scale_fill() + # 重置填充比例尺,用于下一个分组 # Indirect Patient Care:紫色渐变 geom_tile(data = filter(data, group == "Indirect Patient Care"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "plum", high = "purple", limits = c(0, 80), name = "Indirect Care\nTime, %") + new_scale_fill() + # Education:黄色渐变 geom_tile(data = filter(data, group == "Education"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "gold", high = "goldenrod", limits = c(0, 80), name = "Education\nTime, %") + new_scale_fill() + # Rounds:红色渐变(你的需求) geom_tile(data = filter(data, group == "Rounds"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "pink", high = "red", limits = c(0, 80), name = "Rounds\nTime, %") + new_scale_fill() + # Handoff:绿色渐变(你的需求) geom_tile(data = filter(data, group == "Handoff"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "lightgreen", high = "darkgreen", limits = c(0, 80), name = "Handoff\nTime, %") + new_scale_fill() + # Misce:蓝色渐变(你的需求) geom_tile(data = filter(data, group == "Misce"), aes(x = id, y = group, fill = pct)) + scale_fill_gradient2(low = "white", mid = "lightblue", high = "darkblue", limits = c(0, 80), name = "Misce\nTime, %") + # 保留你原来的主题设置 theme(panel.background = element_rect(fill = "white", colour = "grey50"), aspect.ratio = 0.4) + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + scale_x_continuous(name = " ", breaks = seq(1, 8, by = 1)) + scale_y_discrete(name = " ") + theme(axis.text.x = element_text(angle = 0, hjust = 1, vjust = 1), plot.title = element_text(hjust = 0.5)) + ggtitle("Heatmap of time spent doing activities across 194 shifts") print(p)
关键细节说明
ggnewscale核心作用:每次调用new_scale_fill(),ggplot会重置填充映射规则,让后续的geom_tile()可以使用完全独立的颜色渐变,不会和之前的分组冲突。- 按分组筛选数据:用
filter(data, group == "XXX")精准定位每个分组的数据集,确保每个geom_tile()只绘制对应分组的热图块。 - 统一数值标尺:所有渐变都设置了相同的
limits = c(0, 80),这样不同分组的颜色深浅能对应相同的百分比数值,保证可视化的准确性和可比性。 - 渐变自定义:你可以根据需求调整
scale_fill_gradient2的low(浅色调)、mid(中间色调)、high(深色调)参数;如果不需要中间色,改用scale_fill_gradient(仅需设置low和high)即可。
内容的提问来源于stack exchange,提问作者mandy




