如何标准化热图

How to normalise heat maps

我正在尝试标准化从 2dhistogram 派生的热图。无论数据点的数量如何,我都希望分布是相对的。

附件代码包含两组数据。与另一个相比,一个具有更多的 x,y 坐标。虽然数字是随机的,但是否可以对这些图进行归一化,以便密度代表分布而不是频率。使用下面的示例,x1-y1 由于样本数量的原因,看起来会有更多的变化。尽管潜在的变化类似于 x2-y2

import matplotlib.pyplot as plt
import random
import numpy as np

fig, ((ax1, ax2)) = plt.subplots(1,2)

x1 = [random.randrange(1,101,1) for _ in range (10000)]
y1 = [random.randrange(1,101,1) for _ in range (10000)]

x2 = [random.randrange(1,100,1) for _ in range (1000)]
y2 = [random.randrange(1,100,1) for _ in range (1000)]

zi, xi, yi = np.histogram2d(x1, y1, bins=40, normed = False)
im = ax1.imshow(zi, interpolation = 'gaussian', origin = 'lower', cmap = 'jet')

zi, xi, yi = np.histogram2d(x2, y2, bins=40, normed = False)
im = ax2.imshow(zi, interpolation = 'gaussian', origin = 'lower', cmap = 'jet')

我可以通过确定每个 bin 中的最大强度或计数来标准化行,并将其用作参考点并绘制范围为 0 - 1 的其他数据吗?

注意:这与上面的代码无关,但我将附上示例以直观地展示我希望实现的目标。我的代码生成以下图像:

虽然上述代码无法重现,但这些图像是这样生成的:

C_f50,x,y,p = plt.hist2d(Con_F50X, Con_F50Y, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax9.imshow(C_f50.T, interpolation = 'gaussian', cmap = 'jet')

C_fmid,x,y,p = plt.hist2d(Con_FMIDX, Con_FMIDY, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax10.imshow(C_fmid.T, interpolation = 'gaussian', cmap = 'jet')

C_dmid,x,y,p = plt.hist2d(Con_DMIDX, Con_DMIDY, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax11.imshow(C_dmid.T, interpolation = 'gaussian', cmap = 'jet')

C_d50,x,y,p = plt.hist2d(Con_D50X, Con_D50Y, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax12.imshow(C_d50.T, interpolation = 'gaussian', cmap = 'jet')

下一组图像使用@filippo 在答案部分详述的 vminvmax

如您所见,密度发生了显着变化。主要区别在于 vmin/vmax 函数。它从第一个图中获取这些度量 (C_f50)。

我想了解的是,是否有另一种方法可以从一个单独的点标准化所有地块的密度。上面使用了第一个图中的 vmin/vmax 。但很明显,如果从该图中对其进行归一化,密度将不会改变。

C_f50,x,y,p = plt.hist2d(Con_F50X, Con_F50Y, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax9.imshow(C_f50.T, interpolation = 'gaussian', cmap = 'jet')

C_fmid,x,y,p = plt.hist2d(Con_FMIDX, Con_FMIDY, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax10.imshow(C_fmid.T, interpolation = 'gaussian', cmap = 'jet',vmin=C_f50.min(), vmax=C_f50.max())

C_dmid,x,y,p = plt.hist2d(Con_DMIDX, Con_DMIDY, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax11.imshow(C_dmid.T, interpolation = 'gaussian', cmap = 'jet', vmin=C_f50.min(), vmax=C_f50.max())

C_d50,x,y,p = plt.hist2d(Con_D50X, Con_D50Y, bins = 40, range = np.array([(-85, 85), (4, 140)]))
ax12.imshow(C_d50.T, interpolation = 'gaussian', cmap = 'jet',vmin=C_f50.min(), vmax=C_f50.max())

这些有意义吗?

不确定我是否完全理解了这个问题。所附情节与您发布的代码没有明显关系。

您可以预先计算您的直方图,找到最小值和最大值并将它们用于 vminvmax imshow 参数的标准化。

例如

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

# gen 9 2d gaussian samples and histogram
data = np.random.normal(size=(9, 10000, 2))
zidata = np.asarray([np.histogram2d(row[:,0], row[:,1], bins=40)[0] for row in data])

# plot 
gridspec = mpl.gridspec.GridSpec(3,3)
for zi, gs in zip(zidata, gridspec):
    ax = plt.subplot(gs)
    ax.imshow(zi, interpolation='gaussian', vmin=zidata.min(), vmax=zidata.max())
    ax.axis("tight")
plt.show()

默认情况下,imshow 使用 Normalize 规范化您的数据,这基本上应用了一个简单的线性变换,例如:

vmin = img.min()
vmax = img.max()
return (img - vmin)/(vmax - vmin)

您可以手动更改其行为设置 vminvmax,就像在本例中将它们设置为所有子图中的全局极值。

或者,如果您需要更多控制,您可以设置 norm=matplotlib.colors.NoNorm 并自行规范化您的数据,以便它正确映射到 matplotlib 颜色图。