在 Scipy/Matplotlib 中注释树状图节点
Posted
技术标签:
【中文标题】在 Scipy/Matplotlib 中注释树状图节点【英文标题】:Annotating Dendrogram nodes in Scipy/Matplotlib 【发布时间】:2015-07-30 19:30:17 【问题描述】:我正在尝试在scipy.cluster.hierarchy.dendrogram
生成的树状图中标记节点。
我正在使用augmented dendrogram suggested here,尝试将示例中的集群间距离标签 (1.01,1.57) 替换为 ('a+c','a+b+c') 等字符串。
下面是一个示例链接矩阵
Z = array([[ 2, 7, 0, 2],
[ 0, 9, 0, 2],
[ 1, 6, 0, 2],
[ 5, 10, 0, 3],
[11, 12, 0, 4],
[ 4, 8, 0, 2],
[14, 15, 0, 6],
[13, 16, 0, 9],
[ 3, 17, 1, 10]])
对于这个例子,我创建了如下临时标签:
labels = [str(Z[ind,0].astype(int))+'+'+str(Z[ind,1].astype(int)) for ind in range(len(Z))]
并将augmented_dendrogram修改为:
def augmented_dendrogram(labels,*args, **kwargs):
ddata = cl.dendrogram(*args, **kwargs)
if not kwargs.get('no_plot', False):
for ind,(i, d) in enumerate(zip(ddata['icoord'], ddata['dcoord'])):
x = 0.5 * sum(i[1:3])
y = d[1]
plt.plot(x, y, 'ro')
plt.annotate(labels[ind], (x, y), xytext=(10,15),
textcoords='offset points',
va='top', ha='center')
return ddata
但是,生成的标签未与树状图中的节点对齐:
如何将标签与正确的节点对齐?
【问题讨论】:
【参考方案1】:如果我正确理解您的问题,那么您正在寻找由 scipy 的 dendrogram
函数返回的字典中的字段 'leaves'
。根据 scipy 的documentation:
对于每个 i,H[i] == j,簇节点 j 出现在叶子从左到右遍历的位置 i 中,其中 和 。如果 j 小于 n,则第 i 个叶节点对应于原始观察。否则,它对应于非单例集群。
简而言之,这意味着您可以使用此字段将标签排序为正确的顺序,例如通过将相应的行更改为:
plt.annotate(labels[ddata['leaves'][ind]], (x, y), xytext=(10,15), textcoords='offset points', va='top', ha='center')
【讨论】:
据我判断,这个解决方案行不通,因为ddata['leaves']
只包括叶子(即只有终端,但不包括内部节点)。【参考方案2】:
这是我在处理类似问题时找到的解决方案。请注意,OP 中给出的链接矩阵缺少距离(第三列)。我人为地插入这些距离,然后使用它们来识别树状图中节点的正确索引。 scipy distance
函数生成距离已经排序的链接矩阵(至少在使用 ward
作为链接方法时)。
这是我的代码:
Z = np.array([[ 2, 7, 0, 2],
[ 0, 9, 0, 2],
[ 1, 6, 0, 2],
[ 5, 10, 0, 3],
[11, 12, 0, 4],
[ 4, 8, 0, 2],
[14, 15, 0, 6],
[13, 16, 0, 9],
[ 3, 17, 1, 10]], dtype=float)
Z[:, 2] = np.arange(1., len(Z)+1)
labels = [str(len(Z)+1+ind)+'='+str(Z[ind,0].astype(int))+'+'+str(Z[ind,1].astype(int)) for ind in range(len(Z))]
fig, ax = plt.subplots(1, 1, figsize=(10, 10))
dn = dendrogram(Z, ax=ax)
ii = np.argsort(np.array(dn['dcoord'])[:, 1])
for j, (icoord, dcoord) in enumerate(zip(dn['icoord'], dn['dcoord'])):
x = 0.5 * sum(icoord[1:3])
y = dcoord[1]
ind = np.nonzero(ii == j)[0][0]
ax.annotate(labels[ind], (x,y), va='top', ha='center')
plt.tight_layout()
plt.savefig('./tmp.png')
plt.close(fig)
结果是:
【讨论】:
以上是关于在 Scipy/Matplotlib 中注释树状图节点的主要内容,如果未能解决你的问题,请参考以下文章
Windows10+Python3下安装NumPy+SciPy+Matplotlib
python虚拟环境 + win7-64位安装scipy matplotlib
windows下python2.7版本numpy,Scipy,matplotlib安装
python库安装(numpy+scipy+matplotlib+scikit_learn)