如何在X-Y平面划分网格(Bin)并基于Z值统计量绘制热力图
嘿,我来帮你搞定这些问题!针对你提出的三个核心需求,我整理了一套清晰的实现方案,用scipy.stats.binned_statistic_2d来简化分箱统计,同时解决坐标轴固定和空分箱的问题:
1. 标准实现方案:分箱统计+热力图绘制
scipy.stats.binned_statistic_2d是处理这类2D分箱统计的利器,它直接支持mean、std(标准差)、var(方差)等多种统计量,不用手动计算权重和计数的比值,省心很多。下面是完整的可运行代码:
import numpy as np import matplotlib.pyplot as plt from scipy.stats import binned_statistic_2d # 你的原始数据 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和y的[-20,20]范围,这里设为5个分点(4个分箱),可按需调整num值 num_bins = 5 x_bins = np.linspace(-20, 20, num=num_bins) y_bins = np.linspace(-20, 20, num=num_bins) # 计算分箱内的均值和标准差(方差的话把statistic改成'var'即可) mean_stats = binned_statistic_2d(x, y, z, statistic='mean', bins=[x_bins, y_bins]) std_stats = binned_statistic_2d(x, y, z, statistic='std', bins=[x_bins, y_bins]) # 处理空分箱:将样本数为0的分箱统计值设为NaN mean_vals = mean_stats.statistic mean_vals[mean_stats.count == 0] = np.nan std_vals = std_stats.statistic std_vals[std_stats.count == 0] = np.nan # 绘制两幅热力图:均值和标准差 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # 均值热力图 im1 = ax1.imshow(mean_vals.T, origin='lower', cmap='RdBu', extent=[x_bins[0], x_bins[-1], y_bins[0], y_bins[-1]]) ax1.set_xlabel('X') ax1.set_ylabel('Y') ax1.set_title('Mean of Z per Bin') fig.colorbar(im1, ax=ax1, label='Mean Z') # 标准差热力图 im2 = ax2.imshow(std_vals.T, origin='lower', cmap='RdBu', extent=[x_bins[0], x_bins[-1], y_bins[0], y_bins[-1]]) ax2.set_xlabel('X') ax2.set_ylabel('Y') ax2.set_title('Standard Deviation of Z per Bin') fig.colorbar(im2, ax=ax2, label='Std Z') # 固定坐标轴范围 ax1.set_xlim(-20, 20) ax1.set_ylim(-20, 20) ax2.set_xlim(-20, 20) ax2.set_ylim(-20, 20) plt.tight_layout() plt.show()
2. 固定坐标轴范围的关键
我在代码里用了两种方式确保坐标轴固定在[-20,20]:
- 首先,分箱的边界
x_bins和y_bins直接用np.linspace(-20,20,...)生成,覆盖目标范围; - 然后,
imshow的extent参数明确指定了热力图的x/y轴范围,再配合set_xlim和set_ylim双重保障,完全避免了matplotlib自动缩放坐标轴的问题。
3. 空分箱设为NaN的解决方法
binned_statistic_2d返回的统计对象里有个count属性,记录了每个分箱内的样本数量。我们只需要找到count == 0的位置,把对应的统计值设为np.nan即可:
# 以标准差为例 std_vals = std_stats.statistic std_vals[std_stats.count == 0] = np.nan
这样绘图的时候,空分箱就不会显示成错误的0值,而是自动呈现为空白(或者根据colormap的设置处理)。
如果需要计算方差,只需要把statistic='std'改成statistic='var'就行,其他逻辑完全一致。
内容的提问来源于stack exchange,提问作者Jerome
相关产品推荐
相关产品推荐

