☰
广东省市县三级GIS底图SHP数据:坐标系、投影与清洗避坑指南
2026/10/13 3:27:28 网站建设 项目流程

简介:SHP格式的广东省地理信息数据包,面向GIS初学者、规划人员与交通研究者,包含省、市、县三级行政区划边界及道路网、铁路网矢量要素,可直接用于地图制图、空间查询和交通网络分析。压缩包共33个文件,以shp几何文件为核心,配合dbf属性表、prj投影文件、shx空间索引等类型,其中shp存储边界与线网几何,dbf记录行政名称、道路等级、铁路里程等信息,prj确保所有数据统一在WGS84或国家2000坐标系下叠加使用。资源大小68.6MB,已有2201人学习下载。数据按省级、市级、县级、道路、铁路五个专题单独组织,层级清楚、相互独立,可灵活组合,便于开展行政区划与路网的叠加分析、缓冲区计算、通勤路径模拟、人口密度评估等典型GIS场景,也适合为城市规划、交通管理、物流选址及应急疏散研究提供基础底图,能显著节省数据采集与格式转换时间。

1. 一份能直接落地的广东 GIS 底图:省、市、县三级边界加路网,省下至少两周找数据的时间

做 GIS 的人都有一个共识:真正咬人的不是算法模型,而是找底图和洗数据。最近我拆了一份广东省行政区划相关的 SHP 数据包,时点是 2022 年 7 月,里面包含了省、市、县三级行政区划边界,以及道路网和公路网两套线图层。也就是说,做区域分析时常见的底图需求,这份数据基本一步到位,拖进 QGIS 就能开工。适合三类人:做区域经济分析、选址评估的从业者,需要行政边界做数据可视化的前端开发者,以及高校里正在做 GIS 课程项目的同学。下面把拆包过程、参数细节和踩坑记录完整列出来,帮你少走弯路。

2. 拆开 SHP 文件:弄清数据包里到底装了什么再动手

2.1 一个 SHP 不是“一个文件”:.shp/.dbf/.shx/.prj 各管什么

很多新手第一次拿到 shapefile 时,习惯把 .shp 后缀的文件拖进软件就完事,其他同名文件一概不管。这个习惯容易埋雷。一个完整的 shapefile 实际上是一个文件组,至少由四个文件组成,缺一个都可能让图层打不开或者属性丢失。

扩展名作用缺失时的影响
.shp存储几何坐标信息无法渲染图形
.dbf存储属性表内容字段和属性全部丢失
.shx几何索引部分 GIS 软件无法打开
.prj坐标系描述坐标系被识别为未知

解压这份数据包后,你会看到每个图层都对应一组同名但不同扩展名的文件,这是 shapefile 的正常形态,千万不要随手删掉其中某一个。若发现某个图层只有 .shp 没有 .dbf,说明文件在拷贝、压缩或传输环节出了问题,需要重新拿完整版本。我在 Windows 上习惯先打开“显示文件扩展名”再检查,这样每个文件缺不缺一目了然。

2.2 图层逻辑:三级行政区划与两套路网的搭配关系

这份数据包的分层逻辑很直白:省边界是全省域轮廓,市边界是 21 个地级市的行政区划面,县边界再往下细化到县级行政单位。三层是包含关系,做聚合分析时可以从县界上卷到市界,用空间连接或按行政区代码归并都行,不需要另外算几何关系。

路网部分值得留意。标题里写着“道路网+公路网”,一般这种区分是:道路网是相对完整的道路线层,包含高等级和低等级道路,适合做全域路网密度分析;公路网则偏重国省干线和高速公路,适合做干线通达性研究。实际使用时,先按图层名字区分,再打开属性表看一眼字段里的道路等级分类,确认哪一层更贴合你的业务需求。另外,包里没有单独的铁路线图层,如果你需要铁路网参与分析,得再叠加一份铁路矢量数据。这份数据解决的是底图和大路网问题,更细的 POI、水系、铁路都要另行补充。

2.3 用 Python 快速盘点图层、字段与坐标系

拿到数据包以后,我习惯先用 Python 快速过一遍所有图层,确认文件完整性、字段结构和坐标系,避免“以为能打开、实际错位”的局面。下面这段代码递归扫描目录内所有 .shp 文件并打印关键信息。

import geopandas as gpd from pathlib import Path shp_root = Path("./guangdong_shp_202207") for shp in shp_root.rglob("*.shp"): gdf = gpd.read_file(shp, encoding="utf-8") print("图层:", shp.name) print("要素数:", len(gdf)) print("字段:", list(gdf.columns)) print("坐标系:", gdf.crs) print("几何类型:", gdf.geom_type.unique()) print("-" * 50)

这段代码的逻辑很简单:rglob 递归找出所有 .shp 后缀文件,geopandas 逐个读取后打印要素数量、字段列表、坐标系和几何类型。关键是 encoding 参数,早期测绘数据多用 GBK 编码,如果 dbf 是 GBK 而这里写 utf-8,字段名会变乱码;遇到乱码时改成 encoding="gbk" 重新读即可。gdf.crs 输出的结果要重点看,出现 EPSG:4326 表示 WGS84 经纬度,出现 EPSG:4490 表示 CGCS2000 经纬度,两者在省域尺度上差别不大,但如果出现 GCJ-02 相关描述,就需要警惕坐标偏移问题,下一章专门展开。

3. 坐标系与投影:数据能不能叠得准,就看这一步

3.1 WGS84、CGCS2000 与 GCJ-02:三种常用坐标系的差别

数据能不能和业务数据精确叠加,坐标系是第一道门槛。最常见的 WGS84 是 GPS 原始坐标系,全球通用;CGCS2000 是国家大地坐标系,国内测绘成果经常使用。这两者在省域范围内坐标值差异很小,日常可视化几乎看不出区别。GCJ-02 则不同,它把 WGS84 坐标做了非线性偏移,主要用在互联网地图相关产品。如果你从在线地图导出坐标或路径数据,再直接和这份 SHP 底图叠加,常见的现象是整个图层错开几十米甚至上百米,放大到街道级别非常明显。判断方法也简单:看 .prj 文件里写的是 EPSG:4326 / EPSG:4490 还是类似“GCJ-02”的字样;如果你的业务数据来源是互联网地图,先确认目标坐标系再往下做,不要急着画图。

3.2 QGIS / ArcGIS 中检查 CRS 并统一重投影的操作

在 QGIS 中加载 shp 后,右键图层选“属性”,在“信息”面板里找“坐标系”一栏。如果显示未知或 未知CRS,说明 .prj 缺失或内容有问题。正确的处理方式是右键图层,选择“导出” → “要素另存为”,在 CRS 下拉框里指定目标坐标系,导出新文件后再继续分析。注意“图层 CRS”和“项目 CRS”是两回事,项目开启实时投影能让两个不同坐标系的图层在视觉上对齐,但导出数据时仍会保留各自原有坐标系,视觉对齐不等于数据真正统一。

ArcGIS 里操作类似:右键图层 → Properties → Source,查看“Geographic Coordinate System”或“Projected Coordinate System”。如果坐标系显示为空,用 ArcToolbox 里的“Define Projection”工具定义,而不是用“Project”工具。这两个工具经常被搞混——Define Projection 只是标记坐标系,不改变坐标值;Project 才是真正做坐标转换。定错工具,后续所有操作都会在错误坐标系下进行。

3.3 面积与长度统计:为什么必须切到投影坐标系

直接用经纬度坐标计算面积,单位是“平方度”,长度单位是“度”,完全没有物理意义。我一般会先把数据重投影到适合的投影坐标系,再计算面积和长度。以县级边界的面积统计为例:

import geopandas as gpd county = gpd.read_file("county.shp", encoding="utf-8") county_prj = county.to_crs("EPSG:XXXX") # 替换成你在 QGIS 里选好的投影坐标系 county_prj["area_km2"] = county_prj.geometry.area / 1_000_000

这里 EPSG:XXXX 是占位符,需要替换成实际的投影坐标系。我在 QGIS 里处理广东省数据时,常用 Asia North Albers Equal Area Conic 做面积统计,省域范围变形小;如果源数据是 CGCS2000,也可以换 CGCS2000 / 3-degree Gauss-Kruger CM 114E,两种都能得到以平方米为单位的面积值。投影选择没有唯一答案,核心原则是:算面积用等积投影,算短距离或做网络分析用等距投影或高斯投影。道路图层做长度统计同理,把 geometry.length 除以 1000 得到公里数。每次重投影后,建议先用测量工具量一下已知长度的县界,验证数值是否在合理范围内,比如一条县界量出来是几百公里,如果显示 0.2 这类数字,说明坐标系还是经纬度,需要重新检查投影设置。

4. 数据清洗与字段处理:从“能打开”到“能用”的必经之路

4.1 dbf 字符集识别与乱码处理

属性表中文乱码是拿到第三方数据最常遇到的问题。现象是字段名变成“锟斤拷”或“娑撴”之类的符号,本质原因是 dbf 文件的字符集与软件默认字符集不匹配。早期数据多用 GBK,现代数据多采用 UTF-8,QGIS 默认按 UTF-8 读取,所以遇到旧数据极易乱码。解决办法是在 QGIS 加载 shp 时注意出现的“图层编码”选项,GBK 选 GB18030 或 GBK,UTF-8 选 UTF-8。如果已经加载进去了,右键图层 → “图层属性” → “源” → “编码”,重新选择后刷新即可。Python 处理时只需要改一个参数:

import geopandas as gpd # 尝试 UTF-8 读取,乱码则切换为 gbk gdf = gpd.read_file("county.shp", encoding="utf-8") # gdf = gpd.read_file("county.shp", encoding="gbk")

这条代码说明一个习惯:先用 UTF-8 读取,字段出现乱码后立刻改成 gbk,两次读取对比字段名是否可读。字符集问题一旦解决,后续属性连接、分类统计才会稳定。

4.2 拓扑检查:缝隙、重叠、悬挂点

面状行政区划数据最常见的拓扑错误有三种:相邻面之间有缝隙、相邻面之间重叠、边界线上有悬挂点。省、市、县三级边界如果来自不同比例尺的数据源,放大后经常能看到县界之间出现细小白边。在 QGIS 中处理这套数据时,我用 Topology Checker 插件做快速检查。打开“处理工具箱”搜索 Topology Checker,添加面图层后选择规则“must not have gaps”和“must not have overlaps”,点击检查后结果窗口会列出错误位置,双击可以跳转到对应要素。修复时手动编辑太费劲,我会用 GRASS 的 v.clean 工具,设置 snap 容差把相邻节点吸附到一起,注意容差单位与投影坐标系一致,设置过大会把周边要素吸变形。

4.3 属性表连接:把统计年鉴数据挂到县界图层上

行政区划边界本身没有太多业务属性,做分析时通常要把统计年鉴数据连接进来。县级边界一般自带行政区划代码字段,这是最稳定的连接键,因为行政区划代码在全国范围内唯一。用名称连接时先确认两边字符集一致,否则连接结果大量为 NULL。QGIS 的操作路径是:右键县界图层 → “属性” → “连接” → “新建连接”,源选统计表格,连接字段选县名或行政区划代码,目标字段选图层里对应的字段。用 Python 做连接更灵活:

import pandas as pd import geopandas as gpd county = gpd.read_file("county.shp", encoding="utf-8") stats = pd.read_excel("annual_stats.xlsx", dtype={"行政代码": str}) # 统一代码类型后再连接 county["行政区划代码"] = county["行政区划代码"].astype(str) merged = county.merge(stats, left_on="行政区划代码", right_on="行政代码", how="left") # 检查未匹配到的行 print(merged[merged["目标字段"].isna()][["行政区划代码"]])

这段代码的关键点有两个:一是把两边的行政区划代码都转成字符串类型,避免数字位数不同导致匹配失败;二是连接后必须检查 NULL 值,常见原因是代码字段里混入了多余空格或年份不同的代码位数不一致。合并完成后另存为新的 shp 文件,后续分析直接基于新文件做,避免反复重连。

5. 避坑指南:用这份 SHP 做分析时最容易翻车的五个细节

5.1 现象:路网线和行政边界之间总有细小缝隙

做空间连接时,部分道路线段明明在某个县界范围内,却因为端点距离边界线几米而被判定为不在此县内。原因是道路图层和行政区划图层来自不同精度的原始数据,制图综合阶段留下的误差。解决办法是在空间连接前对道路图层先做小范围缓冲。如果数据已经转成投影坐标系,缓冲 50 米通常足够;如果仍在经纬度坐标系下,buffer(0.005) 可能会产生约 500 米的偏差,必须先重投影再缓冲。

5.2 现象:属性表里的数值字段无法参与计算

字段看起来是数字,但求和、平均时全部报错。原因多半是 dbf 文件中该字段被定义为字符型,或者读取时被自动识别为文本。用 QGIS 字段计算器新建一个字段,函数输入 to_real("原字段"),即可得到可计算的数值字段。用 Python 处理更直接:

county["area_km2"] = county["area_km2"].astype(float)

养成拿到新图层就检查 dtypes 的习惯,把所有应有数值型的字段统一转成 float,能省掉后续一堆麻烦。

5.3 现象:放大看县界之间有一圈白色缝隙

相邻两个县的面边界没有共用一条边,而是在中间留下细长空隙。原因是原始数据做数字化时没有做拓扑编辑,两个面各自独立描绘边界。在 QGIS 里打开 Topology Checker,规则选“must not have gaps”,检查结果会标出所有缝隙位置。修复方式推荐用 v.clean 的 snap 参数设置容差,把相邻面的边界节点吸附对齐。注意容差设置要克制,过大会把县界形状拉变形,导致面积统计失真。

5.4 现象:解压或传输后图层打不开

部分 GIS 软件提示文件损坏或索引缺失。最常见的情况是拷贝过程中只复制了 .shp 和 .dbf,忽略了 .shx 索引文件。shp 文件缺失索引后,某些软件能打开但大量操作报错。最省事的修复方案是用 Python 重新写出一个完整文件组:

import geopandas as gpd gdf = gpd.read_file("county.shp") gdf.to_file("county_fixed.shp", encoding="utf-8")

这段代码会把原始数据重新完整输出一份,自动生成配套的 .shx、.dbf、.prj 文件。注意输出时再次指定 encoding,保证属性表中文字符集不出错。

5.5 现象:叠加在线地图时整体偏移几十米

SHP 底图和在线瓦片地图叠加不上,整体错位明显。原因是部分在线地图服务使用 GCJ-02 坐标系,而 SHP 底图是 WGS84 或 CGCS2000。定位偏移在省域尺度看起来只差一个图层边缘,放大到道路交叉口就会影响落点判断。解决思路是先把 SHP 数据转换到目标平台坐标系,再叠加使用。转换时注意区分 WGS84、GCJ-02、BD09 三种坐标系,互转不是简单加偏移量,需要做对应转换处理。上线前先找一个地标点验证坐标偏差,确认无偏移后再批量转换。

6. 进阶用法:行政区划与路网组合分析的三个实用技巧

6.1 技巧一:按县统计路网里程与密度

县域路网密度是区域分析常用指标。先把县界和道路都重投影到同一投影坐标系,再用空间连接把道路归属到县,最后按县聚合里程并计算密度。

road_prj = road.to_crs(projected_crs) county_prj = county.to_crs(projected_crs) joined = gpd.sjoin(road_prj, county_prj, how="inner", op="intersects") dist_len = joined.groupby("district_id")["length_km"].sum()

注意 geopandas 不同版本对空间连接参数写法有差异,旧版用 op="intersects",新版用 predicate="intersects",遇到版本报错时检查一下这个参数。密度计算用总里程除以县面积,单位统一为千米每平方千米。

6.2 技巧二:用 ogr2ogr 做轻量级 Web 可视化

SHP 文件直接扔到前端加载会卡顿,先转成 GeoJSON 并做抽稀能明显提升加载速度。

ogr2ogr -f GeoJSON county_web.geojson county.shp -t_srs EPSG:4326 -simplify 0.001

simplify 参数按经纬度单位抽稀,0.001 约等于百米级简化,适合省域范围展示。出精细图时不要加这个参数,抽稀会轻微改变边界形状。

6.3 技巧三:分级符号化出图

在 QGIS 中用“分类”渲染按道路等级字段给公路网做三类样式,高速公路用深橙色粗线,国道用浅橙色中等线宽,县乡道用灰色细线。底图县界用极浅填充,只保留细边界线,这样一张图能同时看出路网骨架和密度差异。

这套数据我已经整理好放在下载页,压缩包里就是完整的 SHP 文件组。拿到手先按第 3 章检查坐标系,再按第 5 章过一遍校验,能省掉过去小半天的准备工作。从那以后,我每次拿到新的 shp 数据包,都强制自己先查 CRS、再看字段类型、最后跑一轮拓扑检查,这已经是习惯了。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询