热图的基本组成:行、列、颜色映射、聚类树

一张热图,说白了就是一张“彩色表格”。

行、列、颜色、树——就这四样东西。很多初学者一上来对着热图发懵,觉得密密麻麻看不懂。其实拆开来看,每个部分都有自己明确的生物学含义。

我个人习惯是先看行和列,再看颜色,最后才看树。这个顺序能帮你快速抓住热图要讲的故事。

行与列——谁在行,谁在列?

在物种丰度热图里,行通常是物种(OTU/ASV/属/科等),列通常是样本(或分组)。你想想看,行方向展示了哪些物种丰度变化,列方向展示了不同样本之间怎么比较。这是最经典的布局。

但我在项目中遇到过一种坑:有些工具默认把行列反了。比如你用某个R包画热图,数据矩阵是样本×物种,它默认把样本当行、物种当列,出来的图就完全不对味。所以我每次画图前都会检查一下数据框的维度,确认行名是物种还是样本。

小技巧:先打印数据的前几行,看一眼行名的命名风格。如果是“OTU_1”、“Bacillus”这种,行就是物种;如果是“Sample_1”、“Control_1”,行就是样本。一眼就判断。

颜色映射——数值如何变成颜色?

颜色是热图的灵魂。每个单元格的颜色代表一个数值——通常是丰度(比如相对丰度、CPM、log2倍数变化)。数值映射到颜色的过程叫“颜色映射”(color mapping)。

常见的做法:低值映射到冷色(蓝/紫),高值映射到暖色(红/黄)。中间值用白色或浅色。这就是所谓的“发散色板”或“顺序色板”。

我记得有一次帮同事改图,他用了一个彩虹色板,红橙黄绿青蓝紫全上了。数据本身差异不大,结果整张图花花绿绿,评委根本看不出趋势。颜色不是越多越好,简单、可解释才是王道。

色板类型 适用场景 典型颜色 注意事项
顺序色板 丰度从低到高,只有一个方向 蓝→浅蓝→白→浅橙→红 避免色盲不友好(红绿)
发散色板 数值有正负,或需要突出中间值 紫→蓝→白→橙→红 中间值必须是中性色,否则误导
单色渐变 数据跨度小,强调连续变化 白→深蓝 高值区域难以区分细微差异
重要原则:颜色映射的数值范围必须和数据一致。如果数据有负数,必须用发散色板;如果全是正数,用顺序色板。不要硬套。

聚类树——让数据“排排站”

聚类树是热图的“排序系统”。它根据行和列的相似程度重新排列顺序,让相似的行靠在一起,相似的列也靠在一起。这样你一眼就能看出哪些物种在哪些样本里丰度相近,形成“模块”。

聚类树分为行聚类树和列聚类树。行聚类树告诉你哪些物种的行为相似(比如都在某组样本里高表达),列聚类树告诉你哪些样本的群落结构相似(比如都是处理组)。

常用的距离算法包括:Euclidean、Bray-Curtis、Jaccard、Pearson correlation。我建议:丰度数据先用Bray-Curtis或Jaccard,因为它们是专门为群落数据设计的,能处理零值多的情况。Euclidean在高维稀疏数据里表现很差,我吃过亏。

曾经踩过的坑:我用默认的Euclidean距离对OTU表聚类,出来的树乱成一团。后来换成Bray-Curtis,模块一下就清晰了。记住:热图聚类不是给数学考试用的,它反映的是生物学相似性。选对距离比选对算法重要。

聚类方法(连接法)通常有:complete、average、single、ward.D2。average(UPGMA)用得最多。ward.D2对数据分布有假设,适合连续性较好的数据。single容易产生“链状”效果,不常用。

把它们拼起来:一张完整的热图

下面这张SVG图把热图的四个组成部分的关系画清楚了。你可以当作“快速拆解地图”来用。

热图四大组成拆解 热图主体 颜色网格 列聚类树 样本分组 行聚 类树 物种关系 颜色映射 色板 数值→颜色 行/列标签 记忆口诀: 行物种,列样本,颜色代表丰度值,树帮数据排次序。 查看热图先看树,再看颜色区块,最后看具体数值。

实战代码片段:用seaborn画一张基础热图

下面是一段Python代码,展示了最核心的参数——你可以在Jupyter里直接跑。注意看row_cluster和col_cluster这两个参数,它们控制是否显示聚类树。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 模拟数据:10个物种 × 6个样本
np.random.seed(42)
species = [f"OTU_{i}" for i in range(10)]
samples = [f"Sample_{j}" for j in range(6)]
data = pd.DataFrame(
    np.random.dirichlet(np.ones(10), size=6).T,
    index=species,
    columns=samples
)

# 基本热图
plt.figure(figsize=(8, 6))
sns.clustermap(
    data,
    cmap="vlag",          # 发散色板
    method="average",     # 连接法 UP GMA
    metric="braycurtis",  # 距离算法
    row_cluster=True,     # 显示行聚类树
    col_cluster=True,     # 显示列聚类树
    z_score=0,            # 按行做标准化 (z-score)
    figsize=(8, 6)
)
plt.show()
关键参数说明:z_score=0 表示对每行(每个物种)做z-score标准化,让不同丰度水平的物种在同一个颜色尺度下可比。如果数据已经是相对丰度,可以不加。

避坑指南——关于聚类树的几个致命错误

  • 忘记标准化:如果有的物种平均丰度1000,有的只有1,直接聚类的话高丰度物种会主导距离,低丰度物种的差异被淹没。我建议先做log2或z-score标准化。
  • 列聚类顺序被破坏:有时候你希望样本按实验分组排列(比如Control、Treat1、Treat2),但聚类树会强行重排。这时可以关掉列聚类(col_cluster=False),手动指定列顺序。
  • 树高度解读错误:聚类树的高度代表“距离”,不是“相似度”。高度越大,差异越大。别搞反了。
曾经犯过的错:我把两个处理组的样本放在一起,列聚类树把它们混成一团,还以为是生物学变异大。后来才发现是我用的距离算法不对——Bray-Curtis对零值敏感,我用的是Euclidean,完全没考虑物种有无的问题。换了距离之后,分组立现。

好了,以上就是热图四个基本组成的拆解。你看,热图本质上就是一个加了排序系统的彩色表格。把行、列、颜色、树理解清楚,后面看什么热图都不虚。