Plot scipy中树状图坐标与ClusterNodes的关系

Plot scipy中树状图坐标与ClusterNodes的关系,plot,scipy,hierarchical-clustering,linkage,dendrogram,Plot,Scipy,Hierarchical Clustering,Linkage,Dendrogram,我正在寻找一种方法,根据它的返回值来获得图中簇点的坐标 使用scipy从以下数据构建dendogram: X = data Y = pdist(X) Z = linkage(Y) dend = dendrogram(Z) rootnode, nodesList = to_tree(Z, rd=True) 我想做的是构建一个函数get_coords(somClusterNode),它将返回元组(x,y),指定节点在绘图中的位置 多亏了,我设法找出了如何从树状图返回值中获取位置,例如: i, d

我正在寻找一种方法,根据它的返回值来获得图中簇点的坐标

使用scipy从以下数据构建dendogram:

X = data
Y = pdist(X)
Z = linkage(Y)
dend = dendrogram(Z)
rootnode, nodesList = to_tree(Z, rd=True)
我想做的是构建一个函数
get_coords(somClusterNode)
,它将返回元组
(x,y)
,指定节点在绘图中的位置

多亏了,我设法找出了如何从树状图返回值中获取位置,例如:

i, d = list(zip(dend['icoord'], dend['dcoord']))[-1]
x = 0.5 * sum(i[1:3])
y = d[1]
plt.plot(x, y, 'ro')
但是我可以找出节点列表顺序和
icoord/dcoord
顺序之间的关系,以便将一个映射到另一个

你知道我在哪里找吗


谢谢你的帮助

每个树状图只映射到一棵ClusterNodes树,但任何ClusterNodes树都可以映射到无限多个树状图。因此,从节点ID到(x,y)位置的映射可能只是树状图数据结构中的另一个字段,而不是ClusterNode的函数。因此,我没有定义函数
get_coords
,而是在
dend
中添加一个字典,将节点ID映射到(x,y)坐标。您可以使用

x,y = dend['node_id_to_coord'][node_id] # node_id is an integer as returned by ClusterNode.id
代码:

将numpy导入为np
将matplotlib.pyplot作为plt导入
从scipy.cluster.hierarchy导入链接、树状图到_树
从scipy.spatial.distance导入pdist
#创建一些随机数据
X=np.random.rand(10,3)
#获取树状图
Z=联动装置(pdist(X),方法=“病房”)
dend=树状图(Z)
# ----------------------------------------
#获取左坐标,y==0
def展平(l):
return[子列表中项目的l子列表中的项目]
X=展平(密度['ICORD'])
Y=展平(dend['dcord'])
如果y==0,则在zip(x,y)中保留x,y的坐标=[(x,y)]
#在dendogram数据结构中,
#休假ID根据其x坐标以升序列出
order=np.argsort([x代表x,y代表左坐标])

id_to_coord=dict(zip(dend['leaves'],[leave_coords[idx]for idx按顺序))#还有另一种方法:

dendogram的ID似乎是由树的从右到左的反向遍历生成的。这允许我们按照如下方式构造从
node.id
icoord
dcoord
索引的转换:

def rl_遍历(节点):
#跳叶
如果不是node.is_leaf():
屈服节点id
rl_遍历的收益率(node.right)
rl_遍历的收益率(node.left)
id\u map=dict(zip(rl\u遍历(根),反转(范围(root.get\u count()-1)))
#id\u映射[node\u id]=dendogram\u id

然后可以通过
dendo['icoord'][id\u map[node\u id]]

使用什么版本的scipy来获取节点的坐标?当我尝试运行您的代码时,我得到一个错误:
ValueError:当原始观察值被省略时,有效的方法是“single”、“complete”、“weighted”和“average”。
您确定第3行不应该是
Z=linkage(X,method=“ward”)
?我使用SciPy v.0.19.0与python v.3.5.2兼容:“输入y可以是一维压缩距离矩阵,也可以是二维观测向量数组。”是的,但如果您指定method=“ward”“,我的版本仅在提供原始观察结果时有效。升级我的scipy安装以查看问题是否仍然存在…确定。那么任何方法都可以。我不认为我的问题取决于我选择的链接方法。我据此编辑了这篇文章。非常感谢!几天来我一直在努力解决这个问题!泰,泰,泰!我尝试编辑以将
.iteritems()
更改为
.items()
,使其与python3兼容。但是,stack不允许编辑少于6个字符。我很乐意。我将在一秒钟内进行编辑。此外,我刚刚发现我可以使用链接矩阵更有效地遍历树。编辑传入。好的,这个版本现在简单多了。我不知怎的没有意识到链接矩阵中的每个链接都对应于树状图['icoord']
和树状图['dcoords']。是的,你是对的,节点ID有时会出现在所有错误的位置。我也要回去。
import numpy as np
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage, dendrogram, to_tree
from scipy.spatial.distance import pdist

# create some random data
X = np.random.rand(10, 3)

# get dendrogram
Z = linkage(pdist(X), method="ward")
dend = dendrogram(Z)

# ----------------------------------------
# get leave coordinates, which are at y == 0

def flatten(l):
    return [item for sublist in l for item in sublist]
X = flatten(dend['icoord'])
Y = flatten(dend['dcoord'])
leave_coords = [(x,y) for x,y in zip(X,Y) if y==0]

# in the dendogram data structure,
# leave ids are listed in ascending order according to their x-coordinate
order = np.argsort([x for x,y in leave_coords])
id_to_coord = dict(zip(dend['leaves'], [leave_coords[idx] for idx in order])) # <- main data structure

# ----------------------------------------
# get coordinates of other nodes

# this should work but doesn't:

# # traverse tree from leaves upwards and populate mapping ID -> (x,y);
# # use linkage matrix to traverse the tree optimally
# # (each row in the linkage matrix corresponds to a row in dend['icoord'] and dend['dcoord'])
# root_node, node_list = to_tree(Z, rd=True)
# for ii, (X, Y) in enumerate(zip(dend['icoord'], dend['dcoord'])):
#     x = (X[1] + X[2]) / 2
#     y = Y[1] # or Y[2]
#     node_id = ii + len(dend['leaves'])
#     id_to_coord[node_id] = (x, y)

# so we need to do it the hard way:

# map endpoint of each link to coordinates of parent node
children_to_parent_coords = dict()
for i, d in zip(dend['icoord'], dend['dcoord']):
    x = (i[1] + i[2]) / 2
    y = d[1] # or d[2]
    parent_coord = (x, y)
    left_coord = (i[0], d[0])
    right_coord = (i[-1], d[-1])
    children_to_parent_coords[(left_coord, right_coord)] = parent_coord

# traverse tree from leaves upwards and populate mapping ID -> (x,y)
root_node, node_list = to_tree(Z, rd=True)
ids_left = range(len(dend['leaves']), len(node_list))

while len(ids_left) > 0:

    for ii, node_id in enumerate(ids_left):
        node = node_list[node_id]
        if (node.left.id in id_to_coord) and (node.right.id in id_to_coord):
            left_coord = id_to_coord[node.left.id]
            right_coord = id_to_coord[node.right.id]
            id_to_coord[node_id] = children_to_parent_coords[(left_coord, right_coord)]

    ids_left = [node_id for node_id in range(len(node_list)) if not node_id in id_to_coord]

# plot result on top of dendrogram
ax = plt.gca()
for node_id, (x, y) in id_to_coord.iteritems():
    if not node_list[node_id].is_leaf():
        ax.plot(x, y, 'ro')
        ax.annotate(str(node_id), (x, y), xytext=(0, -8),
                    textcoords='offset points',
                    va='top', ha='center')

dend['node_id_to_coord'] = id_to_coord