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

如何基于指定分组创建层次聚类热图?含预处理验证

问题描述

我想要创建特定样式的热图:右侧色带分为4个分组,分别为Control > Rv, Ra、Rv> Ra > Control、Ra > Control > Rv、Ra > Rv > Control。该热图基于Euclidean距离矩阵构建,数据需经过FPKM归一化、log2转换(加1)及均值中心化处理。

示例FPKM表格(实际为85行×3列)

geneControlRaRv
Cyp27a132.6810004.5261613.3868
Serpinb21.611980513.1040020.7699
Rab7b118.96400020.7869043.3432
Ptgs20.328475371.3300029.0941
Mgat4a6.68007070.0953025.931
Acsl115.459900431.43400186.2550
Gas682.0422008.3916917.3220
Bcl2a1a4.162480395.8380099.9439
Zc3h12c7.45401043.0197018.7162
Bcl2a1d15.641200440.34900109.8670

已完成代码

df.set_index('gene', inplace=True)
df[['Control', 'Ra','Rv']] = df_deg[['Control', 'Ra','Rv']].add(1).apply(np.log2) # FPKM +1 and log transformed
df_cent = df.apply(lambda x:x-x.mean()) # mean centered

## Heatmap ##
map_plt= sns.clustermap(df_cent, metric="euclidean", cmap="RdBu_r", vmin=-8, vmax=6, 
               xticklabels=True, yticklabels=False)
map_plt.ax_col_dendrogram.set_visible(False)
plt.show()

当前生成的热图效果不符合预期,需手动调整vmin和vmax避免色块单一。现需解决两个问题:

  1. 如何按上述指定分组对热图进行排列?
  2. 我的log2转换与均值中心化步骤是否正确?

解决方案

1. 按指定分组排列热图

要实现自定义分组排序,需要先为每个基因匹配对应分组标签,再按指定顺序排序数据,最后关闭行聚类以保留自定义顺序,同时添加侧边分组色带。

实现代码

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

# 1. 为基因分配分组标签
def assign_group(row):
    ctrl, ra, rv = row['Control'], row['Ra'], row['Rv']
    if ctrl > rv and ctrl > ra:
        return 'Control > Rv, Ra'
    elif rv > ra and rv > ctrl:
        return 'Rv> Ra > Control'
    elif ra > ctrl and ra > rv:
        if ctrl > rv:
            return 'Ra > Control > Rv'
        else:
            return 'Ra > Rv > Control'
    else:
        return 'Other'  # 处理表达值相等的边界情况

df_cent['group'] = df_cent.apply(assign_group, axis=1)

# 2. 按指定分组顺序排序数据
target_order = ['Control > Rv, Ra', 'Rv> Ra > Control', 'Ra > Control > Rv', 'Ra > Rv > Control']
group_rank = {g:i for i,g in enumerate(target_order)}
df_sorted = df_cent.sort_values(by='group', key=lambda x: x.map(group_rank))

# 3. 准备分组侧边色带的颜色映射
group_colors = {
    'Control > Rv, Ra': '#1f77b4',
    'Rv> Ra > Control': '#ff7f0e',
    'Ra > Control > Rv': '#2ca02c',
    'Ra > Rv > Control': '#d62728'
}
row_colors = df_sorted['group'].map(group_colors)

# 4. 绘制热图(关闭行聚类,保留自定义顺序)
map_plt = sns.clustermap(
    df_sorted.drop('group', axis=1),
    metric="euclidean",
    cmap="RdBu_r",
    xticklabels=True,
    yticklabels=False,
    row_cluster=False,  # 关闭行聚类,使用自定义排序
    row_colors=row_colors  # 添加侧边分组色带
)

map_plt.ax_col_dendrogram.set_visible(False)

# 添加分组图例
handles = [Patch(color=c, label=g) for g,c in group_colors.items()]
map_plt.ax_heatmap.legend(handles=handles, bbox_to_anchor=(1.25, 1), loc='upper left')

plt.show()

2. log2转换与均值中心化步骤检查

你的代码存在两个细节问题,核心逻辑是正确的:

  • 变量名不一致:代码中用df_deg做转换,但前面是对df设置索引,会导致处理错误数据或报错,需统一变量名
  • 均值中心化方向:df.apply(lambda x:x-x.mean())默认按行处理(每个基因自身均值中心化),符合热图常规需求,但建议明确指定axis=1增强可读性

修正后的预处理代码

df.set_index('gene', inplace=True)
# 统一使用df,避免变量名错误
df[['Control', 'Ra','Rv']] = df[['Control', 'Ra','Rv']].add(1).apply(np.log2)  # FPKM+1后log2转换
df_cent = df.apply(lambda x: x - x.mean(), axis=1)  # 明确指定行方向的均值中心化

另外,关于vmin和vmax的手动调整问题,可以通过计算数据全局极值自动设置:

# 取对称边界,避免色块单一
abs_max = np.max(np.abs(df_cent.values))
vmin, vmax = -abs_max, abs_max

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:45:38