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

如何获取matplotlib hexbin图中六边形的精确面积以计算质量面密度?

如何获取matplotlib hexbin生成的六边形精确面积?

我想用matplotlib的hexbin绘制质量面密度图,输入是包含[经度(lon)、纬度(lat)、质量(mass)]的数千条数据的DataFrame。hexbin速度很快,我调用时设置了reduce_C_function=np.sum来获取每个六边形内的质量总和,现在需要将这个总和除以六边形面积得到单位面积质量,但没法获取生成的不规则六边形的精确面积,目前只能通过代码获取六边形中心位置,请问有什么方法可以获取精确面积?

代码示例

# 计算x方向六边形数量,使六边形宽度约为100米
nx = round(111000 * lenght_x / 100)

hb = df.plot.hexbin(
        x="lon",
        y="lat",
        C="mass",
        gridsize=nx,
        cmap="viridis",
        mincnt=3,
        ax=ax,
        reduce_C_function=np.sum,
    )

# 获取六边形中心
pollycollection = hb.get_children()[0]
centers = pollycollection.get_offsets()
x_c = [p[0] for p in centers]
y_c = [p[1] for p in centers]
plt.plot(x_c, y_c, "x-", color="red")

解决方法

方法1:通过六边形路径计算实际面积

PolyCollection对象的get_paths()可以获取每个六边形的顶点路径,结合地理坐标转换计算真实面积:

import matplotlib.path as mpath
import numpy as np

pollycollection = hb.get_children()[0]
paths = pollycollection.get_paths()
actual_areas = []

for idx, path in enumerate(paths):
    # 获取当前六边形的顶点经纬度
    vertices = path.vertices
    lon_list, lat_list = vertices[:, 0], vertices[:, 1]
    
    # 转换经纬度为米级坐标(基于中心纬度的近似转换)
    lat_center_rad = np.radians(y_c[idx])
    # 1度经度对应的米数:随纬度变化
    lon_per_m = 111320 * np.cos(lat_center_rad)
    # 1度纬度对应的米数:近似111000米
    lat_per_m = 111000
    
    # 将顶点转换成米坐标
    x_m = (lon_list - lon_list.mean()) * lon_per_m
    y_m = (lat_list - lat_list.mean()) * lat_per_m
    
    # 计算多边形面积
    area = mpath.Path(np.column_stack((x_m, y_m))).area
    actual_areas.append(abs(area))

方法2:利用gridsize计算理论面积(适合小范围数据)

hexbin的六边形是规则排列的,可通过数据范围和gridsize推导面积,再结合纬度转换:

import numpy as np

# 获取经纬度数据范围
x_min, x_max = df['lon'].min(), df['lon'].max()
y_min, y_max = df['lat'].min(), df['lat'].max()

# 计算单个六边形的经纬度宽度
hex_width_deg = (x_max - x_min) / nx
# 六边形的理论经纬度面积公式:正六边形面积 = (3√3/2) * (边长)²
hex_area_deg = (3 * np.sqrt(3) / 2) * (hex_width_deg / 2) ** 2

# 转换为实际地理面积(平方米)
lat_rad = np.radians(y_c)
actual_areas = hex_area_deg * 111000 * 111320 * np.cos(lat_rad)

方法3:先投影坐标再计算(最准确)

将经纬度转换为平面投影坐标系(如UTM),再用hexbin绘制,此时直接计算的面积就是真实地理面积:

from pyproj import Transformer
import matplotlib.path as mpath

# 根据数据所在区域选择对应的UTM投影(示例为UTM 33N)
transformer = Transformer.from_crs("EPSG:4326", "EPSG:32633")
df['x_utm'], df['y_utm'] = transformer.transform(df['lat'], df['lon'])

# 重新计算gridsize(基于100米宽度)
nx = round((df['x_utm'].max() - df['x_utm'].min()) / 100)

hb = df.plot.hexbin(
        x="x_utm",
        y="y_utm",
        C="mass",
        gridsize=nx,
        cmap="viridis",
        mincnt=3,
        ax=ax,
        reduce_C_function=np.sum,
    )

# 直接获取六边形面积(单位:平方米)
pollycollection = hb.get_children()[0]
paths = pollycollection.get_paths()
actual_areas = [abs(mpath.Path(path.vertices).area) for path in paths]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:59:52