2021年云南省路网水网建筑与土地利用矢量数据shp底图应用指南

发布时间:2026/10/26 13:25:21
2021年云南省路网水网建筑与土地利用矢量数据shp底图应用指南

简介:这份资源面向GIS从业者、城市规划与地理信息相关专业师生,提供2021年云南省路网、水网、建筑、土地利用等矢量数据及行政区划边界,采用WGS84坐标,可直接在ArcGIS等平台加载分析,适用于空间制图、区域规划与基础地理研究。压缩包共40个文件,约57.53MB,以shp、shx、dbf、prj、xml五类配套文件为主,分别承载几何图形、索引、属性表、坐标投影与元数据,覆盖道路、铁路、水系、建筑、土地利用及地名等图层,并附云南省级边界,便于按要素分层调用与叠加分析。目前已有466人学习下载,数据现势性较好、图层较全,可帮助读者省去多源采集与坐标转换的繁琐环节,快速搭建云南区域空间分析底图,适合作为课程作业、项目前期调研与专题制图的可靠数据基础。

1. 2021年云南省路网水网建筑与土地利用矢量数据:一套shp底图能撑起多少事

手上接过一个云南县域的国土空间摸底项目,甲方甩来一句“先把底图整出来”,既没给数据源也没给坐标系要求。翻了一圈公开渠道,能同时覆盖路网、水网、建筑、土地利用四类要素,还带行政区划边界、统一到WGS84地理坐标的shp数据,基本就是2021年云南省这套矢量数据在扛事。它解决的不是“有没有数据”的问题,而是“四类要素能不能叠在同一套坐标里直接算”的问题——路网算通达性、水网做缓冲、建筑提占地、土地利用分类统计,全都要落在同一套行政区划边界内。适合做国土空间规划、GIS二次开发、遥感样本底图、三维场景白模的从业者,也适合刚接手云南相关项目、需要快速搭出可用底图的人。下面按“数据怎么组织→怎么落地→坑在哪”的顺序讲透。

2. 路网水网建筑土地利用四类shp怎么组织:图层拆分与字段设计

2.1 四类要素的图层拆分逻辑

拿到一套“最全”的矢量数据,第一件事不是急着加载,而是先想清楚它为什么按路网、水网、建筑、土地利用拆成四类。这四类要素的几何类型、属性维度、更新频率完全不同,混在一个图层里后期做空间分析会非常难受。常见做法是拆成独立shp文件,每类一个主文件,配套的.dbf、.shx、.prj、.cpg齐全,缺一个在ArcGIS或QGIS里都可能出玄学问题。

路网一般是线要素(Polyline),字段里通常带道路等级、名称、路面材质;水网有线要素(河流)和面要素(湖泊、水库)两种,需要分开存;建筑是面要素(Polygon),字段里带层数、结构类型、占地面积;土地利用也是面要素,字段里带地类编码、地类名称。行政区划边界单独一个面图层,作为所有统计的裁剪框。

提示:shp格式单文件字段名上限10个字符,中文属性字段在跨平台时容易乱码,建议字段名用英文缩写,.cpg文件里声明UTF-8。

2.2 字段设计与WGS84坐标的绑定关系

WGS84是地理坐标系(GCS),单位是度,不是米。很多人拿到shp一看.prj里写着WGS84就以为可以直接算面积、算距离,结果缓冲区半径设500米,出来的圈大得离谱。正确做法是:存储用WGS84,做空间分析前投影到对应的UTM带或高斯克吕格投影。云南跨UTM 47N和48N两个带,做全省分析建议用Albers等面积投影,做县域分析用当地中央经线的高斯投影。

字段设计上,土地利用图层建议保留地类编码(如0101耕地、0301林地)和地类名称两列,方便按编码做统计、按名称做展示。建筑图层保留占地面积字段,单位统一成平方米。路网保留等级字段,国道、省道、县道、乡道分级,后面做通达性分析直接按等级设权重。

import geopandas as gpd # 读取四类要素,统一检查坐标系 layers = { "road": "yn_road_2021.shp", "water": "yn_water_2021.shp", "building": "yn_building_2021.shp", "landuse": "yn_landuse_2021.shp", "boundary": "yn_boundary_2021.shp" } for name, path in layers.items(): gdf = gpd.read_file(path) print(f"{name}: CRS={gdf.crs}, 要素数={len(gdf)}, 几何类型={gdf.geom_type.unique()}") # 检查是否有空几何 empty = gdf[gdf.is_empty] if len(empty) > 0: print(f" 警告:{name}存在{len(empty)}个空几何")

这段代码做的是加载前的体检。gdf.crs确认坐标系是不是WGS84(EPSG:4326),geom_type确认几何类型是否符合预期,空几何检查是血泪经验——空几何在后续空间连接时会直接报错,提前清掉省得后面翻车。参数上,read_file默认用pyogrio或fiona引擎,如果shp属性表有中文乱码,加encoding='utf-8'。

2.3 行政区划边界作为裁剪与统计基准

行政区划边界图层是整套数据的骨架。省、市、县三级边界如果都在一个图层里,用字段区分层级;如果分开存,注意边界接边处不能有缝隙和重叠。常见做法是用县级边界做统计单元,把路网、水网、建筑、土地利用分别做空间叠加,算出每个县的指标。

# 以县级边界为单元,统计各县建筑占地面积 boundary = gpd.read_file("yn_boundary_county.shp") building = gpd.read_file("yn_building_2021.shp") # 确保两者坐标系一致 if boundary.crs != building.crs: building = building.to_crs(boundary.crs) # 空间连接:把建筑落到县 joined = gpd.sjoin(building, boundary, how="inner", predicate="within") # 按县汇总占地面积 stat = joined.groupby("county_name")["area_sqm"].sum().reset_index() stat.columns = ["县名", "建筑占地总面积(平方米)"] print(stat.head(10))

sjoin的predicate="within"表示建筑完全落在县边界内才统计,跨界的建筑会被排除。如果不想丢跨界建筑,改用intersects,但要在汇总时按面积比例分摊。how="inner"只保留能匹配上的记录,避免产生空值行。这一步做完,每个县的建筑占地指标就出来了,可以直接进报表。

3. 从shp到可用底图:WGS84坐标校验、投影转换与批量处理

3.1 WGS84坐标校验的三个必查项

拿到shp第一件事是验坐标,不是看.prj文件里写了什么,而是看坐标值本身。WGS84经纬度坐标的X范围在98°~106°(云南经度),Y范围在21°~29°(云南纬度)。如果X值在几百到几百万之间,那大概率是投影坐标,.prj可能标错了。

必查三项:一是坐标值范围,二是.prj文件内容,三是和已知地物比对。比如昆明市中心大概在102.7°E、25.0°N,加载后如果点跑到非洲去了,坐标系肯定有问题。

# 用ogrinfo查看shp的坐标系和范围 ogrinfo -al -so yn_road_2021.shp # 输出示例关注这两行: # Extent: (97.5, 21.1) - (106.2, 29.3) # Layer SRS WKT: GEOGCS["WGS 84", ...]

ogrinfo是GDAL自带的命令行工具,-al -so表示只输出摘要不输出要素。Extent范围如果在经纬度区间内,说明坐标值本身没问题。如果Extent是几百万,但SRS写着WGS84,那就是.prj标错了,需要手动指定正确的投影。

3.2 投影转换:WGS84到UTM与Albers的选型

做全省尺度的面积统计,用Albers等面积投影,中央经线设105°E,双标准纬线设25°N和47°N(云南大致范围)。做县域尺度的距离分析,用UTM带,云南东部用48N,西部用47N。

from pyproj import CRS # 定义Albers投影(云南全省适用) albers_crs = CRS.from_proj4( "+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 " "+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs" ) # 定义UTM 47N和48N utm47 = CRS.from_epsg(32647) utm48 = CRS.from_epsg(32648) # 转换 landuse = gpd.read_file("yn_landuse_2021.shp") landuse_albers = landuse.to_crs(albers_crs) landuse_albers["area_sqm"] = landuse_albers.geometry.area print(f"投影后总面积:{landuse_albers['area_sqm'].sum()/1e6:.2f} 平方公里")

lat_1和lat_2是双标准纬线,选在云南南北跨度内能最小化面积变形。units=m确保输出单位是米,算出来的面积才是平方米。转换后直接算geometry.area,不用再手动乘系数。这一步是面积统计准确性的关键,用WGS84直接算面积误差能到百分之几,在国土项目里这是不能接受的。

3.3 批量处理多个shp的脚本框架

一套数据动辄几十个shp,一个个手动转不现实。写个批量脚本,遍历目录下所有shp,统一转投影、统一字段名、统一输出。

import os import geopandas as gpd from pyproj import CRS albers_crs = CRS.from_proj4( "+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 " "+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs" ) input_dir = "./raw_shp" output_dir = "./processed_shp" os.makedirs(output_dir, exist_ok=True) for fname in os.listdir(input_dir): if not fname.endswith(".shp"): continue gdf = gpd.read_file(os.path.join(input_dir, fname)) # 统一转Albers gdf_proj = gdf.to_crs(albers_crs) # 输出 out_path = os.path.join(output_dir, fname) gdf_proj.to_file(out_path, encoding="utf-8") print(f"{fname}: {len(gdf)} -> {len(gdf_proj)} 要素,已转换")

to_file的encoding="utf-8"确保.cpg文件正确声明编码,避免中文乱码。批量处理时注意磁盘空间,投影转换后的shp文件可能比原始文件大,因为坐标值位数变多了。如果原始数据有损坏的几何,to_crs会直接报错,建议先跑一遍is_valid检查。

4. 避坑与排查:shp数据加载、坐标偏移与属性乱码的5个常见问题

4.1 现象:加载后要素跑到国外,坐标值却是对的

原因:.prj文件缺失或内容错误,GIS软件默认按WGS84处理,但实际坐标是投影坐标。解决:用ogrinfo看Extent,如果X值在几百到几百万,手动指定正确的投影坐标系,或者用gpd.read_file后手动set_crs再to_crs。

4.2 现象:中文属性字段显示为乱码

原因:shp的.dbf文件默认用系统编码,Windows中文系统是GBK,跨到Linux或QGIS里按UTF-8读就乱。解决:检查.cpg文件是否存在,内容是否为UTF-8。如果没有.cpg,用gpd.read_file(path, encoding="gbk")读入,再to_file(encoding="utf-8")输出。

4.3 现象:空间连接时大量要素匹配不上

原因:两个图层的坐标系不一致,或者边界有微小偏移。解决:先to_crs统一坐标系,再用buffer(0)清理几何,最后用predicate="intersects"代替within,减少因边界接边导致的漏匹配。

4.4 现象:面积统计结果偏大或偏小

原因:在WGS84地理坐标系下直接算面积,单位是度而不是米。解决:投影到等面积投影(Albers)后再算,云南全省用+proj=aea +lat_1=25 +lat_2=47 +lon_0=105。

4.5 现象:shp文件字段名被截断

原因:shp格式限制字段名最多10个字符。解决:设计阶段就用英文缩写,如road_name、land_code、bldg_area,在文档里维护字段对照表,展示时再映射回中文。

5. 进阶用法:用渔网分割shp做格网统计与shp转3dtiles的衔接

5.1 渔网分割shp做格网统计

县域统计太粗,想看空间分布细节,用渔网分割。生成1km×1km格网,把建筑、土地利用叠上去,算每个格网的建筑密度、地类占比。

import geopandas as gpd from shapely.geometry import box import numpy as np boundary = gpd.read_file("yn_boundary_county.shp").to_crs(epsg=32648) minx, miny, maxx, maxy = boundary.total_bounds # 生成1km渔网 cell_size = 1000 cols = np.arange(minx, maxx, cell_size) rows = np.arange(miny, maxy, cell_size) cells = [box(x, y, x+cell_size, y+cell_size) for x in cols for y in rows] grid = gpd.GeoDataFrame({"geometry": cells}, crs="EPSG:32648") # 裁剪到县域范围 grid = gpd.overlay(grid, boundary, how="intersection") # 叠建筑算密度 building = gpd.read_file("yn_building_2021.shp").to_crs(epsg=32648) joined = gpd.sjoin(building, grid, how="inner", predicate="within") density = joined.groupby("index_right")["area_sqm"].sum().reset_index() grid = grid.reset_index().rename(columns={"index": "index_right"}) grid = grid.merge(density, on="index_right", how="left").fillna(0) grid["building_density"] = grid["area_sqm"] / (cell_size**2) print(grid[["building_density"]].describe())

overlay的how="intersection"把渔网裁到县域边界内,边缘格网会被切成不规则形状。sjoin把建筑落到格网,groupby汇总面积,最后除以格网面积得到密度。这套流程换成土地利用、路网密度都一样,改一下输入图层和统计字段即可。

5.2 shp转3dtiles的衔接要点

建筑shp要进三维场景,常见路径是shp→白模→3dtiles。shp里如果有层数字段,按层数拉伸高度;没有的话按默认高度或从外部数据补。坐标系必须统一到WGS84经纬度,因为3dtiles用WGS84。转换工具链一般是GDAL+Python或专门的转换软件,核心是保证建筑底面和地形贴合,不然会出现悬空或埋地。

注意:shp转3dtiles前先做几何有效性检查,自相交的面在拉伸时会生成破面,用buffer(0)修复。

5.3 我踩过的坑与固定习惯

最早做云南项目时,拿到shp直接算面积,结果和甲方手里的统计年鉴对不上,差了将近8%。排查半天才发现是WGS84下直接算的。从那以后,我的固定习惯是:拿到任何shp,先ogrinfo看范围,再to_crs转等面积投影,算完面积再转回WGS84存一份。另一个习惯是每个项目建一个field_mapping.csv,记录shp字段名和中文含义的对照,交付时一起给,省得后面扯皮。这套数据本身不复杂,复杂的是坐标系和字段的细节,把这些抠死,后面做分析、做三维、做报表都顺。希望帮到你。

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