简介:这份资源是广东省地市级行政区域划分的Shapefile矢量数据集,面向从事GIS制图、空间分析与区域规划的研究人员、学生及从业者,可用于省级行政区划底图制作、专题图绘制及与其他地理数据的叠加分析。压缩包共7个文件,约14.67MB,包含shp、shx、dbf、prj、sbn、sbx及xml等类型:shp存储几何边界,shx与sbn、sbx提供空间索引以加速读取,dbf保存行政区名称与代码等属性,prj定义坐标系统,xml记录元数据信息,各文件协同构成完整可用的空间数据集。数据由QGIS合并县级行政区生成,覆盖广东全省地市层级,可直接在QGIS、ArcGIS等兼容SHP的软件中加载。目前已有1251人学习下载,适合需要快速获取省级区划底图、开展空间分析或制图实践的用户参考使用。
1. 广东省 SHP 格式:从哪拿、怎么用、为什么你的 GIS 流程绕不开它
做区域级空间分析的人,迟早会撞上「广东省 SHP 格式」这个检索词。场景通常很具体:要在广东做选址、做行政区划统计、做路网或水系叠加,手头却没有一份边界干净、坐标系明确、字段可用的矢量底图。有人从各种渠道下到一份 shp,打开一看要么是乱码属性表,要么是投影对不上,要么缺了珠三角某些镇街。广东省 SHP 格式说的就是广东省行政边界及其下属市、县区、镇街等层级的 Shapefile 矢量数据,它是 Esri 定义的一种经典矢量格式,由 .shp、.shx、.dbf、.prj 等一组文件共同构成。它解决的是「把广东这块地的空间范围变成可计算对象」的问题,适合做 GIS 分析、数据可视化、后端空间查询的从业者。下面按拿到数据、读懂结构、跑通流程、避开坑的顺序讲透。
2. 广东省 SHP 的层级结构与坐标系:先搞懂手里这份数据是什么
2.1 Shapefile 那组文件到底谁管什么
很多人第一次拿到广东省 SHP,看到解压出来一堆同名文件就懵。Shapefile 不是单个文件,而是一个文件族,缺一个都可能打不开或者属性丢失。常见构成如下:
| 文件后缀 | 作用 | 缺失后果 |
|---|---|---|
| .shp | 存几何图形(点线面坐标) | 直接打不开 |
| .shx | 几何索引,记录每个要素偏移 | 部分软件报错或读取异常 |
| .dbf | 属性表,存名称、代码等字段 | 只剩图形,没有属性 |
| .prj | 坐标系定义(WKT 文本) | 坐标含义不明,叠加错位 |
| .cpg | 属性表字符编码说明 | 中文属性乱码 |
| .sbn/.sbx | 空间索引(可选) | 不影响打开,只影响查询速度 |
血泪经验是:拿到广东省 SHP 后第一件事不是急着加载,而是确认这六个核心文件是否齐全,尤其是 .prj 和 .cpg。前者决定你的坐标能不能和别的图层对上,后者决定「广州市」会不会变成「骞垮窞甯」这种玄学乱码。如果只有 .shp 和 .dbf,基本可以判断这份数据被裁剪过,后续叠加分析要格外小心。
2.2 行政层级:省、市、县区、镇街不是一份数据
广东省 SHP 格式在实际使用中通常按行政层级拆成多份,而不是一个文件包打天下。常见层级和字段设计如下:
- 省级:1 个面要素,字段一般是省名、省代码(如 440000)。
- 地级市:21 个面要素(广州、深圳、佛山等),字段含市名、市代码。
- 县区:约 122 个区县,字段含区县名、区县代码、所属市。
- 镇街:约 1600 多个镇街,字段含镇街名、镇街代码、所属区县。
选哪一层取决于你的分析粒度。做全省宏观统计用省级或市级就够;做门店覆盖、网格化治理、快递分区,必须下沉到镇街。这里有个容易翻车的点:不同来源的镇街边界在珠三角城市交界处会有出入,因为镇街界线本身会随行政区划调整变化。所以如果你的分析涉及跨市对比,务必确认所有层级来自同一批次、同一时点。
2.3 坐标系:EPSG:4326 还是 EPSG:4490,别混用
广东省 SHP 最常见的两种坐标系是 WGS84 地理坐标(EPSG:4326)和 CGCS2000(EPSG:4490)。两者在广东范围内的差异很小,日常可视化几乎看不出,但做高精度量算时不能忽略。判断方法很简单,打开 .prj 文件看里面的 GEOGCS 名称,或者用代码读取。
import geopandas as gpd # 读取广东省 SHP,直接查看坐标系 gdf = gpd.read_file("guangdong_province.shp") print("坐标系:", gdf.crs) print("要素数量:", len(gdf)) print("字段列表:", list(gdf.columns)) print("几何类型:", gdf.geom_type.unique())这段代码做了四件事:读文件、打印 CRS、统计要素数、列出字段和几何类型。参数上gpd.read_file默认按 .prj 自动识别坐标系,如果 .prj 缺失,gdf.crs会返回 None,这时你必须手动指定。逻辑说明:先确认坐标系再谈分析,否则后面所有距离、面积计算都是错的。如果发现是地理坐标(单位是度),而你要算面积,必须先投影到投影坐标系,广东常用 EPSG:4527(CGCS2000 3 度带)或 UTM 49N/50N。
提示:地理坐标系下直接算面积得到的是平方度,没有物理意义。投影转换是面积量算的前置步骤,不是可选项。
3. 用 Python 跑通广东省 SHP 的读取、筛选与投影转换
3.1 环境准备与最小读取命令
工欲善其事,先把环境搭好。我一般用 conda 建独立环境,避免和系统里的 GDAL 版本打架,这是 GIS 圈最常见的翻车来源之一。
# 创建独立环境,指定 python 版本 conda create -n gis_gd python=3.11 -y conda activate gis_gd # 安装核心库,geopandas 会自动带 GDAL 依赖 conda install -c conda-forge geopandas matplotlib shapely pyproj -y逻辑说明:geopandas 依赖 GDAL、PROJ、GEOS 三个底层库,用 conda-forge 渠道安装能保证版本互相兼容。参数上-c conda-forge指定渠道,-y自动确认。如果你用 pip 装 geopandas,在 Windows 上极容易遇到 GDAL 编译问题,这是新手最常踩的坑。装完后用gpd.__version__验证,能打印版本号就说明底层库链接正常。
3.2 按属性筛选出珠三角城市
拿到全省数据后,最常见的操作是筛子集。比如只保留珠三角九市,或者排除某个市做对比分析。
import geopandas as gpd # 读取地级市层级 SHP cities = gpd.read_file("guangdong_city.shp") # 查看市名字段,确认字段名(不同数据源可能是 name / NAME / 市名) print(cities.columns.tolist()) # 按属性筛选珠三角九市 prd_names = ["广州市", "深圳市", "佛山市", "东莞市", "中山市", "珠海市", "惠州市", "江门市", "肇庆市"] prd = cities[cities["市名"].isin(prd_names)] # 导出为新的 SHP,注意指定编码避免中文乱码 prd.to_file("zhujiang_delta.shp", encoding="utf-8") print("筛选后要素数:", len(prd))逻辑说明:先用columns.tolist()确认字段名,因为不同来源的广东省 SHP 字段命名不统一,硬编码字段名是常见错误。isin做多值匹配,比循环筛选高效。参数上to_file的encoding="utf-8"很关键,不指定的话中文属性在部分软件里会乱码。导出后要素数应该是 9,如果不是,说明市名写法和你预期不一致,比如「东莞市」可能写成「东莞」。
3.3 投影转换与面积量算
筛选完只是第一步,要算每个市的面积,必须投影。
import geopandas as gpd prd = gpd.read_file("zhujiang_delta.shp") # 从地理坐标转到投影坐标,EPSG:4527 为 CGCS2000 3 度带 prd_proj = prd.to_crs(epsg=4527) # 计算面积,单位平方米,转成平方公里 prd_proj["area_km2"] = prd_proj.geometry.area / 1e6 # 按面积排序输出 result = prd_proj[["市名", "area_km2"]].sort_values("area_km2", ascending=False) print(result)逻辑说明:to_crs做坐标系转换,参数epsg=4527是投影坐标系代号。转换后geometry.area返回的才是平方米。除以 1e6 得到平方公里。这里要注意:EPSG:4527 覆盖广东部分区域,如果数据跨带,建议用 UTM 或 Albers 等面积投影。参数选择上,做面积统计优先选等面积投影,做距离分析优先选等距投影,别一套投影走天下。
注意:投影转换后不要直接覆盖原文件,保留地理坐标版本,因为很多在线地图底图用的是 EPSG:4326,叠加时还需要转回去。
4. 广东省 SHP 在 Web 地图与后端服务里的落地方式
4.1 转 GeoJSON 给前端用
Shapefile 前端不能直接吃,最常见做法是转 GeoJSON。但全省镇街级 SHP 转出来可能几十兆,直接丢给浏览器会卡。
import geopandas as gpd # 读取镇街级 SHP towns = gpd.read_file("guangdong_town.shp") # 转成地理坐标,GeoJSON 标准用 EPSG:4326 towns_wgs = towns.to_crs(epsg=4326) # 简化几何,容差 0.001 度,约 100 米,减小体积 towns_wgs["geometry"] = towns_wgs.geometry.simplify(0.001) # 导出 GeoJSON towns_wgs.to_file("guangdong_town.geojson", driver="GeoJSON")逻辑说明:simplify用 Douglas-Peucker 算法减少顶点数,容差越大越简化。参数 0.001 度在广东纬度约等于 100 米,可视化够用,但做精确空间查询不能简化。导出用driver="GeoJSON"。如果文件还是太大,可以按市拆分,前端按需加载,这是 Web 地图性能优化的常规手段。
4.2 入库 PostGIS 做空间查询
后端要做「点是否落在某镇街内」这类查询,把 SHP 导入 PostGIS 是标准方案。
# 用 ogr2ogr 把 SHP 导入 PostGIS ogr2ogr -f "PostgreSQL" \ PG:"host=localhost dbname=gis user=postgres password=yourpass" \ guangdong_town.shp \ -nln gd_town \ -lco GEOMETRY_NAME=geom \ -lco FID=gid \ -nlt MULTIPOLYGON \ -t_srs EPSG:4326逻辑说明:-nln指定目标表名,-lco设置几何字段名和主键名,-nlt强制几何类型为 MULTIPOLYGON 避免混合类型报错,-t_srs在导入时统一坐标系。参数里连接串按你实际数据库改。导入后建空间索引,否则查询会慢到怀疑人生:
-- 建空间索引,加速包含查询 CREATE INDEX idx_gd_town_geom ON gd_town USING GIST (geom); -- 查询某个坐标点落在哪个镇街 SELECT town_name, city_name FROM gd_town WHERE ST_Contains(geom, ST_SetSRID(ST_Point(113.264, 23.129), 4326));逻辑说明:GIST 索引是 PostGIS 空间查询的核心,不建索引时 ST_Contains 会全表扫描。ST_Point构造点,ST_SetSRID声明坐标系,必须和表一致才能正确匹配。这条查询返回广州某坐标所属镇街,是选址、配送分区的高频操作。
4.3 字段设计与常见数据规范
广东省 SHP 落地到业务系统时,字段设计要提前规划。常见做法是保留行政代码作为主键,名称字段只做展示。
| 字段名 | 类型 | 说明 |
|---|---|---|
| adcode | 字符串 | 行政区划代码,唯一,建议做主键 |
| name | 字符串 | 行政区名称,用于展示 |
| parent_adcode | 字符串 | 上级区划代码,用于层级关联 |
| level | 整型 | 层级标识,1 省 2 市 3 区县 4 镇街 |
| geom | 几何 | 空间字段 |
用 adcode 而不是名称做关联,是因为名称会变、会重名,代码相对稳定。这是做过多地区划数据的人共同的教训。
5. 广东省 SHP 使用中的避坑与排查清单
5.1 中文属性乱码
现象:打开 SHP 后属性表里中文显示成问号或乱码。原因:.dbf 文件的字符编码和读取端不一致,老数据常用 GBK,新数据多用 UTF-8,而 .cpg 文件缺失或写错。解决:先看有没有 .cpg,没有就手动补一个写UTF-8或GBK;用 geopandas 读取时显式指定encoding参数试两种编码,哪个正常用哪个。
5.2 叠加时图层错位
现象:广东省 SHP 和在线底图或另一份数据叠加时整体偏移几百米。原因:两份数据坐标系不一致,或者其中一份 .prj 缺失被软件默认当成 WGS84。解决:分别打印两份数据的 crs,统一转到同一坐标系再叠加。如果 .prj 缺失,用set_crs手动声明而不是to_crs,两者区别是前者只声明不转换,后者会做坐标运算,用错会引入二次偏移。
5.3 面积计算出负数或极小值
现象:算出来的面积是负数,或者小得离谱。原因:几何存在自相交、环方向错误,或者在地理坐标系下直接算面积。解决:先to_crs投影,再用buffer(0)修复自相交几何,然后重新算面积。负数面积通常是环方向问题,buffer(0) 能顺带修正。
5.4 镇街边界对不上
现象:两份不同来源的镇街 SHP 在交界处有缝隙或重叠。原因:数据时点不同,行政区划调整后边界变了。解决:确认数据生产日期,统一到同一时点;做统计时用面叠加前先做拓扑检查,用overlay时注意how参数选择,避免重复计算。
5.5 导出 GeoJSON 后前端加载卡死
现象:前端加载全省镇街 GeoJSON 直接卡死。原因:顶点太多,文件几十兆。解决:用simplify简化几何,或按市拆分文件按需加载,或转成矢量瓦片(MVT)由后端切片。简化容差根据显示级别调整,别一刀切。
6. 进阶:用广东省 SHP 做空间连接与批量统计的一个实用套路
前面讲的都是单图层操作,真正体现广东省 SHP 价值的是空间连接。举个具体场景:你有一批门店坐标,想知道每个镇街各有多少家门店,进而算门店密度。这个套路我做过很多次,稳定可靠。
import geopandas as gpd import pandas as pd # 读取镇街边界并投影 towns = gpd.read_file("guangdong_town.shp").to_crs(epsg=4527) # 读取门店点数据,假设是 CSV 含经纬度 stores = pd.read_csv("stores.csv") stores_gdf = gpd.GeoDataFrame( stores, geometry=gpd.points_from_xy(stores["lng"], stores["lat"]), crs="EPSG:4326" ).to_crs(epsg=4527) # 空间连接,把镇街属性挂到每个点上 joined = gpd.sjoin(stores_gdf, towns[["镇街名", "区县名", "geometry"]], how="left", predicate="within") # 按镇街统计门店数 count_by_town = joined.groupby("镇街名").size().reset_index(name="store_count") # 合并回镇街面,算密度 towns_with_count = towns.merge(count_by_town, on="镇街名", how="left") towns_with_count["store_count"] = towns_with_count["store_count"].fillna(0) towns_with_count["density"] = towns_with_count["store_count"] / (towns_with_count.geometry.area / 1e6) print(towns_with_count[["镇街名", "store_count", "density"]].sort_values("density", ascending=False).head(10))逻辑说明:先把两个图层统一到同一投影坐标系,这是空间连接的前提。points_from_xy从经纬度列构造点几何,sjoin用within谓词判断点是否落在面内,how="left"保证没有匹配上的点也保留。分组统计后用merge挂回面图层,fillna(0)处理没有门店的镇街。密度用门店数除以面积平方公里数。参数上predicate可选within、intersects、contains,点面关系统一用within最稳。
这个套路能直接复用到人口统计、POI 分布、订单热力等场景。验证方法很简单:把结果导出成带坐标的 CSV,丢到任意地图工具里看,密度高的地方应该和你的业务直觉一致。如果某个镇街密度异常高,先检查是不是边界重叠导致重复计数,用dissolve按镇街名合并一次再统计就能排除。
我自己的习惯是:任何一次空间连接后,都要做一次「总数校验」——连接后的点总数必须等于原始点数,不等就说明有重复匹配,多半是面图层有重叠。这个后悔药,早吃早安心。希望帮到你。
本文还有配套的精品资源,点击获取