首页 文章

如何使用热图在matplotlib中制作方形子图?

提问于
浏览
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()

这产生以下结果:

enter image description here

但问题是轴不是方形,而颜色条被认为是第二个子图的一部分 . 我希望它可以悬挂在绘图之外,并使其成为树形图框和热图框都是正方形并且彼此对齐(即相同尺寸) .

我在文档建议中调用 subplot 时尝试使用 aspect='equal' 来获取方轴,但这破坏了情节,给出了......

enter image description here

如果我尝试在每个子图之后使用 plt.axis('equal') 而不是 aspect='equal' ,它奇怪地对热图而不是其边界框(见下文),同时完全破坏树形图并且还弄乱了xtick标签的对齐.... - 引起崛起这个烂摊子:

enter image description here

怎么能修好?总而言之,我试图绘制一些非常简单的东西:顶部子图中的方形树状图和底部子图中的方形热图,右侧是颜色条 . 没有什么花哨 .

最后,更一般的问题:是否有一般规则/原则要强制matplotlib始终使轴方正?我想不出一个我不喜欢的情况't want square axes but it'通常不是默认行为 . 如果可能的话,我想强制所有的阴谋都是方形的 .

3 回答

  • 0

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

    code output

  • 10

    aspect =“equal”表示数据空间中相同的长度在屏幕空间中的长度相同,但在您的上斧中,xaxis和yaxis的数据范围不同,因此它不是正方形 . 要解决此问题,您可以将方面设置为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类,pad和width参数以像素为单位,

    • pad :设置轴之间的空间,它是colobar

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

    enter image description here

  • 14

    要添加到其他答案,您需要将参数的绝对值设为 .set_aspect

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

相关问题