首页 > 解决方案 > 如何在图像上放置“网格”(例如将 xy 平面划分为 bin)以计算每个 bin 中 z 值的平均值并将其绘制为热图?

问题描述

我的目标:

我有 x、y 和 z 值作为数组。例如:

x=np.array([10,2,-4,12,3,6,8,14])
y=np.array([5,5,-6,8,20,10,2,2])
z=np.array([4,6,10,40,22,14,20,8])

我想绘制一个热图,其中 z 值将作为每对 (x,y) 的强度或“权重”,轴将是 x 和 y 值。所以,我的情节将在 xy 平面上。我想通过将我的 xy 平面分成箱,然后计算每个箱内 z 值的平均值并将该平均值用作该箱的颜色或强度,在我的绘图顶部放置一个“网格”。我还想绘制另一个图,但我想将 z 值的方差绘制为箱内的强度。

我做了什么:

我按照以下方式对其进行了编码,但我认为我误解了一些事情......我认为我不太了解垃圾箱等(我是编程新手)。

import numpy as np
import matplotlib.pyplot as plt
x=np.array([10,2,-4,12,3,6,8,14])
y=np.array([5,5,-6,8,20,10,2,2])
z=np.array([4,6,10,40,22,14,-20,8])

# Bin the data onto a 2x2 grid
# Have to reverse x & y due to row-first indexing
zi, yi, xi = np.histogram2d(y, x, bins=(2,2), weights=z, normed=False)
counts, _, _ = np.histogram2d(y, x, bins=(2,2))

#to get mean divide by counts

zi = zi / counts
print(zi)

zi = np.ma.masked_invalid(zi)

fig, ax = plt.subplots()
sc=ax.pcolormesh(xi, yi, zi, edgecolors='black')
sct = ax.scatter(x, y, c=z, s=200) #shows the points in the bins 
fig.colorbar(sc)
ax.margins(0.05)

plt.show()

我被困在哪里:

我什至不确定上面的代码是否做对了。因此,请随意忘记它,并就解决此问题的任何其他标准方法向我提供建议。使用上面的代码,我得到一个图,其中轴限制由给定的数据集自动确定,但我想保持我的轴恒定在xmin=-20,xmax=20,ymin=-20,ymax=20. 此外,我不确定如何操纵箱内的 z 值来计算其他统计量,如方差或标准偏差等。

编辑:所以,我有一些更好的代码,它给出了 bin 和 plot 中的平均 z 值,np.histogram2d我现在可以根据自己的喜好设置轴等,但是使用它可以得到 H 作为 bin 中值的总和,我可以得到意思是,但不是其他统计量,如方差。我想要一种对此进行编码的方法,以便我可以访问 bin 中的值,并且可以计算这些值的方差并将该结果用作热图的权重/强度。

我附上了垃圾箱中平均 z 的图。

import numpy as np
import matplotlib.pyplot as plt

x=np.array([10,2,4,12,3,6,8,14])
y=np.array([5,5,6,8,20,10,2,2])
z=np.array([4,6,10,40,22,14,20,8])

x_bins = np.linspace(0, 20, 3)
y_bins = np.linspace(0, 20, 3)

H, xedges, yedges = np.histogram2d(x, y, bins = [x_bins, y_bins], weights = z)
H_counts, xedges, yedges = np.histogram2d(x, y, bins = [x_bins, y_bins])

print(H)
H1 = H/H_counts
print(H1)

plt.xlabel("x")
plt.ylabel("y")

plt.imshow(H1.T, origin='lower',  cmap='RdBu',
            extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])
plt.colorbar().set_label('mean z', rotation=270)

这是均值 z 的图

编辑2:当我使用统计标准偏差时,我得到以下图

标准图

右上角的深红色 bin 实际上是空的并且没有 z 值,所以我希望标准偏差为“Nan”而不是被分配值 0。我该怎么做?

我的这个情节的代码是:

from scipy import stats
import numpy as np
import matplotlib.pyplot as plt

x=np.array([10,2,4,12,3,6,8,14])
y=np.array([5,5,6,8,20,10,2,2])
z=np.array([4,6,10,40,22,14,20,8])

x_bins = np.linspace(0, 20, 3)
y_bins = np.linspace(0, 20, 3)

H, xedges, yedges = np.histogram2d(x, y, bins = [x_bins, y_bins], weights = z)

#mean = stats.binned_statistic_2d(x,y,z,statistic='',bins=[x_bins,y_bins])
#mean.statistic
std = stats.binned_statistic_2d(x,y,z,statistic='std',bins=[x_bins,y_bins])
#std.statistic
#print(std.statistic)
plt.xlabel("x")
plt.ylabel("y")
plt.imshow(std.statistic.T, origin='lower',  cmap='RdBu',
            extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])
#plt.clim(0, 20)
plt.colorbar().set_label('std z', rotation=270)

标签: pythonarraysnumpymatplotlibbin

解决方案


您的数据需要在规则网格上进行插值,因为您的计算机不知道哪个z是没有值的值。幸运的是,已经有一个功能:scipy.interpolate.griddata.

import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt

# Dummy data
x=np.array([10,2,-4,12,3,6,8,14])
y=np.array([5,5,-6,8,20,10,2,2])
z=np.array([4,6,10,40,22,14,-20,8])

# Create a regular grid along x and y axis
grid_x, grid_y = np.mgrid[x.min():x.max()+1, y.min():y.max()+1]

# Linear interpolation
# But you could also use a cubic interpolation or whatever you want/need
z_interpolated = griddata((x,y), z, (grid_x, grid_y), method='linear')

# Plot the result:
plt.imshow(z_interpolated, cmap='plasma')

我们得到:

在此处输入图像描述

注意到图像边界上没有值,因为您的空间域没有定义超出包含的值xy因此使用线性插值,您的计算机无法猜测超出这些点的值应该是什么。因此,热图仅限于由您的点形成的凸包,其他任何内容都将是外推。

编辑:

如果您需要计算双向分箱统计,您可以使用:

scipy.stats.binned_statistic_2d()

在您的情况下,如果我们要计算方差和均值:

from scipy import stats
std = stats.binned_statistic_2d(x,y,z,statistic='std',bins=[x_bins,y_bins])
mean = stats.binned_statistic_2d(x,y,z,statistic='mean',bins=[x_bins,y_bins])

哪里mean完全等同于你的H/H_counts


推荐阅读