You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Matplotlib中hexbin每个六边形内的对应数据点?

获取Matplotlib Hexbin分箱对应的原始数据点

问题背景

我正在开发一款用于交互式分析百万级2D散点图的应用,采用Matplotlib的2D六边形分箱(hexbin)功能来减少绘图点数。但需要获取每个分箱对应的原始数据点,目前用shapely判断点是否在六边形内的方案存在冗余——Matplotlib内部应该已经完成了点到分箱的分配计算,希望直接提取这些信息。

无需修改源码的高效解决方案

Matplotlib的hexbin返回的PolyCollection对象,其内部计算逻辑已经完成了点到分箱的索引映射,我们可以直接复用这部分结果,无需重复做几何判断:

步骤1:调用Matplotlib内部分箱计算逻辑

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.axes._axes import _hexbin

# 生成百万级测试数据
x = np.random.normal(loc=100, scale=20, size=1000000)
y = np.random.normal(loc=1000, scale=20, size=1000000)

# 绘制hexbin并获取对象
fig, ax = plt.subplots(figsize=(10, 8))
hexbin = ax.hexbin(x, y, gridsize=25, cmap='jet', picker=True)

# 调用Matplotlib内部的核心分箱计算函数
xlim = ax.get_xlim()
ylim = ax.get_ylim()
counts, xedges, yedges, nx, ny, binx, biny = _hexbin(x, y, hexbin.gridsize, xlim, ylim)

这里的binx和biny是每个原始数据点对应的分箱在x、y方向的网格索引,nx/ny是x/y方向的总分箱数。

步骤2:建立分箱到原始点的映射

# 生成每个点的唯一分箱ID
bin_ids = binx + biny * nx

# 过滤掉超出绘图范围的点(这类点的binx/biny为-1)
valid_mask = binx != -1
valid_bin_ids = bin_ids[valid_mask]
valid_point_indices = np.where(valid_mask)[0]

# 分组获取每个分箱对应的原始点索引
unique_bin_ids = np.unique(valid_bin_ids)
bin_to_points = {}
for bin_id in unique_bin_ids:
    point_mask = valid_bin_ids == bin_id
    bin_to_points[bin_id] = valid_point_indices[point_mask]

# 关联分箱ID与hexbin的offsets(即分箱中心坐标)
# 非空分箱的顺序与hexbin.get_offsets()完全一致
non_empty_mask = counts.flatten() > 0
all_bin_ids = np.arange(nx * ny).reshape(ny, nx).flatten()
non_empty_bin_ids = all_bin_ids[non_empty_mask]

# 最终得到:offsets索引 → 对应原始点的索引列表
offset_to_points = {i: bin_to_points[bid] for i, bid in enumerate(non_empty_bin_ids)}

现在offset_to_points中的键对应hexbin.get_offsets()的索引,值就是该分箱下所有原始数据点的索引,完全复用Matplotlib的计算结果,效率比shapely方案提升几个数量级。

为什么这个方案可行?

Matplotlib的_hexbin是ax.hexbin的核心计算函数,它会直接对原始坐标做网格映射,计算出每个点所属的分箱索引,这一步是绘制hexbin的必经流程。我们只是把它内部计算好的索引结果提取出来,避免了重复的几何判断操作。

修改Matplotlib源码的思路(可选)

如果希望直接在Matplotlib中集成该功能,可以修改axes/_axes.py中的hexbin相关代码:

  1. 在_hexbin函数末尾添加点到分箱ID的计算:
bin_ids = binx + biny * nx
point_to_bin = bin_ids
  1. 在ax.hexbin函数中,将point_to_bin赋值给返回的PolyCollection对象:
hexbin = PolyCollection(...)
hexbin.point_to_bin = point_to_bin

后续就可以直接通过hexbin.point_to_bin获取每个点对应的分箱ID,再自行分组。不过这种方案需要修改源码,存在版本兼容性风险,建议优先使用非侵入式方案。

内容的提问来源于stack exchange,提问作者sweetdream

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 15:07:27