ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ArcGIS创建渔网:参数计算、批量脚本与不显示排查

ArcGIS创建渔网:参数计算、批量脚本与不显示排查

渔网(Fishnet)这个工具,我在 ArcGIS 里用了快十年,被同事追问的频率也差不多有十年。问题几乎永远是同一句:“ArcGIS 如何创建渔网?我建完了,渔网不见了。”前半句是操作问题,后半句是显示问题,两个问题卡在同一句话里,其实正好说明了一件事:渔网的参数逻辑和 ArcGIS 的图层显示逻辑是两套独立的东西,任何一套没理顺,你都会觉得“东西没生成”。这篇就把这两件事彻底拆开讲:参数怎么填、数字怎么算、脚本怎么写,以及渔网建完之后躺在内容列表里却看不见的六种真实原因。适合刚上手 ArcGIS 的新人,也适合天天做格网统计、分幅出图、样方抽样的老手——后面几节的字段扩展和批量脚本,是我自己在项目里沉淀下来的写法,能直接拿去改。

1. 先搞清楚渔网到底是什么,再谈怎么建

1.1 渔网的本质是一套规则化的矢量格网

很多人把渔网想成“地图上画的格子”,这个理解不太准确。渔网在 ArcGIS 里是实打实的矢量要素类,落到地理数据库里就是一堆面或者一堆线,每个格子有自己的 FID、有自己的几何、有自己的属性表记录。它跟你在布局视图里加的参考格网完全是两回事——后者是制图装饰,前者是能用 Select by Attributes 筛、能做空间连接、能参与分区统计的数据。

理解这一点非常关键,因为它直接决定了两件事。第一,渔网的格网数量是有代价的,一万个面还好,一百万个面会让符号化和属性表操作明显变慢,因为每一个格子都是一条独立记录。第二,渔网生成之后“看不见”,绝大概率不是数据没生成,而是图层渲染、坐标系或者视图范围出了问题——数据在硬盘上好好的,只是没画出来。我见过太多人反复点工具、反复重跑,最后发现要素类已经生成了七八个,全堆在默认数据库里。

渔网的规则性体现在三个参数上:原点、方向、步长。原点确定左下角那颗钉子的位置,方向由 Y 轴坐标点确定(默认正北),步长就是每个格子的宽和高。行数和列数决定了往东、往北各铺多少格。四个东西凑齐,整个格网就唯一确定了,没有任何随机性。这也是为什么渔网特别适合做标准化流程——同样的参数跑一百遍,结果完全一致。

1.2 三种常见用法与工具选型判断

同样是“画格子”,ArcGIS 里其实有三四个不同的工具,选错了就会出现“建完找不到”的尴尬。我在下面这张表里把最容易混淆的几个列清楚,你对着自己的目的挑就行。

工具产出物类型典型用途会不会出现在地图视图里
创建渔网 Create Fishnet矢量要素类(面或线)格网统计、样方抽样、分幅索引会,需要手动加图层
格网索引要素 Grid Index Features矢量面要素类分幅出图、图幅索引表会,自带页码和比例字段
生成格网 Generate Grid布局元素出图时压在地图框上的参考网不会,只在布局视图可见
创建规则渔网(栅格化思路)栅格大范围快速分区会,但已经是栅格

表格里第三行是重灾区。不少人搜“ArcGIS 创建渔网”,出来的第一个结果是布局用的格网工具,点进去生成完,数据视图里空空如也,于是就有了“渔网不见了”这个疑问。记住一条判断标准:如果你要拿格网去做统计、做连接、做筛选,那必须是矢量要素类,用创建渔网或者格网索引要素;如果只是想让打印出来的图上有经纬度线或者方里网,那才用布局格网。

至于创建渔网和格网索引要素怎么选,我的经验是看下游需求。单纯要一堆规则的面去做分区统计,创建渔网足够了,参数少、逻辑干净;如果后面要批量出图、每个格子对应一张图、还要在属性表里看到“第几行第几列、比例尺多少”,那格网索引要素省事得多,它自带 PageName、RowLabel、ColLabel 这些字段,接地图系列的时候几乎不用二次处理。

2. 参数准备:九成的“不见了”都埋在这一步

2.1 坐标系选错,格子会小到肉眼看不见

这是我见过最高频的翻车点,没有之一。创建渔网工具本身不强制你选坐标系,它跟着输出位置走,很多人直接把输出丢进默认地理数据库,而默认数据库的要素类往往是地理坐标系(比如常见的经纬度)。这时候“像元宽度”这个参数的单位就变成了度,不是米。

一度在赤道附近大约一百一十一公里,你按平时的习惯填个 100,以为是一百米,实际上是绕地球跑了两圈半,工具要么跑很久,要么直接给你一个覆盖大半个中国的巨网。反过来,有人意识到单位不对,改填 0.001,那就是一百多米,听着挺合理,但如果你的地图视图当前缩放到几千公里范围,这个格子只有零点几个像素,屏幕上当然什么都没有。数据是真生成了,要素数也是对的,只是你 zoom 到那一层才看得见。

所以正确的做法是:先建一个投影坐标系的要素类或者要素数据集,把渔网输出到那里,让像元宽高的单位明确是米。判断方法很简单,打开渔网的属性,看空间参考那一栏写的是不是“投影坐标系”。如果不放心,用测量工具在地图上量一下某个格子的实际边长,跟参数对得上就说明单位没问题。

注意:如果输出位置已经是地理坐标系,工具不会报错,也不会提醒你单位问题,它只会安安静静地生成一个尺度完全不对的结果。这个坑没有报错信息兜底,只能靠事前检查。

2.2 范围、行列数与像元大小的换算关系

渔网的四个核心参数之间有硬约束:范围决定总跨度,像元大小决定单格尺寸,行数乘列数决定总格数。三者必须自洽,否则要么渔网超出研究区一大截,要么盖不满。

举一个我实际项目里的例子。某研究区是一个矩形,投影坐标系下 X 从 500000 到 512800,Y 从 3200000 到 3209600,也就是东西 12800 米、南北 9600 米。我要做 200 米见方的格网,算法很直白:

  • 列数 = (512800 − 500000) ÷ 200 = 64
  • 行数 = (3209600 − 3200000) ÷ 200 = 48
  • 总格数 = 64 × 48 = 3072

原点坐标填 (500000, 3200000),这是左下角;Y 轴坐标填 (500000, 3209600),也就是原点正上方一个总高度的位置。这两个点连成的方向就是格网的“北”,两点的 X 相同,格网就是正的,不会有旋转。

如果除不尽怎么办?比如研究区东西跨度 12800 米,我想用 250 米的格子,12800 ÷ 250 = 51.2,不是整数。这时候工具的行为是:如果你同时给了行列数和像元大小,它按你给的行列数生成,格网可能盖不满或者略微超出;如果你只给像元大小和对角点,它会把行列数向上取整到 52,多出来的 0.2 格也就是 50 米会溢出边界。我的习惯是手动向上取整,然后用研究区边界去做一次裁剪(Clip),把溢出的半格切掉,保证统计结果不包含研究区外的面积。

还有一个容易忽略的参数是对角点。工具允许你只填原点和右上角对角点,行列数留 0,让它自己算。这在快速试参数的时候很方便,但正式成果我建议还是把行列数写死,因为自动取整的规则在不同版本里偶尔会有细微差别,写死了才能保证可复现。

2.3 旋转角与几何类型的选择

渔网默认是正南正北的,但它支持旋转,控制方式有点反直觉——不是填角度,而是改 Y 轴坐标点的位置。比如你想让格网顺时针转 30 度,就把 Y 轴坐标点从原点正上方挪到右上方某个位置,两点连线与正北的夹角就是旋转角。

这个设计对沿河道、沿公路走向布设格网特别有用。我之前做过一个沿线监测的项目,监测带是斜着穿过研究区的,正交格网会浪费大量格子,后来把 Y 轴点沿线路方向偏了二十多度,格网贴合度立刻上来了,无效格子少了将近三成。

几何类型只有两个选项:面(POLYGON)和线(POLYLINE)。做统计、做连接、做裁剪,一律选面;只想要底图上的分幅线、不参与任何分析,选线更轻量,要素数量一样但渲染快很多。另外工具还有一个“创建标注点”的开关,勾上之后会额外生成一个点要素类,每个格子的中心有一个点,命名规则是在输出名后面加_label。这个点集在做样方抽样、做代表性点位选取的时候非常好用,等于白送一份中心点数据。

3. 三条创建路径:对话框、批处理与脚本

3.1 工具箱对话框的完整操作顺序

ArcGIS Pro 里,创建渔网在“数据管理工具 > 采样 > 创建渔网”,ArcMap 里在“数据管理工具 > 要素类 > 创建渔网”,位置不同但参数一模一样。打开之后的填写顺序我建议固定成下面这样,能少走很多弯路:

  1. 输出要素类先指到一个投影坐标系的地理数据库里,别用默认库
  2. 原点坐标填研究区范围的左下角,格式是“X Y”,中间用空格
  3. Y 轴坐标填原点正上方一个总高度处,X 保持不变
  4. 像元宽度、像元高度填以米为单位的格网边长
  5. 行数、列数按前面算出来的值填
  6. 几何类型选面
  7. 需要中心点就勾上创建标注点

填完之后先别急着点运行,用“环境”选项卡里的输出坐标系再确认一遍,跟目标数据库保持一致。运行完,工具不会自动把结果加到地图上——这一点跟很多人的预期不一样,ArcGIS 的多数地理处理工具都是“生成文件”,不是“生成图层”。你得自己去内容列表里点“添加数据”,把刚生成的要素类拉进来。这一步漏掉,就是最朴素意义上的“渔网不见了”。

3.2 用 Python 脚本批量生成与参数复用

参数一旦定下来,就该转脚本了。手动点对话框最怕的就是改一个参数忘一个,尤其是要给十几个分区分别建渔网的时候,脚本能把出错概率压到接近零。下面这段是能直接跑的最小骨架,注意参数顺序:

import arcpy out_fc = r"C:\work\project.gdb\fishnet_200m" origin = "500000 3200000" # 左下角 X Y y_axis = "500000 3209600" # 正上方一个总高度 cell_w = 200 cell_h = 200 rows = 48 cols = 64 arcpy.management.CreateFishnet( out_fc, origin, y_axis, cell_w, cell_h, rows, cols, None, # 对角点,给了行列数就不填 "LABELS", # 生成中心点标注,不需要就写 "NO_LABELS" None, # 模板范围 "POLYGON" )

参数里最容易搞错的是第六、第七位,行在前、列在后。我见过有人把 64 和 48 填反,结果得到一个又扁又宽的格网,还以为是自己范围算错了。另外对角点那个位置如果非要传值,记得行列数要留空或者写 0,两者同时给会以行列数为准。

批量生成的话,外面套一层循环,把每个分区的范围读进来,算出原点和 Y 轴点,输出名带上分区编号:

import arcpy zones = [ ("Z01", 500000, 3200000, 512800, 3209600), ("Z02", 512800, 3200000, 525600, 3209600), ] for name, xmin, ymin, xmax, ymax in zones: cols = int((xmax - xmin) // 200) rows = int((ymax - ymin) // 200) arcpy.management.CreateFishnet( rf"C:\work\project.gdb\fn_{name}", f"{xmin} {ymin}", f"{xmin} {ymax}", 200, 200, rows, cols, None, "NO_LABELS", None, "POLYGON" ) print(f"{name} 完成,{rows} 行 × {cols} 列")

这种写法我在做跨区域对比研究时用得最多,十几个分区一次跑完,属性表里每个格网还能通过输出名反查属于哪个分区,省掉了后面手动合并再拆分的麻烦。

3.3 建完之后必做的三项自检

渔网生成成功不等于结果可用,我每次跑完都会做三个检查,加起来不到一分钟,能挡住后面八成的问题。

第一,看要素数量。在属性表里拉到最底下,记录数应该等于行数乘列数,对不上就说明参数有问题。第二,打开属性看空间参考,确认是投影坐标系而不是地理坐标系。第三,在地图上用测量工具量一个格子的边长,跟设定的像元大小比对。这三步做完,数据的正确性基本有底了。

如果第三步量出来的边长跟设定值差了十万八千里,别怀疑工具,先回去看坐标系。如果要素数量对、坐标系也对,但地图上就是看不见,那就是下一节要讲的显示问题了。

4. “渔网不见了”的六种真相与逐条排查

4.1 图层没被加进来,或者加进来了但被视图甩在身后

最朴素的原因往往最容易被忽略。地理处理工具生成的是硬盘上的文件,不是地图上的图层。很多人跑完工具,看内容列表没变化,就认定失败了,其实文件已经安安静静躺在数据库里。去目录窗格里找到那个要素类,右键“添加到当前地图”,问题解决。

还有一种情况是图层确实加进来了,但当前地图视图缩放的位置离渔网十万八千里。比如你刚才在看另一个区域的底图,渔网建在几百公里外,添加进来之后自然什么都看不到。判断方法很简单:右键图层选“缩放至图层”,如果视野“唰”地跳到一个陌生位置并且出现了格网,那就说明数据一直好好的,只是你没看对地方。

我个人的习惯是把“缩放至图层”设成添加数据后的条件反射动作,比在地图上瞎拖要快得多。

4.2 坐标系不匹配造成的尺度错位

这个在 2.1 节提过,但值得单独拿出来说,因为它伪装得特别好。要素类本身是有效的,属性表记录数也对,可你在地图上就是找不到——因为它要么小得像一粒沙,要么大得把整个地图撑爆。

排查思路是反过来的:先在内容列表里右键渔网图层,看“属性 > 源”里的空间参考。如果显示的是地理坐标系,而你原本想要的是米级格网,那基本可以确诊。处理方法有两个,一是用投影工具把现有渔网转到投影坐标系(注意:如果你是按度生成的,转过来尺度依然是错的,转完还得重算),二是老老实实回到投影坐标系重新建一遍。

顺带说一句,动态投影会让这个问题变得更隐蔽。地图框是投影坐标系,渔网是地理坐标系,ArcGIS 会在显示时自动做一次投影变换,位置看着是对的,但尺度感完全失真,你根本意识不到单位有问题。所以我一直建议渔网这类"有明确物理尺寸"的数据,从生成那一刻就用投影坐标系。

4.3 符号系统把格子画成了隐形

要素在那儿、位置也对、缩放也到位,可屏幕上就是一片空白。这时候去看图层符号:填充色跟底图撞了、填充透明度拉到 100%、轮廓线宽设成 0、图层整体透明度调到了极低——这几种设置任意一种成立,视觉上都是“没有”。

排查办法是把图层拖到最上面,右键打开符号系统,先把填充改成鲜艳的纯色、轮廓线宽改成 1 磅、两个透明度都拉回 100%,如果图案立刻出现,那就是符号问题。如果还是没有,再检查图层有没有被误设成“仅显示轮廓”或者被某个定义查询过滤掉了——定义查询这个坑尤其阴,图层属性里设了一个WHERE 1=2之类的条件,数据全被过滤,地图上自然空空如也,但属性表打开一看记录数还是满的。

提示:属性表有记录、地图上没图形,先怀疑符号和定义查询;属性表也没记录,才回去怀疑生成参数。

4.4 可见比例范围把图层关掉了

ArcGIS 的图层可以设置“最小可见比例”和“最大可见比例”,超出范围图层就自动隐藏。这个功能原本是为了性能优化,但对不熟悉的人来说就是纯粹的迷惑行为——图层在内容列表里明明勾着,就是不显示。

判断特征很明显:你把地图稍微放大或缩小一点,图案“啪”地出现或者消失。遇到这种规律性出现消失,直接右键图层打开属性,找到“常规”里的可见比例范围,把上下限都清空,问题立刻解决。有些模板工程会批量给图层设比例范围,你从别人那儿拷贝过来的地图文档特别容易中这一枪。

4.5 原点填错导致的整体偏移

渔网确实生成了,也确实显示了,但位置整体偏出去一大截。最常见的错误是把研究区范围的左上角当成了原点。渔网的原点定义是左下角,填了左上角,整个格网会往下偏一个总高度,看起来像是“跑到南边去了”。

第二种错误是 X 和 Y 填反了。输入框里是“X Y”顺序,如果填成“Y X”,在投影坐标系下这个点可能直接飞到研究区几千公里外,格网自然也就不在视野里。识别方法很简单:算一下偏移方向,如果整体往南偏了一个总高度,是原点填错;如果偏得毫无规律、动辄上千公里,多半是 X/Y 反了。

第三种错误是 Y 轴坐标点的 X 跟原点不一致,导致格网被旋转了一个角度。如果不是有意的斜向布设,看到格网歪了,就回去检查这两个点的 X 值是否相同。

4.6 工具其实没跑完,或者跑出来了空要素

还有一种“不见了”是字面意义上的:文件都没生成。行列数填成 0 又没给对角点,工具会直接报错退出;行列数填得极大(比如几万乘几万),工具会跑上几个小时甚至直接内存告急,你以为它完成了,其实还在转圈。判断方法是看地理处理面板里的运行状态,以及输出位置有没有对应的要素类文件。

另外,如果研究区范围本身是空的(比如图层选择集为空、定义查询过滤掉了全部要素),工具可能生成一个零要素的渔网,看着像是成功了,打开属性表一片空白。养成看一眼要素数量的习惯,能省下大量自我怀疑的时间。

现象最可能原因处理动作
内容列表没变化工具只生成文件,不加图层目录里手动添加到地图
加了图层但地图空白视图范围不重合右键缩放至图层
缩放后才看到密密麻麻小点地理坐标系下按度设了像元换投影坐标系重建
图层勾着却不显示,缩放才出现可见比例范围限制清空比例范围上下限
属性表有记录但无图形符号透明、线宽 0、定义查询过滤恢复符号、清除定义查询
格网整体偏南一个总高度原点填成了左上角改填范围左下角
格网歪斜Y 轴点与原点 X 不一致保持两点 X 相同
生成了空要素类行列数为 0 或范围为空补齐参数、检查选择集

5. 让渔网真正能用的进阶处理

5.1 补上行列号与格网编码字段

刚生成的渔网属性表里只有 OBJECTID 和 Shape_Length、Shape_Area 这几个字段,拿来统计很难对应到具体位置。我一般会立刻补三个字段:行号、列号、格网编码,编码格式用R03C17这种,人一眼就能在地图上定位。

Create Fishnet 生成要素的顺序是固定的——从左下角开始,先沿 X 方向铺满一行,再往上走一行。所以行号列号可以直接从 OBJECTID 反推,不需要读取几何:

import arcpy fc = r"C:\work\project.gdb\fishnet_200m" cols = 64 arcpy.management.AddField(fc, "ROW_ID", "SHORT") arcpy.management.AddField(fc, "COL_ID", "SHORT") arcpy.management.AddField(fc, "GRID_CODE", "TEXT", field_length=12) with arcpy.da.UpdateCursor(fc, ["OID@", "ROW_ID", "COL_ID", "GRID_CODE"]) as cur: for oid, r, c, code in cur: idx = oid - 1 row = idx // cols + 1 col = idx % cols + 1 cur.updateRow([oid, row, col, "R{:02d}C{:02d}".format(row, col)])

这段代码有个前提:要素类是新生成的,OBJECTID 连续无空洞。如果中途删过格子,序号就断了,这时候得改用读取几何中心点坐标来反算行列,稳妥但慢一些。

顺手把中心点坐标也加上,做散点图、做空间插值、导出到其他工具都用得上。方法是用SHAPE@TRUECENTROID令牌遍历一次,把 X、Y 写进两个双精度字段就行。

5.2 与空间连接、分区统计的配合打法

渔网真正的价值在于它是一个“容器”。往里面装点数据、装栅格值、装线长度,才能出结论。最常用的是空间连接:渔网作为目标要素,点数据作为连接要素,连接操作选“一对一”并勾选“保留所有目标要素”,这样没有点的格子也会保留,计数为 0。这一步很多人忘了勾,结果只得到有点的格子,做密度分析时样本就有偏了。

栅格统计走的是分区统计工具,渔网面作为分区数据,栅格作为值栅格,输出一张表,每个格子一行,包含均值、最大值、标准差这些。这里有个性能细节:渔网格子数上万之后,分区统计会明显变慢,我的做法是先把渔网转成栅格(要素转栅格,像元大小设成格子的边长),用栅格做分区统计,速度快一个量级,代价是边界会有半个像元的误差。精度要求高的项目还是老老实实用面。

还有一种玩法是用渔网做样方抽样:给每个格子生成一个随机点,用这些点去提取遥感影像的值,做地面验证样本。生成随机点的工具支持在面内约束,每个格子出一到多个点,全程脚本化,比人工在图上点要可靠得多。

5.3 分幅出图的命名与地图系列衔接

用渔网做分幅底图是很成熟的做法。把渔网的 GRID_CODE 字段作为地图系列的索引字段,出图时每张图自动带页码名,文件名也用它,几百张图批量导出不用手动改名。

这里有个小经验:格网编码不要只用数字,纯数字排序在某些环境下会被当字符串处理,1、10、11、2 这样排,非常难受。用R01C01这种带行列表头的编码,排序和肉眼定位都舒服。另外,如果分幅图要拼接,格子之间记得留一点点重叠,通常给总跨度的百分之一到二,太严丝合缝的话拼接处容易出现细缝。

5.4 大体量渔网的性能控制

格网数量是绕不开的性能红线。我的经验值是这样的:几千个面,随便玩;几万个面,符号化开始有延迟,属性表滚动变卡;几十万个面,地图操作明显迟滞,建议关掉标注、简化符号;上百万个面,基本就别用矢量了,转成栅格或者先分区再分块处理。

如果业务确实需要超密格网,我会先用渔网生成分块索引(每个分块几百个格子),再逐块生成细格网,最后按需合并。这样每次操作的数据量可控,出问题也容易定位到具体块。另外,生成完成后立刻建立空间索引,对后续的空间查询和连接速度提升非常明显。

注意:不要在渔网上开要素标注,尤其是把 GRID_CODE 标在每个格子上。几千个格子就会让重绘慢到怀疑人生,需要标注时临时打开、出图前再关掉。

6. 几个我踩过的坑,写下来省你时间

第一个坑是默认地理数据库。ArcGIS 默认把工具输出丢到工程自带的 .gdb 里,那个库的坐标系往往不是你想要的,生成完一堆渔网混在里头,找都找不着。我的做法是在每个项目开始时先建一个专用文件地理数据库,明确设好投影坐标系,所有中间成果都往里面放,路径固定、单位固定,出问题的概率直线下降。

第二个坑是“重跑覆盖”。工具的输出路径如果已经存在同名要素类,有的版本会直接报错,有的会静默追加或覆盖,行为不完全一致。所以脚本里我习惯在生成前先判断并删除,或者给输出名加时间戳,避免拿到一份“上一次的残骸”还以为是新的。

第三个坑是范围参数的取整方向。行列数向下取整会盖不满研究区,向上取整会溢出边界,两种都有隐患。我的处理是向上取整保证全覆盖,然后用研究区边界做一次裁剪,把溢出部分切掉。裁剪之后再重新算面积,别直接拿 Shape_Area 去汇总,会虚高。

第四个坑跟显示有关:如果你在三维场景里打开渔网,默认的拉伸和基底高度设置会让它浮在空中或者埋到地下,看着就像“丢了”。切回二维地图看一眼,问题立刻清楚。这个坑不常见但很折磨人,尤其是刚接触三维视图的时候。

最后一个体会是关于工具选择的。这些年我带过不少新人,发现“渔网不见了”这个问题里,真正因为参数填错导致失败的比例其实不到三成,剩下七成全是显示、坐标系、图层添加这类“非数据问题”。所以遇到空白,先别急着重跑工具,花三十秒做三件事:查图层在不在、缩放至图层、看空间参考。这三步能解决绝大部分困扰,比反复点运行有效得多。真要重跑,也先把上一次的输出找出来看一眼要素数量和坐标系,别在同一个坑里摔两次。

返回列表