如何在R的ggplot中为每个类别设置渐变颜色生成热力表?
解决ggplot热力图因数值范围差异导致小数值颜色无区分的问题
我明白你的问题——当不同类别的数值跨度极大时(比如你的A列数值集中在80-100,D列集中在0-10),全局统一的颜色渐变会让小数值列的细节完全被掩盖,根本看不出数值差异。下面我给你几个实用的解决方案,帮你给每个类别设置独立的颜色渐变,突出每列内部的数值重要性:
第一步:修正并整理你的数据
首先先把你的数据代码补全语法错误,转为数据框并整理成长格式(ggplot做热力图需要长数据格式):
set.seed(123) # 设置随机种子,保证结果可复现 library(dplyr) library(tidyr) library(ggplot2) # 修正数据生成代码 dt <- as.data.frame( cbind( rbinom(10, 100, 0.9), rbinom(10, 100, 0.5), rbinom(10, 100, 0.2), rbinom(10, 100, 0.05) ) ) colnames(dt) <- c("A", "B", "C", "D") dt$row <- paste0("Row_", 1:10) # 添加行标识,方便热力图展示 # 转为长格式 dt_long <- dt %>% pivot_longer(-row, names_to = "column", values_to = "value")
方案1:归一化数值(快速简单,突出相对差异)
如果你的重点是看每个类别内部的相对大小,而非绝对数值,可以对每列进行0-1归一化,把所有数值映射到同一区间,再用统一颜色渐变:
# 对每个类别单独归一化 dt_long_norm <- dt_long %>% group_by(column) %>% mutate(norm_value = scales::rescale(value, to = c(0, 1))) %>% ungroup() # 绘制热力图 ggplot(dt_long_norm, aes(x = column, y = row, fill = norm_value)) + geom_tile(color = "white") + # 白色边框区分单元格 geom_text(aes(label = value), size = 3) + # 显示原始数值 scale_fill_gradient(low = "#f7fbff", high = "#08306b", name = "归一化值") + labs(title = "按类别归一化后的热力图", x = "类别", y = "行") + theme_minimal()
优点:实现简单,能快速对比每个类别内部的数值相对差异;缺点:丢失了原始数值的绝对大小信息,无法直接对比不同类别间的绝对数值。
方案2:分面独立颜色标尺(保留绝对数值,可读性强)
如果需要保留原始数值的同时看清每个类别内部的差异,推荐用patchwork包把每个类别的热力图单独绘制后拼接,每个图用独立的颜色渐变:
library(patchwork) # 为每个类别单独绘制热力图,自定义颜色渐变 plot_A <- ggplot(filter(dt_long, column == "A"), aes(x = column, y = row, fill = value)) + geom_tile(color = "white") + geom_text(aes(label = value), size = 3) + scale_fill_gradient(low = "#fff7bc", high = "#cc4c02", name = "A类数值") + labs(x = NULL, y = "行") + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1)) plot_B <- ggplot(filter(dt_long, column == "B"), aes(x = column, y = row, fill = value)) + geom_tile(color = "white") + geom_text(aes(label = value), size = 3) + scale_fill_gradient(low = "#f1eef6", high = "#990000", name = "B类数值") + labs(x = NULL, y = NULL) + theme_minimal() + theme(axis.text.y = element_blank()) plot_C <- ggplot(filter(dt_long, column == "C"), aes(x = column, y = row, fill = value)) + geom_tile(color = "white") + geom_text(aes(label = value), size = 3) + scale_fill_gradient(low = "#e5f5f9", high = "#2ca25f", name = "C类数值") + labs(x = NULL, y = NULL) + theme_minimal() + theme(axis.text.y = element_blank()) plot_D <- ggplot(filter(dt_long, column == "D"), aes(x = column, y = row, fill = value)) + geom_tile(color = "white") + geom_text(aes(label = value), size = 3) + scale_fill_gradient(low = "#fef0d9", high = "#d7301f", name = "D类数值") + labs(x = NULL, y = NULL) + theme_minimal() + theme(axis.text.y = element_blank()) # 拼接所有图 plot_A + plot_B + plot_C + plot_D + plot_layout(nrow = 1) + plot_annotation(title = "每个类别独立颜色标尺的热力图")
优点:每个类别用独立的颜色渐变,能清晰看到内部数值差异,同时保留原始数值;还可以给每个类别设置不同的颜色主题,强化类别区分;缺点:需要多写几行代码,但逻辑很清晰。
方案3:同一图内多颜色标尺(适合同一视图对比)
如果你想把所有类别放在同一个热力图里,同时用不同的颜色渐变,可以用ggnewscale包实现多组颜色标尺:
library(ggnewscale) ggplot() + # 绘制A类 geom_tile(data = filter(dt_long, column == "A"), aes(x = column, y = row, fill = value), color = "white") + geom_text(data = filter(dt_long, column == "A"), aes(x = column, y = row, label = value), size = 3) + scale_fill_gradient(low = "#fff7bc", high = "#cc4c02", name = "A类数值") + # 新建颜色标尺 new_scale_fill() + # 绘制B类 geom_tile(data = filter(dt_long, column == "B"), aes(x = column, y = row, fill = value), color = "white") + geom_text(data = filter(dt_long, column == "B"), aes(x = column, y = row, label = value), size = 3) + scale_fill_gradient(low = "#f1eef6", high = "#990000", name = "B类数值") + new_scale_fill() + # 绘制C类 geom_tile(data = filter(dt_long, column == "C"), aes(x = column, y = row, fill = value), color = "white") + geom_text(data = filter(dt_long, column == "C"), aes(x = column, y = row, label = value), size = 3) + scale_fill_gradient(low = "#e5f5f9", high = "#2ca25f", name = "C类数值") + new_scale_fill() + # 绘制D类 geom_tile(data = filter(dt_long, column == "D"), aes(x = column, y = row, fill = value), color = "white") + geom_text(data = filter(dt_long, column == "D"), aes(x = column, y = row, label = value), size = 3) + scale_fill_gradient(low = "#fef0d9", high = "#d7301f", name = "D类数值") + labs(title = "同一图内多颜色标尺的热力图", x = "类别", y = "行") + theme_minimal()
优点:所有类别在同一视图,方便横向对比;缺点:图例较多,可能会占用较多空间,需要注意排版。
内容的提问来源于stack exchange,提问作者Mehmet Yildirim
相关产品推荐
相关产品推荐

