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

如何用ggplot geom_tile将两个相关性统计量合并为一个三角热图

合并双数据热图:分区域展示不同指标

问题描述

我用以下R代码生成了两个相关性统计热图,分别以d1和r1作为填充值,但每个热图都有一半区块信息重复。由于两个热图坐标轴完全一致,希望将它们合并为一个热图:

  • 上三角(或下三角)区块展示d1值,采用绿色系渐变配色
  • 另一三角区块展示r1值,采用红色系渐变配色
  • 对角线区块使用第三种固定颜色

原始代码:

dt <- data.frame(
  h = rep(LETTERS[1:5], 5), 
  j = c(rep("A", 5), rep("B", 5), rep("C", 5), rep("D", 5), rep("E", 5)),
  d1 = c(1, 0.717, 0.089, 0.027, 1, 0.717, 1, 0.11, 0.03, 1, 0.089, 0.11,
         1, 0.464, 0.835, 0.027, 0.03, 0.464, 1, 1, 1, 1, 0.835, 1, 1), 
  r1 = c(1, 0.462, 0.002, 0.001, 0.001, 0.462, 1, 0.003, 0.001, 0.001, 0.002,
         0.003, 1, 0.054, 0.004, 0.001, 0.001, 0.054, 1, 0.001, 0.001, 0.001, 0.004, 0.001, 1)
)

# 以d1为填充值的热图
ggplot(dt, aes(x = h, y = j, fill = d1)) + 
  geom_tile(color = "black") +
  scale_fill_gradient(low = "white", high = "green") +
  geom_text(aes(label = d1), color = "black", size = 4) +
  coord_fixed() +
  theme_minimal() +
  labs(x = "", y = "", fill = "D")

# 以r1为填充值的热图
ggplot(dt, aes(x = h, y = j, fill = r1)) + 
  geom_tile(color = "black") +
  scale_fill_gradient(low = "white", high = "red") +
  geom_text(aes(label = r1), color = "black", size = 4) +
  coord_fixed() +
  theme_minimal() +
  labs(x = "", y = "", fill = "r")

解决方案

方案1:无需额外包,单比例尺适配

通过分区域绘制tile,用统一的渐变比例尺覆盖绿色和红色区间,适合快速实现:

library(ggplot2)
library(dplyr)

# 预处理数据:转换因子并添加索引判断区域
dt$h <- factor(dt$h, levels = LETTERS[1:5])
dt$j <- factor(dt$j, levels = LETTERS[1:5])
dt$h_idx <- as.integer(dt$h)
dt$j_idx <- as.integer(dt$j)

# 绘制合并热图
ggplot(dt) +
  # 上三角展示d1(绿色渐变)
  geom_tile(data = filter(dt, h_idx > j_idx), aes(x = h, y = j, fill = d1), color = "black") +
  # 下三角展示r1(红色渐变)
  geom_tile(data = filter(dt, h_idx < j_idx), aes(x = h, y = j, fill = r1), color = "black") +
  # 对角线固定灰色
  geom_tile(data = filter(dt, h_idx == j_idx), aes(x = h, y = j), fill = "gray50", color = "black") +
  # 自定义渐变:白-绿-红,覆盖0-1数值范围
  scale_fill_gradientn(colors = c("white", "forestgreen", "firebrick"),
                       values = c(0, 0.5, 1), limits = c(0, 1), name = "数值") +
  # 添加对应区域的数值标签
  geom_text(data = filter(dt, h_idx > j_idx), aes(x = h, y = j, label = round(d1, 3)), size = 4, color = "black") +
  geom_text(data = filter(dt, h_idx < j_idx), aes(x = h, y = j, label = round(r1, 3)), size = 4, color = "black") +
  geom_text(data = filter(dt, h_idx == j_idx), aes(x = h, y = j, label = "1"), size = 4, color = "white") +
  coord_fixed() +
  theme_minimal() +
  labs(x = "", y = "")

方案2:使用ggnewscale实现双独立图例

如果需要分别展示d1和r1的渐变图例,推荐使用ggnewscale包添加第二个填充比例尺,更清晰专业:

library(ggplot2)
library(dplyr)
library(ggnewscale)

# 预处理数据
dt$h <- factor(dt$h, levels = LETTERS[1:5])
dt$j <- factor(dt$j, levels = LETTERS[1:5])
dt$h_idx <- as.integer(dt$h)
dt$j_idx <- as.integer(dt$j)

# 绘制合并热图
ggplot(dt) +
  # 上三角:d1绿色渐变,对应第一个图例
  geom_tile(data = filter(dt, h_idx > j_idx), aes(x = h, y = j, fill = d1), color = "black") +
  scale_fill_gradient(low = "white", high = "forestgreen", name = "D值") +
  # 新建填充比例尺,用于下三角的r1
  new_scale_fill() +
  # 下三角:r1红色渐变,对应第二个图例
  geom_tile(data = filter(dt, h_idx < j_idx), aes(x = h, y = j, fill = r1), color = "black") +
  scale_fill_gradient(low = "white", high = "firebrick", name = "R值") +
  # 对角线固定灰色
  geom_tile(data = filter(dt, h_idx == j_idx), aes(x = h, y = j), fill = "gray50", color = "black") +
  # 添加数值标签
  geom_text(data = filter(dt, h_idx > j_idx), aes(x = h, y = j, label = round(d1, 3)), size = 4, color = "black") +
  geom_text(data = filter(dt, h_idx < j_idx), aes(x = h, y = j, label = round(r1, 3)), size = 4, color = "black") +
  geom_text(data = filter(dt, h_idx == j_idx), aes(x = h, y = j, label = "1"), size = 4, color = "white") +
  coord_fixed() +
  theme_minimal() +
  labs(x = "", y = "")

关键说明

  • 通过h_idx和j_idx判断每个区块的位置(上三角、下三角、对角线),实现分区域数据展示
  • 方案1适合快速可视化,方案2的双图例更便于区分两个指标的数值梯度
  • 可根据需求调整配色、标签精度和对角线样式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:57:36