如何获取Scipy树状图中对应样本的叶节点坐标?
Scipy层次聚类树状图:仅提取样本标签对应的节点坐标
问题背景
使用Scipy绘制层次聚类树状图的代码如下:
from scipy.cluster.hierarchy import linkage, dendrogram, complete, to_tree from scipy.spatial.distance import squareform import numpy as np import pandas as pd diff_matrix = [[0, 0, 1, 0, 1], [0, 0, 1, 0, 1], [1, 1, 0, 1, 2], [0, 0, 1, 0, 1], [1, 1, 2, 1, 0]] linkage_matrix = linkage(squareform(diff_matrix),'complete') dendrogram_info = dendrogram(linkage_matrix, labels= list(df.index))
执行后生成的dendrogram_info字典为:
{ 'icoord': [[35.0, 35.0, 45.0, 45.0], [25.0, 25.0, 40.0, 40.0], [15.0, 15.0, 32.5, 32.5], [5.0, 5.0, 23.75, 23.75]], 'dcoord': [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 0.0], [0.0, 2.0, 2.0, 1.0]], 'ivl': ['Sample05', 'Sample03', 'Sample04', 'Sample01', 'Sample02'], 'leaves': [4, 2, 3, 0, 1], 'color_list': ['C1', 'C1', 'C1', 'C0'], 'leaves_color_list': ['C0', 'C1', 'C1', 'C1', 'C1'] }
尝试的提取代码及问题
尝试用以下代码提取样本对应的节点坐标:
leaf_coords = [] for x, y in zip(dendrogram_info['icoord'], dendrogram_info['dcoord']): if y[0]==0: leaf_coords.append([x[0], y[0]]) if y[3]==0: leaf_coords.append([x[3], y[3]])
得到的结果包含[40.0, 0]、[32.5, 0]这类非样本节点坐标:
[[35.0, 0.0], [45.0, 0.0], [25.0, 0.0], [40.0, 0.0], [15.0, 0.0], [32.5, 0.0], [5.0, 0.0]]
需要仅提取下图中箭头所示的样本/标签对应的节点坐标:
解决方案
方法1:过滤去重并排序
通过记录已出现的x坐标,避免重复添加中间节点的坐标,最终排序得到样本节点坐标:
leaf_coords = [] seen_x = set() for x_vals, y_vals in zip(dendrogram_info['icoord'], dendrogram_info['dcoord']): # 遍历线段的所有端点,收集y=0且未记录过的x坐标 for x, y in zip(x_vals, y_vals): if y == 0.0 and x not in seen_x: leaf_coords.append([x, y]) seen_x.add(x) # 按x坐标排序,对应标签的显示顺序 leaf_coords.sort()
执行后得到的结果为:
[[5.0, 0.0], [15.0, 0.0], [25.0, 0.0], [35.0, 0.0], [45.0, 0.0]]
方法2:利用标签顺序直接生成
Scipy的dendrogram默认叶子节点的x坐标按固定间隔排列(从5开始,每次递增10),可直接根据标签列表长度生成:
# 按ivl中的标签顺序生成对应坐标 leaf_coords = [[5 + 10*i, 0.0] for i in range(len(dendrogram_info['ivl']))]
如需将坐标与样本标签关联,可生成字典:
coords_dict = {label: [5 + 10*i, 0.0] for i, label in enumerate(dendrogram_info['ivl'])}
说明
之前的代码会捕获中间合并节点的端点,是因为这些节点的线段也存在y=0的端点,但它们不属于样本叶子节点。通过记录已出现的x坐标,可有效过滤掉这类非样本节点;而利用固定间隔生成的方式更简洁,适合默认布局的场景。
内容的提问来源于stack exchange,提问作者崔箐坡
相关产品推荐
相关产品推荐

