1. 为什么需要相关性热图与散点图结合?
在科研数据可视化领域,相关性分析是最基础也最重要的分析手段之一。传统的相关性热图(Correlation Heatmap)通过颜色梯度展示变量间的相关系数,能快速呈现大量变量间的关联模式。但纯热图存在两个致命缺陷:
-
无法展示数据分布特征:相同的相关系数可能对应完全不同的数据分布形态(如下图)。热图只给结果,不显示过程。
-
隐藏异常值影响:一个极端离群值可能导致高相关系数,但热图无法反映这种数据质量问题。
而散点图(Scatter Plot)恰恰能弥补这些缺陷——直接展示数据点的分布情况、离群值存在与否、线性关系的均匀性等。这就是为什么Nature等顶级期刊越来越多地采用"热图+散点图"的混合可视化方案。
提示:在生物医学领域,这种组合图尤其重要。例如基因共表达分析中,两个基因的相关系数为0.8,可能是均匀的线性关系,也可能是少数离群样本导致的假象,只有散点图能揭示真相。
2. 工具选型:Python生态 vs R生态
2.1 Python方案:Seaborn+Matplotlib组合
Python科学计算栈是当前最主流的可视化工具链,核心优势在于:
- 与pandas数据框无缝集成
- 代码简洁直观(相比ggplot2)
- 输出出版级矢量图
关键库及版本要求:
python复制import seaborn as sns # ≥0.12.0
import matplotlib.pyplot as plt # ≥3.6.0
import numpy as np # ≥1.23.0
2.2 R方案:corrplot+ggplot2组合
R语言在统计可视化领域仍有不可替代的优势:
- 更丰富的统计检验集成
- ggplot2的图形语法更灵活
- 生物信息学工具链更成熟
必要R包:
r复制library(corrplot) # ≥0.92
library(ggplot2) # ≥3.4.0
library(ggpubr) # 用于多图排版
2.3 决策建议
对于大多数场景,我推荐Python方案:
- 代码更易读易维护
- Jupyter Notebook交互更方便
- 与机器学习流程整合更好
但如果是生物信息学分析,特别是需要集成limma、DESeq2等专业包时,R方案更合适。
3. 完整Python实现教程
3.1 数据准备与预处理
使用经典的iris数据集演示,但处理方法通用:
python复制# 加载数据
iris = sns.load_dataset('iris')
numeric_cols = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
data = iris[numeric_cols]
# 计算相关系数矩阵
corr_matrix = data.corr(method='pearson') # 也可用'spearman'
# 设置样式
sns.set(style="white", font_scale=1.2)
plt.figure(figsize=(10, 8))
3.2 热图基础绘制
使用seaborn的heatmap函数绘制主热图:
python复制# 绘制热图主体
mask = np.triu(np.ones_like(corr_matrix, dtype=bool)) # 隐藏上三角
heatmap = sns.heatmap(
corr_matrix,
mask=mask,
vmin=-1, vmax=1,
cmap='coolwarm',
annot=True,
fmt=".2f",
annot_kws={"size": 12},
square=True,
linewidths=.5,
cbar_kws={"shrink": 0.8}
)
# 调整坐标轴
heatmap.set_xticklabels(
heatmap.get_xticklabels(),
rotation=45,
horizontalalignment='right'
)
heatmap.set_yticklabels(heatmap.get_yticklabels(), rotation=0)
plt.title('Iris Feature Correlations', pad=20, fontsize=16)
此时得到的是标准热图,接下来添加散点图。
3.3 散点图叠加技巧
关键思路:在热图每个单元格内嵌入微型散点图。这需要自定义Axes位置:
python复制from matplotlib.offsetbox import OffsetImage, AnnotationBbox
def create_scatter(x, y, **kwargs):
# 创建微型散点图
fig, ax = plt.subplots(figsize=(1, 1))
sns.regplot(x=x, y=y, ax=ax, scatter_kws={'s': 15}, line_kws={'lw': 1})
ax.set(xticks=[], yticks=[])
ax.set_xlabel('')
ax.set_ylabel('')
# 转换为图像对象
fig.canvas.draw()
img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
plt.close(fig)
return img
# 在热图上添加散点图
for i in range(len(numeric_cols)):
for j in range(len(numeric_cols)):
if i != j and i > j: # 只在下三角区域添加
x = data[numeric_cols[i]]
y = data[numeric_cols[j]]
scatter_img = create_scatter(x, y)
# 精确定位
ax = heatmap.axes
box = ax.get_position()
x_offset = box.x0 + (box.width / len(numeric_cols)) * (j + 0.5)
y_offset = box.y1 - (box.height / len(numeric_cols)) * (i + 0.5)
# 添加图像
imagebox = OffsetImage(scatter_img, zoom=0.3)
ab = AnnotationBbox(imagebox, (x_offset, y_offset),
xycoords='axes fraction',
frameon=False)
ax.add_artist(ab)
3.4 样式优化与输出
最后调整图形细节并保存:
python复制# 调整边距
plt.tight_layout()
# 保存矢量图
plt.savefig('corr_heatmap_scatter.pdf',
format='pdf',
dpi=300,
bbox_inches='tight')
# 显示图形
plt.show()
4. 高级定制技巧
4.1 处理大数据集策略
当变量超过15个时,传统热图会变得拥挤。解决方案:
- 聚类排序:
python复制g = sns.clustermap(corr_matrix,
method='ward',
cmap='coolwarm',
figsize=(12, 10))
- 重点标注:只显示|r|>0.7的强相关对
python复制sig_matrix = corr_matrix.where(np.abs(corr_matrix) > 0.7)
sns.heatmap(sig_matrix, annot=True, mask=sig_matrix.isnull())
4.2 交互式版本实现
对于需要探索的数据,推荐使用Plotly:
python复制import plotly.express as px
fig = px.scatter_matrix(data,
dimensions=data.columns,
color=iris['species'],
title='Interactive Correlation Matrix')
fig.update_traces(diagonal_visible=False)
fig.show()
4.3 学术期刊的特殊要求
Nature系列期刊对图表有严格规定:
- 字体:Helvetica或Arial
- 字号:主标签8-10pt
- 线宽:0.5-1pt
- 颜色模式:CMYK
适配代码:
python复制plt.rcParams.update({
'font.sans-serif': 'Arial',
'font.size': 10,
'axes.linewidth': 0.8,
'lines.linewidth': 0.8,
'pdf.fonttype': 42 # 确保文字可编辑
})
5. 常见问题排查
5.1 散点图位置偏移
症状:散点图没有准确居中在热图单元格内
解决方案:
- 检查
box.x0和box.y1计算逻辑 - 确认
zoom参数与图形尺寸匹配 - 添加调试代码打印坐标值
5.2 相关系数显示异常
可能原因:
- 数据包含NaN值 → 使用
data.dropna() - 非数值型数据 → 检查
data.dtypes - 极端离群值 → 先做
np.log1p变换
5.3 图形元素重叠
优化方案:
- 调整
figsize使画布更大 - 减小
annot_kws中的字体大小 - 使用
plt.subplots_adjust()手动调整边距
6. 真实案例:基因表达数据分析
以TCGA乳腺癌数据为例展示专业应用:
python复制# 加载RNA-seq数据
import pandas as pd
expr = pd.read_csv('tcga_brca_rpkm.csv', index_col=0)
# 选择关键基因
genes = ['ESR1', 'PGR', 'ERBB2', 'MKI67']
expr_subset = expr[genes].apply(np.log1p)
# 绘制临床级热图
plt.figure(figsize=(8, 8))
sns.heatmap(
expr_subset.corr(),
annot=True,
annot_kws={"size": 10},
cmap='RdBu_r',
center=0,
square=True
)
# 添加病理特征标记
clinical = pd.read_csv('tcga_clinical.csv')
for i, gene1 in enumerate(genes):
for j, gene2 in enumerate(genes):
if i > j:
ax = plt.gca()
box = ax.get_position()
x_offset = box.x0 + (box.width / len(genes)) * (j + 0.5)
y_offset = box.y1 - (box.height / len(genes)) * (i + 0.5)
# 根据ER状态着色
er_status = clinical['ER_Status'].iloc[0]
color = 'red' if er_status == 'Positive' else 'blue'
plt.scatter(x_offset, y_offset, s=100,
c=color, marker='s',
transform=ax.transAxes)
这个案例展示了如何将临床注释信息整合到相关性分析中,是发表级图表的典型做法。
