13

正方形の軸を維持しながら、あるサブプロットに樹状図を、別のサブプロットにヒートマップを含む単純なサブプロットを作成しようとしています。私は次のことを試みます:

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()

これにより、次のようになります。

ここに画像の説明を入力してください

ただし、問題は、軸が正方形ではなく、カラーバーが2番目のサブプロットの一部と見なされることです。代わりに、プロットの外側にぶら下げて、樹状図ボックスとヒートマップボックスの両方が正方形で、互いに整列するようにします(つまり同じサイズ)。

aspect='equal'ドキュメントが示唆するように呼び出すときに正方形の軸を取得するために使用しようとしましsubplotたが、これはプロットを台無しにし、これを与えます...

ここに画像の説明を入力してください

plt.axis('equal')の代わりに各サブプロットの後に使用しようとするとaspect='equal'、ヒートマップは奇妙に二乗されますが、境界ボックスは二乗されません(以下を参照)が、樹状図を完全に破壊し、xtickラベルの配置を台無しにします....-これを引き起こします混乱:

ここに画像の説明を入力してください

どうすればこれを修正できますか?要約すると、私は非常に単純なものをプロットしようとしています。上部のサブプロットに正方形の樹状図、下部のサブプロットに正方形のヒートマップがあり、右側にカラーバーがあります。何も派手ではありません。

最後に、より一般的な質問:matplotlibに常に軸を正方形にするために従うべき一般的なルール/原則はありますか?正方形の軸が必要ない単一のケースは考えられませんが、通常はデフォルトの動作ではありません。可能であれば、すべてのプロットを強制的に正方形にします。

4

3 に答える 3

15

アスペクト="等しい"は、データスペースの同じ長さが画面スペースの同じ長さになることを意味しますが、上部の軸では、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()

出力は次のとおりです。

ここに画像の説明を入力してください

カラーバーの位置を特定するには、ColorBarLocatorクラスを作成する必要があります。パッドと幅の引数はピクセル単位で、

  • パッド:軸とそのコロバーの間のスペースを設定します
  • width:カラーバーの幅

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)

ここに画像の説明を入力してください

于 2012-08-10T01:04:29.837 に答える
10

@HYRYの答えは非常に優れており、すべての功績に値します。しかし、四角いプロットをうまく並べることについての答えを完成させるために、matplotlibをだまして、両方のプロットにカラーバーがあると考えさせ、最初のプロットだけを非表示にすることができます。

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()

コード出力

于 2012-08-15T22:08:59.583 に答える
1

他の答えに追加するには、引数の絶対値を次のように取る必要があります.set_aspect

x0,x1 = ax1.get_xlim()
y0,y1 = ax1.get_ylim()
ax1.set_aspect(abs(x1-x0)/abs(y1-y0))
于 2013-10-19T08:31:34.887 に答える