如何让热力图次坐标轴Y轴刻度居中并显示边缘边框
问题描述
我有如下数据框:
l1 = ['A','A','A','A','A','A','A','A','A','A','B','B','B','B','B','B','B','B','B','B'] l2 = ['Name-1','Name-2','Name-3','Name-4','Name-5','Name-6','Name-7','Name-8','Name-9','Name-10','Name-11','Name-12','Name-13','Name-14','Name-15','Name-16','Name-17','Name-18','Name-19','Name-20'] v1 = [1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1] v2 = [0,0,0,1,1,1,0,0,1,1,0,0,0,1,1,1,0,0,1,1] v3 = [1,0,1,1,1,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0] v4 = [0,0,0,0,1,1,1,0,0,1,0,0,0,0,1,1,1,0,0,1] v5 = [1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1] v6 = [1,1,0,0,1,1,0,1,0,1,1,1,0,0,1,1,0,1,0,1] v7 = [0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,0,1] v8 = [0,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1] v9 = [1,1,0,1,1,1,0,0,0,1,1,1,0,1,1,1,0,0,0,1] v10 =[1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,0,1] d = {'variable': l1, 'value': l2,'ID1': v1,'ID2': v2,'ID3': v3,'ID4': v4,'ID5': v5,'ID6': v6,'ID7': v7,'ID8': v8,'ID9': v9,'ID10': v10} df = pd.DataFrame(d) df = df.set_index(['variable','value']) sum_list = df.sum(axis=0)
我绘制了左右两侧带Y轴刻度的热力图,代码如下:
sns.set(rc={'figure.figsize': (10,10),'xtick.labelsize': 12,'ytick.labelsize': 12, 'axes.labelcolor': 'black', 'ytick.left': True, 'ytick.right': True,'axes.grid': False,}) heat_map = sns.heatmap(df.reset_index(level='variable', col_level=0,drop=True),square=False,yticklabels=True,xticklabels=False,cmap=['#FFFFFF','#ff0303'],vmin=0,vmax=1,cbar=False,linewidths=1,linecolor='black', annot_kws={"fontsize":3}) heat_map.set_yticklabels(labels=heat_map.get_yticklabels(),weight='bold',color='black') heat_map.set(xlabel=None,ylabel=None) sec_axis=heat_map.twinx() sec_axis.set_yticks(heat_map.get_yticks()) sec_axis.set_yticklabels(df.sum(axis=1).values[::-1], weight='bold', color='black', fontsize=12) ## Add tick labels which will be the sum sec_axis.grid(False)
现在遇到两个问题:
- 添加右侧次坐标轴后,热力图四边边缘消失
- 右侧Y轴刻度未居中对齐
需要实现两个需求:
- 显示热力图并保留四边边缘
- 将次坐标轴Y轴刻度居中对齐
解决方案
1. 恢复热力图四边边缘
twinx()会默认隐藏原轴的右侧边框,同时可能导致整体边框被遮挡。只需手动开启原轴的四边边框,并调整次轴的边框显示逻辑,再优化布局避免裁剪:
在创建次坐标轴后添加以下代码:
# 恢复原热力图轴的四边边框 heat_map.spines[['top', 'bottom', 'left', 'right']].set_visible(True) # 隐藏次轴的左、上、下边框,仅保留右侧边框 sec_axis.spines[['top', 'bottom', 'left']].set_visible(False) sec_axis.spines['right'].set_visible(True) # 调整布局,确保边框不被画布裁剪 plt.tight_layout()
2. 让右侧Y轴刻度居中对齐
原代码直接复用原轴的刻度位置,而热力图的行中心和刻度位置不匹配。需要计算每行的中心坐标来设置次轴刻度:
替换原有的sec_axis.set_yticks(...)和sec_axis.set_yticklabels(...)代码,改为:
# 获取热力图的Y轴范围 y_min, y_max = heat_map.get_ylim() # 计算每行的中心位置:总共有len(df)行,每行高度为(y_max - y_min)/len(df) yticks = [y_min + (i + 0.5)*(y_max - y_min)/len(df) for i in range(len(df))] # 设置次轴刻度为行中心位置 sec_axis.set_yticks(yticks) # 设置刻度标签,无需反转顺序 sec_axis.set_yticklabels(df.sum(axis=1).values, weight='bold', color='black', fontsize=12)
完整代码
import seaborn as sns import pandas as pd import matplotlib.pyplot as plt # 构造数据框 l1 = ['A','A','A','A','A','A','A','A','A','A','B','B','B','B','B','B','B','B','B','B'] l2 = ['Name-1','Name-2','Name-3','Name-4','Name-5','Name-6','Name-7','Name-8','Name-9','Name-10','Name-11','Name-12','Name-13','Name-14','Name-15','Name-16','Name-17','Name-18','Name-19','Name-20'] v1 = [1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1] v2 = [0,0,0,1,1,1,0,0,1,1,0,0,0,1,1,1,0,0,1,1] v3 = [1,0,1,1,1,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0] v4 = [0,0,0,0,1,1,1,0,0,1,0,0,0,0,1,1,1,0,0,1] v5 = [1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1] v6 = [1,1,0,0,1,1,0,1,0,1,1,1,0,0,1,1,0,1,0,1] v7 = [0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,0,1] v8 = [0,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1] v9 = [1,1,0,1,1,1,0,0,0,1,1,1,0,1,1,1,0,0,0,1] v10 =[1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,0,1] d = {'variable': l1, 'value': l2,'ID1': v1,'ID2': v2,'ID3': v3,'ID4': v4,'ID5': v5,'ID6': v6,'ID7': v7,'ID8': v8,'ID9': v9,'ID10': v10} df = pd.DataFrame(d) df = df.set_index(['variable','value']) sum_list = df.sum(axis=0) # 绘制热力图 sns.set(rc={'figure.figsize': (10,10),'xtick.labelsize': 12,'ytick.labelsize': 12, 'axes.labelcolor': 'black', 'ytick.left': True, 'ytick.right': True,'axes.grid': False,}) heat_map = sns.heatmap(df.reset_index(level='variable', col_level=0,drop=True),square=False,yticklabels=True,xticklabels=False,cmap=['#FFFFFF','#ff0303'],vmin=0,vmax=1,cbar=False,linewidths=1,linecolor='black', annot_kws={"fontsize":3}) heat_map.set_yticklabels(labels=heat_map.get_yticklabels(),weight='bold',color='black') heat_map.set(xlabel=None,ylabel=None) # 创建次坐标轴 sec_axis=heat_map.twinx() # 处理右侧刻度居中问题 y_min, y_max = heat_map.get_ylim() yticks = [y_min + (i + 0.5)*(y_max - y_min)/len(df) for i in range(len(df))] sec_axis.set_yticks(yticks) sec_axis.set_yticklabels(df.sum(axis=1).values, weight='bold', color='black', fontsize=12) # 恢复热力图四边边缘 heat_map.spines[['top', 'bottom', 'left', 'right']].set_visible(True) sec_axis.spines[['top', 'bottom', 'left']].set_visible(False) sec_axis.spines['right'].set_visible(True) sec_axis.grid(False) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Yash
相关产品推荐
相关产品推荐

