在同一个图上一起绘制两个距离矩阵?
Posted
技术标签:
【中文标题】在同一个图上一起绘制两个距离矩阵?【英文标题】:Plotting two distance matrices together on same plot? 【发布时间】:2017-11-01 15:14:58 【问题描述】:我正在尝试从两个不同的距离矩阵创建树状图并进行比较。我使用代码here 作为起点,但问题是由于我使用了两个不同的矩阵但相同的聚类方法,我需要将两个不同的矩阵绘制在一起进行比较分析。我想知道是否可以将每个正方形/节点的对角线分成两半以显示两个不同的距离矩阵。
这张图片代表了我的目标结果:
这是我的代码:
from sklearn import preprocessing
from sklearn.neighbors import DistanceMetric
import pandas as pd
import numpy as np
from ete3 import Tree
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.metrics.pairwise import cosine_distances
import scipy
import pylab
import scipy.cluster.hierarchy as sch
import scipy.spatial.distance as sd
import random
#g[n] is a one dimensional array containing datapoints
g1 = random.sample(range(30), 5)
g2 = random.sample(range(30), 5)
g3 = random.sample(range(30), 5)
g4 = random.sample(range(30), 5)
g5 = random.sample(range(30), 5)
g1 = np.array(g1)
g2 = np.array(g2)
g3 = np.array(g3)
g4 = np.array(g4)
g5 = np.array(g5)
X = (g1,g2,g3,g4,g5)
#Comparing between euclidean and cosine###########################################
distanceC = cosine_distances(X)
dist = DistanceMetric.get_metric('euclidean')
distanceE = dist.pairwise(X)
##################################################################################
#Plots############################################################################
# Compute and plot first dendrogram.
fig = pylab.figure(figsize=(8,8))
ax1 = fig.add_axes([0.09,0.1,0.2,0.6])
Y = sch.average(sd.squareform(distanceC))
Z1 = sch.dendrogram(Y, orientation='right')
ax1.set_xticks([])
ax1.set_yticks([])
# Compute and plot second dendrogram.
ax2 = fig.add_axes([0.3,0.71,0.6,0.2])
Y = sch.average(sd.squareform(distanceE))
Z2 = sch.dendrogram(Y)
ax2.set_xticks([])
ax2.set_yticks([])
# Plot distance matrix.
axmatrix = fig.add_axes([0.3,0.1,0.6,0.6])
idx1 = Z1['leaves']
idx2 = Z2['leaves']
distance = distance[idx1,:]
distance = distance[:,idx2]
im = axmatrix.matshow(distance, aspect='auto', origin='lower', cmap=pylab.cm.YlGnBu)
axmatrix.set_xticks([])
axmatrix.set_yticks([])
# Plot colorbar.
axcolor = fig.add_axes([0.91,0.1,0.02,0.6])
pylab.colorbar(im, cax=axcolor)
fig.show()
fig.savefig('dendrogram.png')
##################################################################################
【问题讨论】:
我已经删除了第二个问题。虽然我知道这里的代码示例有点“损坏”,但问题是生成列表 g1、g2...g5 的代码有很多文件 IO 和处理操作,这并不真正相关,但我仍然绑定用随机列表生成器替换它,它应该可以完成工作。 【参考方案1】:没有内置方法可以绘制由三角形组成的图像,将像素切成两半。
因此需要构建一些自定义热图。这可以使用三角形的PolyCollection
来完成。在下面的解决方案中,一个函数围绕原点创建三角形的点,如果需要旋转它们,并应用偏移量。遍历数组允许为每个点创建一个三角形。最后,所有这些三角形都被收集到一个 PolyCollection 中。
然后您可以决定对其中一个数组使用普通的imshow
或matshow
绘图,并在其顶部使用自定义三角形矩阵。
import matplotlib.pyplot as plt
import matplotlib.collections as collections
import numpy as np
def triatpos(pos=(0,0), rot=0):
r = np.array([[-1,-1],[1,-1],[1,1],[-1,-1]])*.5
rm = [[np.cos(np.deg2rad(rot)), -np.sin(np.deg2rad(rot))],
[np.sin(np.deg2rad(rot)),np.cos(np.deg2rad(rot)) ] ]
r = np.dot(rm, r.T).T
r[:,0] += pos[0]
r[:,1] += pos[1]
return r
def triamatrix(a, ax, rot=0, cmap=plt.cm.viridis, **kwargs):
segs = []
for i in range(a.shape[0]):
for j in range(a.shape[1]):
segs.append(triatpos((j,i), rot=rot) )
col = collections.PolyCollection(segs, cmap=cmap, **kwargs)
col.set_array(a.flatten())
ax.add_collection(col)
return col
A,B = np.meshgrid(range(5), range(4))
B*=4
fig, ax=plt.subplots()
im1 = ax.imshow(A)
im2 = triamatrix(B, ax, rot=90, cmap="Reds")
fig.colorbar(im1, ax=ax, )
fig.colorbar(im2, ax=ax, )
plt.show()
当然也可以使用其中两个三角形矩阵
im1 = triamatrix(A, ax, rot=0, cmap="Blues")
im2 = triamatrix(B, ax, rot=180, cmap="Reds")
ax.set_xlim(-.5,A.shape[1]-.5)
ax.set_ylim(-.5,A.shape[0]-.5)
这也需要手动设置轴限制。
【讨论】:
谢谢!这正是我正在寻找的。我现在在将该方法与树状图集成时遇到了一点麻烦,即叶子没有与矩阵中的相应距离对齐。 抱歉,我没有可用的 scikit-lern。您能否为所有 3 个图设置可见的刻度并提供一张图片,从中可以看出发生了什么问题? 很抱歉回复晚了,我试着多玩一点代码。我想问题在于涉及两种不同的放置方法(用于树状图的 add_axes 和用于距离矩阵的 add_subplot)。我得到的结果很奇怪:imgur.com/a/AwJfi 我看到了问题。但是对其中一个矩阵使用 matshow 或 imshow 图的第一个解决方案应该可以工作,对吧?我更新了答案以包括第二个解决方案的限制设置。 是的!第一个解决方案有效,现在第二个解决方案也有效。我可能可以根据我的规范对代码进行微调,但除此之外它非常完美,谢谢!以上是关于在同一个图上一起绘制两个距离矩阵?的主要内容,如果未能解决你的问题,请参考以下文章