2012-08-09 143 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))