如何实现seaborn的heatmap与kdeplot重叠绘制避免挤压
解决方案:Seaborn Heatmap与Kdeplot图层重叠绘制
核心问题原因
- Seaborn的heatmap默认将透视后的行、列作为分类坐标轴,坐标轴实际范围是
[0, 类别数量],而非原始数据的数值范围,和直接用原始数值绘制的kdeplot坐标体系不匹配 - heatmap默认自带的右侧色卡会占用画布空间,导致heatmap被挤压到左侧
- 错误使用
twinx创建双轴会进一步放大坐标不匹配的问题
修改后可运行代码
import numpy as np import seaborn as sns import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable # 先处理数据中逗号作为小数点的格式问题 for col in ['X', 'Y', 'Z']: dataset[col] = dataset[col].str.replace(',', '.').astype(float) f, ax = plt.subplots(figsize=(11, 9), dpi=300) plt.tick_params(bottom='on') # 生成透视表并对行、列排序确保坐标映射正确 X1 = dataset.pivot(index="X", columns="Y", values="Z") x_labels = X1.columns.sort_values() y_labels = X1.index.sort_values() X1 = X1.reindex(index=y_labels, columns=x_labels) # 绘制heatmap,关闭自带色卡避免挤压画布 sns.heatmap(X1, cmap="Spectral", ax=ax, cbar=False) ax.invert_yaxis() # 原始数值坐标转heatmap网格坐标:每个格子的中心在索引+0.5位置 def val_to_grid_pos(val, sorted_val_list): return np.argwhere(sorted_val_list == val)[0][0] + 0.5 dataset['grid_x'] = dataset['Y'].apply(lambda x: val_to_grid_pos(x, x_labels)) dataset['grid_y'] = dataset['X'].apply(lambda x: val_to_grid_pos(x, y_labels)) # 同一坐标轴上绘制kde,zorder确保在上层显示 sns.kdeplot(x=dataset['grid_x'], y=dataset['grid_y'], ax=ax, zorder=2, color='white', linewidths=1.5) # 手动添加色卡,不占用heatmap画布空间 divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.1) plt.colorbar(ax.collections[0], cax=cax) ax.axis('tight') plt.show()
关键修改说明
- 新增坐标映射逻辑:把原始数据的X/Y数值转换为heatmap网格的中心坐标,确保两个图层坐标完全对齐
- 关闭heatmap默认色卡,手动新增色卡到右侧独立轴,避免挤压heatmap显示区域
- 取消
twinx双轴设置,两个图层共用同一坐标轴,通过zorder参数控制图层上下顺序 - 提前对透视表的行、列做排序,避免索引顺序混乱导致坐标映射错位
内容的提问来源于stack exchange,提问作者mjackie
相关产品推荐
相关产品推荐

