You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ggplot热力图定制着色需求:指定区域纯色+按距离梯度着色

解决方案:自定义热力图Tile着色逻辑

问题描述

我想用热力图绘制以下数据,已经得到了想要的热力图布局,但无法按预期给Tiles着色。当前代码是根据Tile内的数值比例着色,不符合需求。我需要:

  1. 两个指定矩形区域内的Tiles分别统一着色(左侧为黄色,右侧为蓝色);
  2. 其余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)

代码说明

  1. 颜色分配逻辑:

    • 左侧non meet列的所有Tile直接设置为黄色#F0E442
    • 右侧above 40th/meet/master且test1_score=4的Tile直接设置为蓝色#56B4E9
    • 其余Tile计算到蓝色区域的最小曼哈顿距离,将距离归一化后映射到黄蓝渐变色谱,距离越近颜色越蓝,越远越黄
  2. 关键函数:

    • case_when():分条件定义颜色规则
    • colour_ramp():生成渐变颜色的函数,输入起始和结束颜色,输出对应比例的中间色
    • scale_fill_identity():直接使用数据框中的颜色值作为填充色,替代默认的数值映射

内容的提问来源于stack exchange,提问作者Michael Matta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:25:19