ArcGIS六边形渔网生成工具箱:空间均匀采样与蜂窝图实战

发布时间:2026/10/27 7:08:32
ArcGIS六边形渔网生成工具箱:空间均匀采样与蜂窝图实战

简介:本资源是一款面向GIS从业者与空间分析学习者的ArcGIS工具箱,用于在ArcGIS中快速生成正六边形渔网(蜂窝图),解决传统渔网工具难以直接产出规则六边形格网的问题,适用于城市规划、生态分区、格网统计等场景。压缩包共83个文件,约889KB,包含tbx工具箱、lyr图层文件、mxd工程文档、py脚本以及配套gdb示例地理数据库(含gdbtable、gdbtablx、atx索引等),解压后可直接加载使用,双击工具箱输入研究区与六边形边长即可生成结果,支持ArcGIS 10.2及以上版本,永久可用。目前已有363人学习下载,适合需要快速构建蜂窝格网、开展格网化空间分析的中初级用户参考使用。

1. 六边形渔网不是花架子:从蜂窝图到空间均匀采样的真实需求

做空间分析的人迟早会撞上一个问题:用规则方格网做采样或统计,边缘效应和方向偏差总是阴魂不散。方格网在对角线方向上的邻接距离是边长的 1.414 倍,这意味着同一套数据在不同方向上被"看见"的方式根本不一样。六边形渔网(蜂窝图)就是冲着这个痛点来的——每个六边形的六条边到中心距离完全相等,邻接方向只有六个,各向同性远好于方格。ArcGIS 自带的渔网工具(Fishnet)只能生成矩形网格,想要六边形得自己动手。这份工具箱干的事很明确:在 ArcGIS 里一键生成指定范围、指定大小的六边形蜂窝渔网,输出可直接用于采样、聚合、制图和分析的要素类。适合做土地利用统计、生态样方布设、客流热力聚合、遥感影像分块的人。下面把它怎么落地、参数怎么调、哪里容易翻车,一条条拆开讲。

2. 工具箱的底层逻辑:六边形怎么在 ArcGIS 里被"画"出来

2.1 为什么不用 ArcGIS 自带 Fishnet 硬凑

ArcGIS 的 Fishnet 工具(CreateFishnet)生成的是正交矩形网格,它的几何构造逻辑是"给定原点、Y 轴角度、格网宽高、行列数,逐个计算每个矩形的四个角点"。这套逻辑天生只认矩形,你没法通过改参数让它输出六边形。有人试过用 Fishnet 生成点阵再手动连线,但那样得到的六边形要么边长不一致,要么在投影坐标系下发生形变,后期做邻接分析时拓扑错误一堆。

常见做法是绕开 Fishnet,直接用脚本按六边形几何公式逐行逐列计算中心点坐标,再构造 Polygon。工具箱本质上就是这个思路的封装:输入范围、六边形外接圆半径(或边长),脚本算出所有六边形中心点,然后以每个中心点为基准生成六边形面。这样做的好处是几何精度可控,不会因为投影变形导致蜂窝歪斜——前提是你得用投影坐标系,地理坐标系下算出来的六边形会随纬度变形,这是后面要重点说的坑。

2.2 六边形几何参数与坐标计算

六边形分"平顶"(flat-top)和"尖顶"(pointy-top)两种朝向。平顶六边形的宽是2 * size,高是sqrt(3) * size;尖顶六边形反过来,宽是sqrt(3) * size,高是2 * size。这里size是外接圆半径,也等于边长。工具箱一般默认尖顶朝向,因为它在南北方向上排列更紧凑,适合做纵向采样。

行与行之间的垂直间距是1.5 * size(尖顶情况下),同一行内相邻六边形中心水平间距是sqrt(3) * size,奇数行要水平偏移sqrt(3) * size / 2。这套偏移逻辑是蜂窝图的核心,写错了就会得到一堆重叠或间隙的六边形。下面是一段典型的中心点计算代码,工具箱内部逻辑与此一致:

import math def gen_hex_centers(xmin, ymin, xmax, ymax, size, pointy_top=True): """ 生成覆盖指定范围的六边形中心点坐标 size: 外接圆半径(等于边长) pointy_top: True 为尖顶六边形,False 为平顶 """ centers = [] if pointy_top: # 尖顶:水平间距 sqrt(3)*size,垂直间距 1.5*size dx = math.sqrt(3) * size dy = 1.5 * size row = 0 y = ymin while y <= ymax + size: # 奇数行水平偏移半个间距 x_offset = (dx / 2) if (row % 2 == 1) else 0 x = xmin + x_offset while x <= xmax + size: centers.append((x, y)) x += dx y += dy row += 1 else: # 平顶:水平间距 1.5*size,垂直间距 sqrt(3)*size dx = 1.5 * size dy = math.sqrt(3) * size col = 0 x = xmin while x <= xmax + size: y_offset = (dy / 2) if (col % 2 == 1) else 0 y = ymin + y_offset while y <= ymax + size: centers.append((x, y)) y += dy x += dx col += 1 return centers

这段代码的关键参数就两个:size和pointy_top。size直接决定蜂窝密度,size越小六边形越多、计算越慢;pointy_top决定朝向,选错了后续做邻接矩阵时方向定义会全乱。代码里while y <= ymax + size多留了一个size的余量,是为了保证边缘六边形完整覆盖范围,不然边界上会出现半截六边形。工具箱在调用这段逻辑后,会用arcpy.Polygon按六个顶点构造面,顶点角度从30°开始每隔60°取一个(尖顶情况),平顶则从0°开始。

2.3 工具箱的输入参数与运行环境

工具箱通常以.tbx或.pyt形式提供,挂在 ArcGIS 的 ArcToolbox 里。核心输入参数一般包括:输出要素类路径、范围(可以是要素类、栅格或手动输入的 xmin/ymin/xmax/ymax)、六边形大小(单位跟随坐标系)、朝向选择。运行环境要求 ArcGIS Desktop 10.x 或 ArcGIS Pro,需要 Python 2.7(Desktop)或 Python 3.x(Pro)环境,依赖arcpy站点包。

参数含义常见取值注意
输出路径结果要素类位置地理数据库.gdb内不要输出到 shapefile,字段名会截断
范围来源决定蜂窝覆盖区域要素类 / 栅格 / 手动坐标手动坐标要和数据同坐标系
六边形大小外接圆半径100 / 500 / 1000(米)单位跟随投影坐标系
朝向尖顶或平顶尖顶与后续分析方向定义一致

参数设完后点运行,工具箱会在后台完成中心点计算、面构造、投影写入、属性表添加(通常带一个唯一 ID 字段)。如果范围很大、size很小,生成过程可能跑几分钟到几十分钟,这是正常的,不是卡死。

3. 从零跑通一遍:范围准备、参数设置与结果校验

3.1 准备范围和坐标系

动手之前先把范围定清楚。最常见的做法是拿一个研究区的面要素作为范围输入,工具箱会读取它的extent。但这里有个前置动作容易被跳过:确认数据框和输入要素都用了投影坐标系。如果是地理坐标系(比如 WGS84 经纬度),六边形会随纬度发生形变,越往高纬越扁。判断方法很简单,看坐标系名称里有没有"Degree"或"经纬度"字样,有就说明是地理坐标系,需要先投影。

投影用Project工具,选一个适合研究区的投影带。国内常用的是 CGCS2000 高斯克吕格投影或 UTM 分区投影。投影完再拿投影后的要素去生成蜂窝。这一步不做,后面所有六边形的面积、邻接距离都不可信。

import arcpy # 把研究区面要素投影到适合的投影坐标系 arcpy.Project_management( in_dataset="study_area_wgs84", out_dataset="study_area_projected", out_coor_system=arcpy.SpatialReference(4547) # CGCS2000 3度带 中央经线117E )

SpatialReference(4547)是 CGCS2000 的 3 度带投影,中央经线 117°E,适合华东一带。换研究区要换对应的 EPSG 代码,别照抄。投影完成后,用arcpy.Describe确认一下spatialReference.type是不是"Projected",是的话再往下走。

3.2 调用工具箱生成蜂窝

工具箱挂载后,在 ArcToolbox 里双击打开,按顺序填参数。如果习惯脚本调用,也可以用arcpy直接调工具箱里的脚本工具:

import arcpy # 调用六边形渔网工具箱 arcpy.HexagonFishnet_toolbox( in_features="study_area_projected", out_features="C:/data/analysis.gdb/hex_grid", hex_size=500, # 外接圆半径 500 米 orientation="POINTY", # 尖顶朝向 add_id_field=True # 添加唯一 ID 字段 )

hex_size=500意味着每个六边形外接圆半径 500 米,相邻中心间距约 866 米(尖顶水平方向)。这个尺度适合做中等分辨率的人口或土地利用聚合。如果研究区是城市街区级别,size可以降到 100 甚至 50;如果是省级尺度,可以放大到 5000 或 10000。add_id_field=True会加一个类似HEX_ID的字段,后续做表连接和分组统计时靠它做唯一标识,建议开着。

运行结束后,结果会自动加载到地图。先别急着做分析,花两分钟做几何校验。

3.3 结果校验:面积、邻接与覆盖完整性

校验分三步。第一步看面积:随便选几个六边形,用Calculate Geometry算面积,和理论值(3 * sqrt(3) / 2) * size^2对比。size=500时理论面积约 649519 平方米。如果算出来差很多,说明坐标系或几何构造有问题。

第二步看邻接:用Polygon Neighbors工具(需要 Advanced 许可)或手动量测,确认每个六边形有 6 个邻居(边缘的除外)。如果出现 4 个或 8 个邻居,说明行偏移逻辑写错了,蜂窝变成了错位方格。

第三步看覆盖:把研究区面要素叠上去,目视检查边缘有没有大面积空洞或超出范围太多。工具箱一般会多生成一圈边缘六边形,这是正常的,可以用Select by Location把与研究区不相交的六边形删掉。

# 删除与研究区不相交的边缘六边形 arcpy.MakeFeatureLayer_management("hex_grid", "hex_lyr") arcpy.SelectLayerByLocation_management("hex_lyr", "INTERSECT", "study_area_projected") arcpy.CopyFeatures_management("hex_lyr", "hex_grid_clipped")

SelectLayerByLocation的"INTERSECT"关系会把只要碰到研究区的六边形都留下,包括只搭了一个角的。如果要求六边形中心点落在研究区内,改用"HAVE_THEIR_CENTER_IN"。这一步做完,蜂窝就算真正可用了。

4. 避坑与排查:六边形渔网最容易翻车的五个地方

4.1 地理坐标系下生成,六边形变成"扁蜂窝"

现象:生成的六边形在高纬度地区明显被压扁,面积不一致,邻接距离也不等。原因:地理坐标系以度为单位,经度方向的实际距离随纬度收缩,而脚本按等间距度数计算中心点,导致几何形变。解决:生成前先用Project工具把范围要素投影到投影坐标系,确保size参数的单位是米而不是度。判断方法:看数据框坐标系名称,含"Degree"就是地理坐标系。

4.2 六边形大小设成直径,结果密度翻倍

现象:生成的蜂窝比预期密一倍,六边形数量远超估算。原因:工具箱的size参数是外接圆半径(等于边长),不是直径,也不是对边距离。有人按"直径 1000 米"去填size=1000,实际得到的是半径 1000 米、直径 2000 米的六边形,但数量计算时又按 1000 米估,导致预期和结果对不上。解决:填参数前先确认工具箱文档里size的定义,按半径填。如果不确定,先生成一小块测试,量一下相邻中心间距,尖顶情况下水平间距应该是sqrt(3) * size。

4.3 输出到 Shapefile 导致字段名截断和中文乱码

现象:生成的蜂窝要素类属性表里字段名变成HEX_ID_1、HEX_I之类,或者中文别名显示为乱码。原因:Shapefile 格式限制字段名最长 10 个字符,且对 Unicode 支持差。解决:输出路径一律指向文件地理数据库(.gdb),不要用.shp。如果必须用 Shapefile,字段名控制在 10 字符以内,别名用英文。

4.4 范围太大导致内存溢出或运行超时

现象:工具箱跑到一半报内存错误,或者进度条卡住几十分钟不动。原因:size设得太小、范围太大,六边形数量达到百万级,arcpy逐面构造 Polygon 时内存扛不住。解决:先估算六边形数量,公式是(范围面积) / (六边形面积),六边形面积约2.598 * size^2。如果超过 50 万,考虑放大size或分块生成再合并。分块时注意块与块之间要留重叠带,避免接缝处出现半截六边形。

4.5 邻接分析时发现六边形有重叠

现象:做Polygon Neighbors或空间连接时,发现某些六边形互相重叠,或者同一个六边形被重复计数。原因:行偏移量算错,奇数行偏移了dx而不是dx/2,导致相邻行六边形错位重叠。解决:检查中心点计算代码里x_offset的值,尖顶情况下应该是dx / 2,平顶情况下y_offset应该是dy / 2。生成后用Intersect工具自查,如果结果非空说明有重叠,需要修正偏移逻辑重新生成。

5. 进阶用法:把蜂窝渔网接进空间统计与制图流程

蜂窝图生成只是第一步,真正体现价值的是后续怎么用。一个高频场景是空间聚合统计:把点数据(比如 POI、采样点)按六边形分组计数,得到每个六边形的密度值,再拿去做热力图或聚类分析。做法是用Spatial Join把点要素连接到六边形上,match_option选"CONTAINS",然后按HEX_ID分组统计。

# 把 POI 点空间连接到六边形,统计每个六边形内的点数 arcpy.SpatialJoin_analysis( target_features="hex_grid_clipped", join_features="poi_points", out_feature_class="hex_with_count", join_operation="JOIN_ONE_TO_ONE", join_type="KEEP_ALL", match_option="CONTAINS" ) # 此时属性表里 Join_Count 字段就是每个六边形的点数

join_type="KEEP_ALL"保证没有点的六边形也保留,Join_Count为 0。这一步之后,可以拿Join_Count做分级设色,或者导出到其他工具做空间自相关分析。六边形的邻接关系比方格更均匀,做 Moran's I 或 Getis-Ord Gi* 时结果更稳,这是蜂窝图在空间统计里的核心优势。

另一个场景是遥感影像分块采样。把蜂窝渔网叠在影像上,每个六边形作为一个采样单元,提取六边形范围内的像元均值。用Zonal Statistics as Table工具,zone_field选HEX_ID,statistics_type选"MEAN",输出表格再连接回六边形属性表。这样得到的采样数据在空间上分布均匀,不会像方格那样在方向上产生系统性偏差。

# 按六边形分区统计栅格均值 arcpy.gp.ZonalStatisticsAsTable( in_zone_data="hex_grid_clipped", zone_field="HEX_ID", in_value_raster="ndvi.tif", out_table="hex_ndvi_stats", statistics_type="MEAN" )

zone_field必须是整型字段,HEX_ID如果生成时是字符串要先转成整型。statistics_type除了"MEAN",还可以选"SUM"、"MAX"、"MIN"、"STD",按分析目标定。输出表格用HEX_ID和六边形做Join,就能在地图上按 NDVI 均值设色。

最后说一个我自己的习惯:每次生成蜂窝后,先跑一遍Check Geometry和Repair Geometry,再跑Polygon Neighbors确认邻接数。这三步加起来不到一分钟,但能挡掉后面九成的玄学问题。从那以后我每次做蜂窝渔网都强制走一遍这个校验流程,宁可多花一分钟,也不想在空间统计跑完之后才发现几何有毛病。希望帮到你。

本文还有配套的精品资源,点击获取