ggplot热力图定制着色需求:指定区域纯色+按距离梯度着色
解决方案:自定义热力图Tile着色逻辑
问题描述
我想用热力图绘制以下数据,已经得到了想要的热力图布局,但无法按预期给Tiles着色。当前代码是根据Tile内的数值比例着色,不符合需求。我需要:
- 两个指定矩形区域内的Tiles分别统一着色(左侧为黄色,右侧为蓝色);
- 其余Tiles根据其到蓝色区域的距离,呈现从黄色到蓝色的渐变效果。
修改后的代码实现
核心思路是给每个Tile分配自定义颜色:直接指定固定区域的颜色,对渐变区域计算其到蓝色区域的距离,再映射到黄蓝渐变色谱上。
library(tidyverse) library(scales) # 生成模拟数据集 set.seed(1243) test1_score <- sample(c(3.5, 3.8, 4), 200, replace = TRUE) test2_score <- round(runif(200, 0, 38)) test2_class <- ifelse(test2_score < 20, "non meet", ifelse(test2_score < 30, "below 40th", ifelse(test2_score < 35, "above 40th", ifelse(test2_score < 37, "meet", "master")))) exit_program <- ifelse(test1_score == 4 & test2_class %in% c("above 40th", "meet", "master"), 1, 0) df <- data.frame(ID = 1:200, test1_score, test2_class, exit_program) # 分组统计并添加颜色逻辑 df2 <- df |> group_by(test1_score, test2_class, exit_program) |> summarize(n = n(), .groups = "drop") |> mutate( test2_class = factor(test2_class, levels = c("non meet", "below 40th", "above 40th", "meet", "master")), # 转换因子为数值坐标,方便计算距离 x_num = as.integer(test2_class), y_num = as.integer(as.factor(test1_score)), # 为每个Tile分配颜色 tile_color = case_when( # 左侧区域统一黄色 test2_class == "non meet" ~ "#F0E442", # 右侧指定区域统一蓝色 test2_class %in% c("above 40th", "meet", "master") & test1_score == 4 ~ "#56B4E9", # 剩余区域:根据到蓝色区域的距离生成渐变颜色 TRUE ~ { # 蓝色区域的坐标是(x=3/4/5, y=3),计算当前Tile到这些点的最小曼哈顿距离 min_dist <- pmin(abs(x_num - 3), abs(x_num - 4), abs(x_num - 5)) + abs(y_num - 3) # 归一化距离到0-1范围,0对应最接近蓝色,1对应最接近黄色 norm_dist <- (min_dist - min(min_dist)) / (max(min_dist) - min(min_dist)) # 生成黄蓝渐变的中间色 colour_ramp(c("#56B4E9", "#F0E442"))(norm_dist) } ) ) |> arrange(test2_class) # 绘制热力图 df2 |> ggplot(aes(x = test2_class, y = as.factor(test1_score))) + theme( legend.position = "none", panel.background = element_rect(fill = "white"), axis.text = element_text(size = 12), axis.title = element_text(size = 14) ) + geom_tile(aes(fill = tile_color)) + geom_text(aes(label = n), size = 7, family = "sans") + labs(x = "分类", y = "分数") + scale_fill_identity() + # 使用自定义的tile_color作为填充色 # 添加区域边框 geom_rect(aes(xmin = 2.5, xmax = 5.5, ymin = 2.5, ymax = 3.5), linewidth = 2, color = "#0072B2", fill = NA) + geom_rect(aes(xmin = 0.5, xmax = 1.5, ymin = 0.5, ymax = 3.5), linewidth = 2, color = "#E69F00", fill = NA)
代码说明
颜色分配逻辑:
- 左侧
non meet列的所有Tile直接设置为黄色#F0E442 - 右侧
above 40th/meet/master且test1_score=4的Tile直接设置为蓝色#56B4E9 - 其余Tile计算到蓝色区域的最小曼哈顿距离,将距离归一化后映射到黄蓝渐变色谱,距离越近颜色越蓝,越远越黄
- 左侧
关键函数:
case_when():分条件定义颜色规则colour_ramp():生成渐变颜色的函数,输入起始和结束颜色,输出对应比例的中间色scale_fill_identity():直接使用数据框中的颜色值作为填充色,替代默认的数值映射
内容的提问来源于stack exchange,提问作者Michael Matta
相关产品推荐
相关产品推荐

