2012-08-09 96 views
11

我试图在一个子图和另一个热图中制作一个简单的子图,同时保持方形轴。我尝试以下方法:如何在matplotlib中使用热图制作方形子图?

from scipy.cluster.hierarchy import linkage 
from scipy.cluster.hierarchy import dendrogram 
from scipy.spatial.distance import pdist 

fig = plt.figure(figsize=(7,7)) 
plt.subplot(2, 1, 1) 
cm = matplotlib.cm.Blues 
X = np.random.random([5,5]) 
pmat = pdist(X, "euclidean") 
linkmat = linkage(pmat) 
dendrogram(linkmat) 
plt.subplot(2, 1, 2) 
labels = ["a", "b", "c", "d", "e", "f"] 
Y = np.random.random([6,6]) 
plt.xticks(arange(0.5, 7.5, 1)) 
plt.gca().set_xticklabels(labels) 
plt.pcolor(Y) 
plt.colorbar() 

这会产生以下:

enter image description here

,但问题是,轴不垂直,而彩条被认为是第二次要情节的一部分。我希望它挂在剧情外面,并使之成为树状图框和热图框都是方形的并且彼此对齐(即相同的尺寸)。

我尝试使用aspect='equal'来获取方形轴时调用subplot如文档建议,但是这破坏了剧情,让这...

enter image description here

,如果我尝试每一个插曲,而不是aspect='equal'后使用plt.axis('equal'),它奇怪的广场热图,但不是它的边框(见下文),同时完全破坏树形图,并搞乱了xtick标签的对齐。 - 从而引发这个烂摊子:

enter image description here

这可怎么固定?总结一下,我试图绘制一些非常简单的东西:顶部子图中的方形树状图,以及底部子图中的方形热图,右边的颜色条。没有什么花哨。

终于,更一般的问题:是否有一个通用规则/原则遵循强制matplotlib到总是使轴线方形?我不能想到一个我不想要方形轴的情况,但它通常不是默认行为。如果可能的话,我想强制所有地块平方。

回答

9

@ HYRY的回答是很不错的,值得所有的功劳。不过,玩完了答案约衬平方地块高达很好,你可以欺骗matplotlib以为这两条曲线有colorbars,只有使第一个无形的:

from scipy.cluster.hierarchy import linkage 
from scipy.cluster.hierarchy import dendrogram 
from scipy.spatial.distance import pdist 
import matplotlib 
from matplotlib import pyplot as plt 
import numpy as np 
from numpy import arange 

fig = plt.figure(figsize=(5,7)) 
ax1 = plt.subplot(2, 1, 1) 
cm = matplotlib.cm.Blues 
X = np.random.random([5,5]) 
pmat = pdist(X, "euclidean") 
linkmat = linkage(pmat) 
dendrogram(linkmat) 
x0,x1 = ax1.get_xlim() 
y0,y1 = ax1.get_ylim() 
ax1.set_aspect((x1-x0)/(y1-y0)) 

plt.subplot(2, 1, 2, aspect=1) 
labels = ["a", "b", "c", "d", "e", "f"] 
Y = np.random.random([6,6]) 
plt.xticks(arange(0.5, 7.5, 1)) 
plt.gca().set_xticklabels(labels) 
plt.pcolor(Y) 
plt.colorbar() 

# add a colorbar to the first plot and immediately make it invisible 
cb = plt.colorbar(ax=ax1) 
cb.ax.set_visible(False) 

plt.show() 

code output

13

aspect =“equal”意味着数据空间中的相同长度在屏幕空间中将是相同的长度,但是在您的顶部斧头中,x轴和y轴的数据范围并不相同,因此它不会是方形。要解决这个问题,你可以将纵横设置为x轴范围的比例和Y轴范围:

from scipy.cluster.hierarchy import linkage 
from scipy.cluster.hierarchy import dendrogram 
from scipy.spatial.distance import pdist 
import matplotlib 
from matplotlib import pyplot as plt 
import numpy as np 
from numpy import arange 

fig = plt.figure(figsize=(5,7)) 
ax1 = plt.subplot(2, 1, 1) 
cm = matplotlib.cm.Blues 
X = np.random.random([5,5]) 
pmat = pdist(X, "euclidean") 
linkmat = linkage(pmat) 
dendrogram(linkmat) 
x0,x1 = ax1.get_xlim() 
y0,y1 = ax1.get_ylim() 
ax1.set_aspect((x1-x0)/(y1-y0)) 
plt.subplot(2, 1, 2, aspect=1) 
labels = ["a", "b", "c", "d", "e", "f"] 
Y = np.random.random([6,6]) 
plt.xticks(arange(0.5, 7.5, 1)) 
plt.gca().set_xticklabels(labels) 
plt.pcolor(Y) 
plt.colorbar() 

这里是输出:

enter image description here

到位置,我们需要写一个ColorBarLocator的颜色条类,垫和宽度参数是在像素单元中,

  • :设置的轴线之间的空间,它的山口OBAR
  • 宽度:在彩条

的宽度用下面的代码替换plt.colorbar()

class ColorBarLocator(object): 
    def __init__(self, pax, pad=5, width=10): 
     self.pax = pax 
     self.pad = pad 
     self.width = width 

    def __call__(self, ax, renderer): 
     x, y, w, h = self.pax.get_position().bounds 
     fig = self.pax.get_figure() 
     inv_trans = fig.transFigure.inverted() 
     pad, _ = inv_trans.transform([self.pad, 0]) 
     width, _ = inv_trans.transform([self.width, 0]) 
     return [x+w+pad, y, width, h] 

cax = fig.add_axes([0,0,0,0], axes_locator=ColorBarLocator(ax2)) 
plt.colorbar(cax = cax) 

enter image description here

+0

感谢您的答案,但你的情节仍然不像常规小情节对齐。顶部和底部的边界框未对齐。我希望它们能够垂直对齐,并且颜色背向右侧,有点像你拥有它,但没有错位。对此有何想法? – user248237dfsf 2012-08-10 01:55:33

+1

我编辑了答案,请检查它。 – HYRY 2012-08-10 03:03:20

+0

感谢您的回答 - 这正是正确的输出,但代码看起来非常复杂!有更容易的方法吗?似乎你必须成为matplotlib开发人员之一才能知道如何写这样的东西,只是为了让颜色条排列起来... – user248237dfsf 2012-08-10 03:50:45

0

要添加其他答案,你需要采取的参数的绝对值.set_aspect

x0,x1 = ax1.get_xlim() 
y0,y1 = ax1.get_ylim() 
ax1.set_aspect(abs(x1-x0)/abs(y1-y0))