【问题标题】:Color bars in multi subplots doesn't follow the same scale多个子图中的颜色条不遵循相同的比例
【发布时间】:2021-09-12 21:54:13
【问题描述】:

我正在尝试比较四个二维直方图。我需要每个直方图中的颜色条。但是,很明显,所有直方图中的色标都不相同。有没有办法让这个比例一样?

我使用的代码在这里:

plt.set_cmap('hot')


fig = plt.figure()

fig.set_size_inches(10, 10)

# Adds subplot on position 1
ax = fig.add_subplot(221,aspect='equal')
# Adds subplot on position 2
ax2 = fig.add_subplot(222, aspect='equal')

ax3 = fig.add_subplot(223, aspect='equal')

ax4 = fig.add_subplot(224, aspect='equal')


h = ax.hist2d(data,datay,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))


ax.set_title('step size = 2.0 ', size= 16, fontname='Comic Sans MS')


h2 = ax2.hist2d(data2,datay2,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))
ax2.set_title('step size = 5.0 ', size= 16, fontname='Comic Sans MS')



h3 = ax3.hist2d(data3,datay3,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))
ax3.set_title('step size = 6.0 ', size= 16, fontname='Comic Sans MS')
    

h4 = ax4.hist2d(data4,datay4,bins=(100,100), rasterized=True,range=np.array([(-7.9, 7.9), (-7.9, 7.9)]))
ax4.set_title('step size = 8.0 ', size= 16, fontname='Comic Sans MS')


"""
DEFINING COLOR BARS
"""
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(h[3], cax=cax)


divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(h2[3], cax=cax)

divider = make_axes_locatable(ax3)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(h3[3], cax=cax)

divider = make_axes_locatable(ax4)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(h4[3], cax=cax)

ax2.set_yticks([])
ax4.set_yticks([])

plt.subplots_adjust(wspace=0.3)


plt.savefig('24pog.pdf') 
plt.savefig('24pog.png') 
plt.show()  

【问题讨论】:

    标签: python matplotlib histogram


    【解决方案1】:

    您必须标准化颜色范围(查看文档中的cmaxcmin。或者,您可以使用ScalarMappable,即

    
    import matplotlib.pyplot as plt, numpy as np
    
    norm = plt.cm.colors.Normalize(vmin = 0, vmax = 2)
    cmap = 'hot'
    sc = plt.cm.ScalarMappable(norm = norm, cmap =  cmap)
    
    fig, ax = plt.subplots(2, 2)
    for idx, axi in enumerate(ax.flat):
        axi.hist2d(*np.random.rand(2, 10), cmap = cmap)
        fig.colorbar(sc, ax = axi)
    fig.show()
    

    【讨论】:

    • 谢谢!但是我如何获得 vmax?有没有办法从直方图中获得这个?还是我需要手动放置?
    • @Daumann 是的,假设您想要自动化 vminvmax,您只需使用 min()max() 提取它们(否则手动值仍然有效)
    • @Daumann 如果您希望颜色条反映相同的范围,您必须告诉 matplotlib 该范围来自您的数据。或者,您可以使用 Normalize 类标准化所有内容,但这会失去“绝对”比例。
    • 作为旁注;如果所有颜色条都在同一范围内,则也可以在 fig.colorbar(sc, ax = ax) 中放入 1 个颜色条,因为 ax 是上面的二维矩阵。
    【解决方案2】:

    plt.hist2d 的问题在于,要将相同的“颜色缩放”应用于四个数据实例,您必须提前知道四个直方图的分箱值,但在绘制直方图。

    一种可能的解决方案是只绘制两次直方图,第二次您将知道分箱数据的全部范围,但这似乎很浪费。

    另一种方法,绘制四个直方图,读取分箱数据范围,然后更改 hist2d 返回的颜色网格的属性,但这似乎很复杂。

    在我看来,最简单、最经济的方法是自己模仿hist2d,这里你可以看到它的源代码(nb:self是一个Axes实例)

    def hist2d(self, x, y, bins=10, range=None, density=False, weights=None,
               cmin=None, cmax=None, **kwargs):
        ...
        h, xedges, yedges = np.histogram2d(x, y, bins=bins, range=range,
                                           density=density, weights=weights)
        ...
        pc = self.pcolormesh(xedges, yedges, h.T, **kwargs)
        self.set_xlim(xedges[0], xedges[-1])
        self.set_ylim(yedges[0], yedges[-1])
    
        return h, xedges, yedges, pc
    

    好吧,没有什么特别花哨的……所以计划是在每个 x, y 实例上调用 histogram2d,将结果保存在列表中,检查分箱数据以找到正确的规范化,最后使用我们保存的数据histogram2d,调用 pcolormesh — 请注意,如果需要,您还可以对所有绘图使用相同的轴限制。

    这是我用过的代码

    In [49]: import matplotlib.pyplot as plt
        ...: from matplotlib.cm import ScalarMappable
        ...: from numpy.random import rand
        ...: from numpy import histogram2d
        ...: 
        ...: # generate data - I have not your data…
        ...: data = ((rand(10000+500*i), rand(10000+500*i)) for i in range(4))
        ...: 
        ...: # generate histograms (for you it's for x, y in ((x1,x2),(x2,y2),...)
        ...: hist = [histogram2d(x,y) for x, y in data]
        ...: # find min and max for each histogram
        ...: min_, max_ = zip(*((h.min(), h.max()) for h, xedges, yedges in hist))
        ...: 
        ...: norm = plt.Normalize(min(min_), max(max_))
        ...: sm = ScalarMappable(norm, 'hot')
        ...: 
        ...: fig, sp = plt.subplots(2, 2, constrained_layout=1)
        ...: sp = sp.flatten()
        ...: for ax, (h, xedges, yedges) in zip(sp, hist):
        ...:     ax.pcolormesh(xedges, yedges, h.T, norm=norm, cmap='hot')
        ...: plt.colorbar(sm, ax=sp, aspect=30)
    

    【讨论】:

      猜你喜欢
      • 2017-11-10
      • 2016-01-01
      • 2018-11-28
      • 2016-06-14
      • 2018-03-18
      • 2017-04-20
      • 1970-01-01
      • 2015-10-26
      相关资源
      最近更新 更多