简介:这套一千一百万基础地理数据库收录了二〇一七年全国县级行政区的矢量边界,面向GIS数据分析师、城乡规划与科研工作者,用于区域统计、空间制图和辅助决策。数据采用一比一百万比例尺,配合中国大地坐标系统二〇〇〇与WGS一九八四结合的坐标系,县名、行政区代码等属性字段完整,可叠加人口、地形、气象等多源数据进行综合研判。压缩包内共七个文件,核心SHP矢量文件对应几何边界,配套DBF属性表存储县名代码,PRJ文件定义投影,SBN、SBX、SHX索引文件加速几何检索,XML元数据记录来源信息,整体体积约四十六点三三兆字节。目前已有六百一十四人学习下载。借助这份数据,使用者可直接获取规范化的全国县级面状图层,免去自行数字化与格式转换的繁琐环节,将其作为专题制图、区域对比、空间查询和可视化分析的基础底图,也能结合人口密度、地形气候等数据做叠加分析,显著提升地理信息项目的启动效率。
1. 1100万基础地理数据库加载前,先把2017县级行政区shp文件的门道摸清
做空间分析的人都会经历一个阶段:手里的数据越多,越觉得边界底图难得。这套1100万基础地理数据库,点与兴趣点记录达到千万级,真正让它们产生区域价值的,是配套的2017县级行政区shp文件——一张全国县级行政边界矢量图,回答“这条记录落在哪个县”。这篇笔记把资源拆到可复现:文件族结构、坐标系选择、属性表字段含义,以及与千万级点数据的空间关联操作全部覆盖。新手能从零走通,熟手可以直接跳到参数和踩坑段落。
2. 县级行政区shp的构成与坐标系:加载前先分清三件事
2.1 一个shp是一组文件而不是单个文件
先谈格式本身。Shapefile 从上世纪 90 年代沿用至今,仍然是行业默认的矢量交换格式,几乎所有主流 GIS 软件都能读写。很多人在第一次解压时都会以为,只要里面有一个后缀为 .shp 的就是完整数据。实际上这是一个文件集合,至少由 .shp、.shx、.dbf 三个主体文件组成,扩展一下还包括 .prj、.cpg、.sbn/.sbx。我拆 shp 时,第一件事永远是清点文件族,缺了哪个都好判断。
拿这套 2017 县级行政区数据来说,解压后应该能看到完整的文件组。常见结构如下:
| 文件后缀 | 作用 | 缺失时的表现 |
|---|---|---|
| .shp | 几何坐标主体,存放每个面要素的坐标串 | 无法打开 |
| .shx | 几何索引,帮助软件定位要素位置 | 部分软件拒绝加载 |
| .dbf | 属性表,存放县名、行政代码等字段 | 打开后无属性表 |
| .prj | 坐标系描述,写明 EPSG 或投影参数 | 坐标系被当作未知 |
| .cpg | 声明 .dbf 字符编码(GBK 或 UTF-8) | 中文名称可能乱码 |
| .sbn/.sbx | 空间索引,可选 | 一般不影响加载 |
常见的错误是只把 .shp 文件复制到其他目录,剩下几个留在原文件夹。QGIS 打开这种残缺文件时,通常还能画出几个面,但一打开属性表就彻底空白,或者在启动时报加载失败。所以拿到资源后先整个文件夹原样解压,再拖目录里的 .shp 文件,让路径里保留旁边的 .dbf 和 .prj。
面要素数量也是快速判断数据完整度的指标。全国县级行政区划数量在 2017 年前后大约是 2900 多个,如果你看到的面数远远少于这个数,要么是 zip 里只有部分区域,要么是属性表被分离了。下一步在 QGIS 的属性表里数一数行数,如果和几何要素数对不上,就要留意是否加载到了残缺文件。这里有个操作习惯:我从来不直接双击 .shp,因为系统默认打开程序看不出坐标系和属性,文件是否完整也无从判断。
2.2 坐标系怎么选:WGS84、CGCS2000与投影坐标系的差异
县级 shp 文件的价值藏在 .prj 里。同一套边界几何,坐标系不对,叠加结果可能偏到千里之外。国内流通的基础地理数据常见三种坐标系:WGS84 地理坐标系(EPSG:4326)、CGCS2000 地理坐标系(EPSG:4490),以及基于 CGCS2000 的高斯-克吕格投影坐标系。三者本身的差异在地球尺度上很小,但分析和制图时的体验完全不同。
先看 .prj 的内容。用文本编辑器打开这份数据的 .prj,如果看到GEOGCS["WGS_84"就是 WGS84;看到GEOGCS["China_2000"就是 CGCS2000;如果看到PROJCS开头,后面带带号描述,则是投影坐标系。
三条选择路径:
| 应用场景 | 建议坐标系 | 说明 |
|---|---|---|
| 叠加GPS经纬度点 | EPSG:4326 | 点数据多为WGS84,直接用最省事 |
| 对接自然资源业务数据 | EPSG:4490 | CGCS2000与国内测绘成果一致 |
| 计算面积、密度、邻接关系 | CGCS2000投影带 | 需要用平面坐标量算 |
| 输出到Web地图 | EPSG:3857 | 与前端瓦片底图一致 |
我的习惯是:先统一到 EPSG:4326 做叠加,因为绝大多数点数据集都是经纬度给出的;等到计算面积和密度时再临时转投影坐标系。注意一个坑,地理坐标系的单位是度,直接拿 geometry.area 算出来的“面积”是平方度,完全没有物理意义。要做面积量算,必须先用投影坐标系去算。
检查坐标系的方法在 QGIS 里很直接:右键图层,打开“属性”->“信息”,在坐标系那一行就能看到 EPSG 编号。在 Python 里用 GeoPandas 则是print(gdf.crs)。如果显示 None 或 unknown,千万别硬着头皮往下做,先手动指定。后面第五章会专门讲这层错位怎么排。
2.3 属性表的三板斧:县名、行政代码与常用字段
县级行政区 shp 的属性表字段设计通常非常稳定。常见字段有县名(NAME)、省份(PROVINCE)、地市(CITY)、行政代码(ADCODE 或 PAC 开头),面积字段(AREA)要看数据源是否计算过。行政代码这个字段是全表最重要的关联键。中国县级行政区划代码是 6 位数字,前两位表示省份,后四位在省内连续编号,即使县城改名了代码一般会跟着调整,所以做关联前一定要确认两边的代码版本对齐。
这里要注意 DBF 格式的字段名限制。dBASE 的字段名最长只有 10 个字节,早期数据常出现缩写,比如 ADCODE99、COUNTY_NA。用表格软件直接打开 DBF 时,长字段名还会被截断,比如 PROVINCE 会变成 PROVINC,这会导致后续合并出错。所以检查属性表要用专业的 GIS 工具,或者用 Python 的 pandas 读取后再处理。
另一个关键点是行政代码的取值类型。数据库里可能存成整数,shp 属性表里也可能存成字符串。连接时一边 int 一边 str,最终结果往往全是 NaN。我在处理这种跨界资源时,第一次就把代码统一成字符串再补零:比如 110101 这样的代码,如果有的县被存成了 11010,就必须astype(str).str.zfill(6)补齐。
3. 用QGIS和GeoPandas处理底图:加载、重投影与拓扑自检
3.1 QGIS加载与第一道检查
打开 QGIS 主界面后,直接把解压好的文件夹拖进图层区域。QGIS 会自动识别 .shp 并加载出一个面图层。右键点击图层名,选“属性”->“信息”,第一行先看要素类型是不是面,再看坐标系是不是有明确的 EPSG 编号。如果显示“未知的 CRS”,说明 .prj 缺失或损坏——这个问题的处理放到第五章细说。
之后按 F6 打开属性表,确认行数和预期的县级数量对得上。选中任意一行,地图上会高亮对应面,双击面还能直接看属性字段值。我一般随机抽三四个县,把名字和行政代码对照自己熟悉的地方,确认没有乱码或错位。检查通过后,顺手做一次符号化:选中图层,在“符号”里选个区分度高的颜色,再开“标注”显示县名,确认边界整体分布合理,没有挤成一团或大面积空白。
QGIS 在这一步还肩负另一个任务:判断编码。如果属性表里中文全是乱码,多半是 dbf 采用 GBK 编码而 QGIS 默认按 UTF-8 解析。这时候右键图层->“属性”->“数据源”,在“编码”处改成 GBK 或 GB18030,重新加载后应该就正常了。这个编码设置可以保存进工程文件,不用每次重开都重新配。
3.2 用GeoPandas做批量预处理:字段筛选、去重与统一坐标系
GeoPandas 是做矢量批量处理的标配工具,在 Jupyter 或者脚本里完成重投影、字段整理、去重,下面每一段都有实际用途。
import geopandas as gpd # 读取县级shp,编码按实际情况调整为 'utf-8' 或 'gbk' gdf = gpd.read_file("2017_county.shp", encoding="utf-8") # 查看当前坐标系,如果是 'None' 一定要停下来 print("原始坐标系:", gdf.crs) # 统一转为 WGS84 地理坐标系,方便与经纬度点数据对齐 gdf = gdf.to_crs(epsg=4326) print("转换后坐标系:", gdf.crs) print("面要素数量:", len(gdf)) # 选择核心字段,注意行政代码格式统一为6位字符串 gdf["ADCODE"] = gdf["ADCODE"].astype(str).str.zfill(6) gdf = gdf[["ADCODE", "NAME", "PROVINCE", "CITY", "geometry"]] # 按行政代码去重,防止个别区域重复录入 gdf.drop_duplicates(subset="ADCODE", keep="first", inplace=True) print("去重后数量:", len(gdf)) # 另存为新shp,编码用utf-8并自动写入cpg gdf.to_file("county_clean.shp", encoding="utf-8")逻辑说明:read_file的encoding参数控制的是 dbf 属性表解析编码,utf-8不行就换gbk;gdf.crs如果返回的是 None,说明 .prj 信息缺失,不要接着做to_crs,否则坐标会被当成无投影数据直接覆盖。astype(str).str.zfill(6)是把整数类型的行政区划代码补齐成 6 位字符串,这是所有后续关联不出歧义的前提。drop_duplicates(subset="ADCODE")用代码做唯一键,比用县名可靠得多,因为名字可能重复或带有历史别名。
to_file输出编码建议写 utf-8。但要注意,旧版桌面 GIS 软件对 UTF-8 shp 的兼容性一般,识别不到会直接乱码。如果你还需要把文件交给用旧版软件的人,保留一份encoding="gbk"的版本是更稳的选择。我自己的习惯是输出两个版本:一个 UTF-8 给自己用,一个 GBK 给合作方,省得到时候背锅。
3.3 面要素拓扑自检:重叠、缝隙与无效几何
行政区边界在制作过程中最难避免的问题是拓扑不一致。相邻两个县的面应该是无缝贴合、不重叠的,但原始数据由不同时期测绘拼接,往往会出现微小缝隙、重叠带、甚至自相交多边形。这些看着不起眼的瑕疵,会直接污染后续空间连接的统计结果,比如一个点位同时落入两个县的范围内。
检测方法可以用 Shapely 的校验函数,直接对 geometry 做检查:
from shapely.validation import explain_validity invalid = gdf[~gdf.geometry.is_valid] print("无效几何数量:", len(invalid)) if len(invalid): for idx, geom in invalid.geometry.items(): print(idx, explain_validity(geom))~gdf.geometry.is_valid返回布尔序列,True 表示这个几何在 OGC 规则下无效,后面explain_validity会告诉你具体原因,比如 Self-intersection 就是自相交。这种问题通常处理方式是给所有面做一层零缓冲,即buffer(0),它能消除多数自相交情况,同时不改变边界轮廓。我在每次拿到新 shp 做空间分析时都会先跑一遍buffer(0),这属于有百利而无一害的保险动作。
再检查重叠和缝隙。最简单直观的办法是拿同一图层做一次 overlay(intersection),把相交部分提出来,视觉上就能看出哪些边界在打架。之后对提取出的重叠区域做面积求和,如果总面积超过一个合理阈值,就说明两个县的面有大面积重叠,必须先修正再继续。缝隙的判断则需要看所有面的并集与外边界框的差,这部分用代码写也不复杂,但在 QGIS 里直接用“矢量->地理处理->检查几何”更省事,把规则选成“无重叠”和“无缝隙”跑一遍即可。
关于 buffer(0) 对精度的影响,县级尺度下几乎可以忽略,但如果你在 1:500 的大比例尺场景做规划图,就别偷懒,需要回到原始勘界成果去修正拓扑。大多数数据分析和制图场景里,buffer(0) 配合去重已经足够让数据达到可用状态。
4. 1100万点数据的空间归属:如何把每条记录关联到县级行政区
4.1 点数据的读取与清洗:先过滤再建几何
1100 万条记录,这是很多人的笔记本内存直接触碰天花板的数量级。如果一上来就用 pandas 的 read_csv 全量读入,再用 GeoPandas 逐行构造点,即使 16G 内存也容易撑爆。所以第一步要拆着读。下面这段代码按块读取,每块 10 万行,把缺失坐标的行丢掉,再把坐标范围之外的点过滤掉,最后合并成一个干净的 DataFrame。
import pandas as pd chunks = pd.read_csv("base_data.csv", chunksize=100000, usecols=["lng", "lat", "category", "business"]) filtered_list = [] for chunk in chunks: chunk.dropna(subset=["lng", "lat"], inplace=True) mask = (chunk["lng"] >= 73) & (chunk["lng"] <= 136) & \ (chunk["lat"] >= 18) & (chunk["lat"] <= 54) filtered_list.append(chunk[mask]) df = pd.concat(filtered_list, ignore_index=True) print("有效记录数:", len(df)) print("字段列表:", df.columns.tolist())chunksize决定了每次进入内存的行数,100000 是比较温和的数值,硬盘慢的机器可以降到 50000。usecols只读取需要的列,别把几十个无关字段全拖进来,这是减少内存开销最有效的一招。坐标范围的上下限 73、136、18、54 覆盖了全国范围,能把明显的脏数据挡在外面。
这里要提一个容易被忽视的边界问题:“有效坐标”不等于“有效业务数据”。很多点数据里 lng 和 lat 都是 0,或者集中在某个坐标点,比如 0,0 这样的默认值,在地图上看就是西南角一个靶心。处理这种脏数据常见做法是,在过滤之后加一行df = df[(df["lng"] != 0) & (df["lat"] != 0)]。另外提醒,如果点位数据的坐标系跟 shp 不一致,坐标过滤做得再严格也白搭,这一步的检查放到第五章排查部分细说。
4.2 空间连接:用 sjoin 算出每条记录落在哪个县
把点数据转换成 GeoDataFrame 并执行空间连接,是整个流程里最核心的一步。下面这段代码里的predicate="within"是控制在面之内的点才算匹配的关键参数。
import geopandas as gpd from shapely.geometry import Point # 用坐标构造几何对象 geometry = [Point(x, y) for x, y in zip(df["lng"], df["lat"])] gdf_pts = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326") # 读取上一步预处理好的县级边界 county_gdf = gpd.read_file("county_clean.shp", encoding="utf-8").to_crs("EPSG:4326") # 空间连接:左连接保留全部点,行数不会少 joined = gpd.sjoin(gdf_pts, county_gdf, how="left", predicate="within") print("连接后行数:", len(joined)) print(joined.head(3))这里how="left"会保留左侧点数据的全部行,没有被任何面匹配到的点会在行政区字段上出现 NaN,这些点的数量就是边界外或数据异常的点数。predicate="within"是几何关系判定的关键。如果用intersects,一个点恰好在两个县边界上,会同时匹配到多个县,产生重复行,统计时就会把点算两次。而within要严格得多,点落在边界线上时,相邻面哪个都不算匹配,宁可让它落到 NaN,也不要重复。
空间索引在这里会自动构建,GeoPandas 的 sjoin 内部会对右侧的县级面数据建立 R-tree 索引,所以即使左侧有 1100 万点,也不是逐个遍历所有面。但要注意一个性能陷阱:如果你把点数据先存成了 GeoDataFrame,再反复做 sjoin,每次构建几何对象的内存开销都很高。建议一次构建,一次连接,不要做多次尝试。如果内存仍吃紧,就把点数据按经度切成四个片区,分开做 sjoin,最后再 pd.concat,肉眼可见地平滑很多。
4.3 按县聚合与结果导出:从百万点变成一张统计表
连接完成后,下一步是把 1100 万个点压缩成每个县一行,得到“哪个县有多少点”的统计结果。聚合的依据是连接后表里的行政代码字段,这个字段在空间连接时从县级边界表带进来了,一般是 ADCODE。
# 按县代码统计点数 count_stats = joined.groupby("ADCODE").size().reset_index(name="point_count") # 与县级边界合并,保留所有县 county_result = county_gdf.merge(count_stats, on="ADCODE", how="left") # 没有匹配的县填0,而不是NaN county_result["point_count"] = county_result["point_count"].fillna(0).astype(int) # 如果要算密度,先转投影坐标系再算面积 county_utm = county_result.to_crs(epsg=3857) county_result["density"] = county_result["point_count"] / county_utm.geometry.area # 输出shp和GeoJSON两种格式 county_result.to_file("county_stats_2017.shp", encoding="utf-8") county_result.to_file("county_stats_2017.geojson", driver="GeoJSON")groupby("ADCODE").size()统计的是每个代码出现的次数,恰好等于落点数量。合并时用how="left"保证所有县面都保留在结果里,即使有些县一个点都没有。fillna(0)把 NaN 改成 0,这样渲染时不会因为缺值而出现空白。密度计算要先转投影坐标系,3857 的 Web 墨卡托在县级尺度做相对比较已经够用;如果追求准确,应该转 CGCS2000 的投影带。
导出方面,shp 适合继续在桌面端做分析,GeoJSON 适合直接丢给 Web 前端做可视化,一次导出两种,省得后面临时再转格式。我习惯在这个节点把结果另存一份 GeoPackage,因为它的单文件特性和空间索引读取效率都比 shp 好,后面要反复改样式时就不用反复读 dbf 了。
5. 避坑指南:编码乱码、坐标系错位与关联失败的排查实录
5.1 属性表中文显示为乱码
现象:QGIS 打开 shp 后,县名、省份等字段显示成一堆方块或者乱码,GeoPandas 读取后打印出来也是不可读字符。
原因:dbf 属性表是按 GBK 或 GB18030 编码的,但读取时没有指定编码,工具默认用了 UTF-8 解码。国内很多早期的基础数据都没有写入 .cpg 文件,程序无法自动识别。
解决:在 GeoPandas 读取时显式指定编码:
gdf = gpd.read_file("2017_county.shp", encoding="gbk")如果试 gbk 还乱码,用 gb18030 基本能全覆盖。在 QGIS 里则是图层属性 -> 数据源 -> 编码处切换。这里存一个习惯:每次处理国内 shp 时,先用encoding="utf-8"读一次,乱码就换 gbk,不要盲目试一圈。另外注意,读取成功不代表保存也成功,导出时同样要写对 encoding,否则转手给别人依然乱码。
5.2 点和边界整体错位,明明同是经纬度
现象:点数据和 shp 单独看都正常,叠加后点整体偏移几百米甚至几公里,边界外的点明显聚集在某个固定方向。
原因:数据集之间坐标系来源不同。最常见的是点数据来自互联网产品,坐标经历了 GCJ-02 加密偏转;而 shp 是基于 WGS84 或 CGCS2000 的数据,两者之间相差约几百米,且是非线性偏移。还有一种情况是两个图层坐标系代码不同,比如一个 4490 一个 4326,差别很小,肉眼几乎看不出,但投影坐标系叠加地理坐标系就会变形严重。
解决:先确认各图层的 crs。点数据的 crs 从数据制作方拿说明,如果只有经纬度没有坐标系描述,可以先按 WGS84 处理,叠加后再看偏离方向是否一致。若确认是加密坐标问题,就先把点数据做一次 GCJ-02 转 WGS84 的逆偏移,具体算法在主流地图服务商的开源文档里都有公开。如果只是 EPSG 不同,直接to_crs(epsg=4326)就可以解决。
三层检查顺序:一看 shp 的 .prj;二看点数据说明文档;三在图上取几个已知地物点对照。三层走完还没发现问题,再看坐标偏移量是否固定,固定的话就是一个可解的固定平移。
5.3 行政代码连接失败,所有县都变成 NaN
现象:用 pandas 的 merge 把点统计结果和 shp 属性按代码关联,结果目标字段全是 NaN,或者行数翻倍。
原因:字段类型或位数不一致。shp 里的 ADCODE 是整数,统计表里是字符串;或者一边是 6 位一边是 5 位。另一种情况是代码本身发生了变化,比如 2017 年的某个县在后续几年并入其他区,新版代码已经不存在。
解决:统一类型并补零是第一步:
county_gdf["ADCODE"] = county_gdf["ADCODE"].astype(str).str.zfill(6) joined["ADCODE"] = joined["ADCODE"].astype(str).str.zfill(6)如果两边都转成字符串依然有大量 NaN,拿几个具体值出来对比,看是不是代码体系差异导致。比如某些数据源用了 12 位统计用区划代码,而不是 6 位民政代码,需要截取前 6 位再做匹配。
joined["ADCODE_6"] = joined["ADCODE_12"].str.slice(0, 6)这个坑的高发点是新旧代码更替。2017 年的县级代码到现在可能已经调整过行政区划,有的改成市辖区,有的撤并成街道。遇到这种情况就以 shp 文件中的代码体系为准,把另一边的代码做映射表,别指望原始数据自动对齐。我做关联之前一定会先做一次两套代码的差集对比,代码这种主键问题越早暴露越省事。
5.4 1100万点关联时内存崩溃
现象:脚本运行到一半内存占用飙升,进程被杀或者 Jupyter 重启,甚至连系统都卡死。
原因:一次性把点数据、GeoDataFrame、多份连接结果同时放在内存里,1100 万行几何对象占的空间远大于想象。每条 shapely 几何对象除坐标外还带方法引用,开销比纯坐标数组高很多。
解决:三条路。第一,分块关联,按经度把点切成 4 到 8 片,逐片 sjoin 后聚合再合并,核心是让内存里同时存在的点数据始终在百万行级别。第二,用空间索引过滤,在 sjoin 前先用包围盒粗略筛选掉完全不可能落进县界的点。第三,如果数据落进 PostGIS 或 DuckDB 这类数据库,直接让数据库做空间连接,把压力给到数据库引擎而不是 Python 进程。实际项目里我大部分时间用第一种方案,代码改动最小,效果也最直接。
# 分片关联的简易模板 xmin, ymin, xmax, ymax = county_gdf.total_bounds half_lng = (xmin + xmax) / 2 left_part = gdf_pts[gdf_pts.geometry.x <= half_lng] right_part = gdf_pts[gdf_pts.geometry.x > half_lng] for part in (left_part, right_part): part_res = gpd.sjoin(part, county_gdf, how="left", predicate="within") # 聚合后保存中间结果,然后拼接这个模板的重点是按经度切分后,每一片都执行 sjoin,中间结果落盘,再 concat,彻底绕开一锅端的内存压力。切分线放在两个县交叉地带时,边界点可能被分到两片,但因为我们最终是按县级聚合,点归属在哪一片都不影响最后结果。
6. 统计结果如何上色:县级专题图的渲染与验证
数据整理到 county_result,离最终交付只差最后一步:把 1100 万个点压缩成的点密度画到地图上。这一步既是对前面所有工作的视觉验证,也是专题图出图的关键。不同的渲染方式会让同一份数据呈现出完全不同的结论。
先用 GeoPandas 直接画一张静态专题图:
import geopandas as gpd import matplotlib.pyplot as plt county_result = gpd.read_file("county_stats_2017.shp", encoding="utf-8") county_result["point_count"] = county_result["point_count"].fillna(0).astype(int) fig, ax = plt.subplots(figsize=(10, 8)) county_result.plot( column="point_count", cmap="YlOrRd", scheme="quantiles", legend=True, ax=ax ) ax.set_title("County-level Point Density (2017)") plt.axis("off") plt.savefig("county_density.png", dpi=300)这个代码里有两个关键参数。cmap="YlOrRd"是颜色渐变方案,从浅黄到深红,适合表达从少到密的分布;scheme="quantiles"表示用分位数分级,每一级包含相同数量的县,好处是颜色层次丰富,坏处是当大量县都是 0 点时,0 点县和低点县会被分到同一级,视觉上压扁了差异。所以我通常先看一眼 point_count 的分布,如果 0 值占比超过三成,就改scheme="equalinterval",或者干脆把 0 值单独渲染成灰色,其他县再按数值分级。如果要在 QGIS 里做交互式专题图,操作路径是:双击图层打开“图层属性”,在“符号化”选“分级”,设置字段是 point_count,模式选“分位数”或“自然间断点”,类别数量设 5 或 7。
渲染完成之后,是收尾验证。拿一个你自己熟悉县城,手工数一下原始数据里落在该县范围内的点数量,跟渲染图的统计值对比,值对得上说明整个流程是通的。再做一个总量校验:把 county_result 的 point_count 求和,和第一步清洗后的总点数比较,两者差值应该等于落在县界外的点数。任何超过 5% 的差量都说明连接逻辑或边界拓扑有问题,需要回头查。
从那以后我每次处理这类行政区关联数据,都会强制走一遍固定流程:先看 .prj 确认坐标系,再试一遍编码确认能正常读属性,最后抽一个已知县做点数量反推全库落点数。三步走完,后面做渲染和交付基本不翻车。希望帮到你。
本文还有配套的精品资源,点击获取