简介一份2024年北京市河流水系矢量图层shp数据包面向GIS开发人员、地图制图人员及水利、规划相关从业者解决北京市水系数据获取难、不全面的问题。数据包同时包含水系线与水系面数据要素数量达数千至上万条细节丰富可直接用于ArcGIS、QGIS等平台的空间分析、地图制图、水域监测与水文模拟。压缩包共11个文件除核心的shp矢量文件外还配置了dbf属性表、shx索引、prj投影及cpg编码文件另附shp2json.py脚本便于批量导出GeoJSON数据规范且压缩后仅2.64MB。目前已有160人浏览学习。使用此数据可快速制作水系专题图、开展河流选线分析或用于GIS课程教学配套的坐标与字段信息减少了预处理负担是标准化的水系基础数据适合数据科学项目、城市规划展示等场景。1. 北京河流水系矢量数据别只看成一张图做规划、做环评、做防汛演练的人拿到“2024北京市河流水系矢量图层shp数据”时第一反应往往是丢进ArcMap里看一眼有多细。但真正让它值钱的不是那张蓝线图而是它同时给了你“线”和“面”两套几何外加一个可直接改的shp2json.py脚本。线数据适合做河道中心线、流向分析面数据适合做淹没范围、水域占用统计。这套shp内含水系线和水系面共上万条要素细化程度远超市面上常见的省级骨干河流数据集。对于需要在北京范围内做空间分析、地图出图、数据转换的GIS工程师来说这套数据能直接缩短三天以上的数据预处理时间。适合有ArcGIS Pro或QGIS基础、且需要处理真实地理数据的从业者不建议完全零基础的人拿它当入门练习。2. 数据包解剖prj、dbf、shx与shp2json.py各管什么拿到“北京市.zip”解压后你会看到一堆后缀不同的同名文件。这可不是冗余而是Shapefile格式的硬性要求。一个完整的SHP矢量数据集必须由主文件.shp、属性表.dbf、索引.shx和投影信息.prj共同组成。缺了.dbf属性字段全丢缺了.shx查询速度会慢到让人抓狂缺了.prj坐标系无法被正确识别。2.1 认识每个文件的角色与常见坑解压后的文件清单里值得逐个确认的有北京市_水系线数据.shp存储线要素几何用于河流中心线、沟渠等线性水体。北京市_水系面数据.shp存储面要素几何用于水库、湖泊、坑塘等面状水体。.prj包含WGS84或CGCS2000等坐标系信息。如果缺失ArcGIS Pro会默认用“未知坐标系”导致叠加其他数据时偏差几百米。.cpg声明.dbf字段的字符编码。常见缺这个文件后中文属性在QGIS里乱码所以看到cpg文件别删。shp2json.py一个用Python写的数据转换脚本通常用来把shp转成GeoJSON便于WebGIS或Leaflet等前端使用。需要注意同一组数据里“线”和“面”是分开的文件不是同一个要素类里的不同图层。所以做叠加分析前要在ArcGIS Pro里分别加载再用“相交”或“空间连接”来关联而不是默认它们自带拓扑关系。2.2 查看投影与字段属性的具体操作在ArcGIS Pro中用“目录”窗格连接到数据所在文件夹双击“北京市_水系面数据.shp”即可预览。右键选择“属性” → “源”选项卡能看到坐标系描述。若显示GCS_WGS_1984说明经纬度坐标单位是度若显示CGCS2000_3_Degree_GK_CM_117E之类则是平面坐标单位是米。二者在计算面积和长度时结论差异极大切勿混用。要查看字段打开属性表常见字段可能有Name、Type、Length、Area等。检查一下是否包含河流名称字段这直接决定后续是否能做名称标注。如果只有OBJECTID和Shape_Length那就只能做几何分析做不了地名检索。2.3 shp2json.py脚本改造从固定路径到命令行传参提供的shp2json.py通常只处理写死的文件路径不适合批量使用。我一般会把它改造成接收命令行参数的形式方便在处理多个区县数据时复用。示例改法如下import json import sys import shapefile # pyshp库 def shp_to_geojson(shp_path, json_path, encodingutf-8): sf shapefile.Reader(shp_path, encodingencoding) fields sf.fields[1:] # 跳过删除标记字段 field_names [f[0] for f in fields] features [] for record in sf.shapeRecords(): attrs dict(zip(field_names, record.record)) geometry record.shape.__geo_interface__ features.append({ type: Feature, properties: attrs, geometry: geometry }) result { type: FeatureCollection, features: features, crs: sf.srs if hasattr(sf, srs) else None } with open(json_path, w, encodingencoding) as f: json.dump(result, f, ensure_asciiFalse, indent2) print(f转换完成{len(features)} 条要素 - {json_path}) if __name__ __main__: if len(sys.argv) ! 3: print(用法: python shp2json.py 输入shp 输出json) sys.exit(1) shp_to_geojson(sys.argv[1], sys.argv[2])这段代码用pyshp库读取shp把每个要素的几何和属性打包成GeoJSON Feature。注意encoding参数声明为utf-8如果原始dbf是GBK编码需要改成gbk否则中文名称会乱码。__geo_interface__是从pyshp的Shape对象中提取几何类型、坐标列表的标准接口不需要手写坐标遍历。命令行用法是python shp2json.py 北京市_水系线数据.shp 北京市_水系线.json转换后可直接被D3、Mapbox、Cesium等前端库消费。3. 在ArcGIS Pro与QGIS里正确叠加、符号化与出图拿到shp后最忌讳的是双击直接用Windows资源管理器预览或拖进ArcMap不检查坐标系就硬叠加。正确流程是先建立工作空间再统一投影再按制图规范调整符号。3.1 建立文件地理数据库并导入shp我建议建一个Beijing_Hydro.gdb把线、面数据都导入进去避免之后做分析时因路径移动而丢失相对引用。在ArcGIS Pro中操作如下1. 打开目录窗格右键默认工作文件夹 → 新建文件地理数据库命名Beijing_Hydro.gdb 2. 右键Beijing_Hydro.gdb → 导入 → 要素类(单个) 3. 输入选择“北京市_水系线数据.shp”输出要素类名保持默认 4. 重复导入“北京市_水系面数据.shp”导入时注意“要素类(单个)”选项是专门处理单个shp的如果选“要素类(多个)”而数据源又不在同一个文件夹容易报错。导入后右键每个要素类 → 属性 → 源确认坐标系已经变成地理数据库默认的投影。如果prj缺失导致坐标系未知先在ArcGIS Pro里用“定义投影”工具手动指定WGS84再用“投影”工具转成目标坐标系不要直接跳过这一步否则后续里程计算全是错的。3.2 线符号与水系分级的制图参数水系线在出图中通常按河流等级设置不同线宽和颜色。北京市水系数据里若字段含有LEVEL或ORDER可以用唯一值符号化。操作如下图层属性 → 符号系统 → 主符号系统 → 唯一值 值字段选择LEVEL或Type 颜色带选择蓝绿色系建议主河道用C32E8F等级低的支流用A6CEE3 线宽干线2.5pt支线1.0pt细小沟渠0.4pt如果没有分级字段就用Shape_Length做“分级色彩”按长度分五级。面数据则建议用浅蓝色填充、35%透明度让底图地形露出来。透明度在“图层属性 → 显示 → 透明度”里设置面填充色选#A6CEE3轮廓线用#1F78B4、线宽0.2pt这样既不会抢了线的视觉层次又能看出湖泊范围。出图前在布局视图中插入图例图例项只保留水系相关的三到四层不要把所有图层都塞进去。比例尺选“交替单位”显示公里和米指北针直接删掉北京地区用GRID网格或经纬度注记更专业。3.3 QGIS中处理cpg缺失导致乱码的解法如果你在QGIS里打开属性表发现中文名称全是“?????”或乱码多半是.cpg文件缺失或声明编码与dbf实际编码不符。这时不要重新下载直接用系统自带记事本新建一个文本文件写入GBK或UTF-8然后改名为北京市_水系线数据.cpg替换原文件。注意cpg文件内容必须与dbf实际编码一致。如何判断实际编码可以用Notepad打开dbf的十六进制前若干字节看字符区域更简单的方法是依次用UTF-8和GBK重命名cpg试一遍哪个打开属性表不乱码就锁定哪个。在QGIS图层属性 → 数据源 → 编码选项中也可以手动覆盖为UTF-8或GBK但保存项目时要确保该设置被持久化。QGIS里快速检查坐标系的做法是双击图层 → “信息”选项卡如果显示WGS 84 / Pseudo-Mercator之类的投影且底图为OSM标准瓦片则无需重新投影QGIS可实时变换。但做面积统计时必须把图层“另存为”到本地使用“ESRI Shapefile”格式并选择正确的目标坐标系或者在“处理”工具箱里使用“重投影图层”算法不然算出来的面积是基于伪墨卡托的扭曲结果。4. 基于Python的水系数据清洗与拓扑修复实战直接拿来用的shp数据源往往伴随“属性多余”“几何重复”“线段自相交”等问题。尤其水系数据线要素在分幅采集后经常出现断头线面要素则可能因为重复采集导致重叠或缝隙。用Python脚本批量处理比在ArcGIS里一个个点选高效得多。4.1 使用geopandas读取并检查几何有效性import geopandas as gpd gdf_line gpd.read_file(北京市_水系线数据.shp, encodingutf-8) gdf_poly gpd.read_file(北京市_水系面数据.shp, encodingutf-8) print(线要素数量:, len(gdf_line)) print(面要素数量:, len(gdf_poly)) print(坐标系:, gdf_line.crs) valid_check ~gdf_poly.geometry.is_valid print(非法面要素数量:, valid_check.sum()) print(gdf_poly.loc[valid_check, geometry].head())geopandas.read_file会自动读取prj中的坐标系信息返回一个GeoDataFrame。is_valid是shapely提供的方法用于判断几何是否满足OGC规则比如多边形环方向、自相交等。输出中如果显示非法要素数量超过0就要用buffer(0)修复常见做法是执行gdf_poly.geometry gdf_poly.geometry.buffer(0)。这行命令的作用是给几何加零缓冲shapely会重建有问题的多边形边界。对于线要素常见问题是线串自相交可以用line.unsnapped()或先“线转点”再“点转线”来重建但更简单的是用geopandas的explode()将MultiLineString拆分成单线再逐条检查。4.2 清洗属性字段删除无价值列与统一命名原始数据里常有FID_1、Shape_Leng这类软件生成的冗余列以及大量空值。drop_cols [FID, Shape_Leng, Shape_Area] gdf_line_clean gdf_line.drop(columns[c for c in drop_cols if c in gdf_line.columns]) gdf_line_clean gdf_line_clean.rename(columns{Name: river_name, TYPE: type_code}) gdf_line_clean[length_km] gdf_line_clean.geometry.length / 1000 gdf_line_clean gdf_line_clean[gdf_line_clean[length_km] 0.1] # 过滤短碎线geometry.length的单位取决于shp的坐标系。如果当前坐标系是经纬度(WGS84)这个长度值是“度”不能直接作为公里数。需要先用to_crs投影成EPSG:3857或北京地方坐标系再计算长度。例如gdf_line_clean gdf_line_clean.to_crs(epsg3857)然后再算length_km。过滤掉长度小于0.1公里的碎线能大幅减少后续拓扑分析中的噪音。这里的0.1公里阈值可以根据数据密度调整如果数据集本身包含更短的小沟渠建议保留。4.3 检查并修复节点断开与重复要素水系线最常见的质量问题是两条首尾相邻的线段没有在同一个端点上相交导致路径分析时河流断裂。from shapely.ops import unary_union lines gdf_line_clean.geometry.tolist() merged unary_union(lines) print(合并后要素数:, len(merged))unary_union会尝试把所有相交的线在交点处打断如果两条线的端点距离小于容差它们会合并为一条连续线。如果合并后的要素数比合并前少很多说明断头现象严重。这时可以调用gdf_line_clean.geometry gdf_line_clean.geometry.snap(gdf_line_clean.geometry.tolist(), tolerance0.0001)其中tolerance的单位是坐标系单位。如果数据是经纬度0.0001约等于10米如果数据是投影坐标系米tolerance要设置成0.1或0.5米。snap会把每个线端点吸附到另一个线的最近节点上从而消除微小间隙。重复面要素的检测可以用gdf_poly.geometry.equals(gdf_poly.geometry.shift())的思路但实际操作中更推荐去掉完全重复的几何gdf_poly_dedup gdf_poly.drop_duplicates(subsetgeometry)该命令基于shapely几何对象的哈希值判断重复删除后要重置索引。面拓扑修复中重叠面积较大的两个面可以用“擦除(Erase)”工具处理但这属于ArcGIS工具箱的操作Python里则需要用gpd.overlay函数做差集分析比较耗时。通常我只处理非法几何重叠问题留给ArcGIS Pro的“修复几何”工具。5. 面转线、线转面与批量导出JSON的高阶玩法最后这部分分享三个能直接优化工作流的操作全部围绕这套北京水系数据展开。5.1 用ArcGIS Pro的“面转线”与“线转面”处理拓扑需求“面转线”是把湖泊、水库的面边界提取为线要素用于分析岸线长度或合并相邻水体边界。操作路径是“分析工具 → 要素提取 → 面转线”。参数上注意“识别和存储面邻接信息”选项要勾选输出会多出左右多边形ID字段方便后续判断哪个线是两湖公共边界。“线转面”则恰好相反把封闭的线要素圈定成面。如果想把“水系线”和“水系面”统一转化为专项岸线图可以先把面转线得到岸线shp再和原有的线shp合并然后用“线转面”重新构建多边形构建后使用“融合”按河流名称合并就能得到一个干净的分行政区水系面。线转面对源数据要求很高必须是完全封闭的线段出现一个缺口就生成不了面。常见的补救措施是先用“编辑 → 捕捉”把所有端点捕捉到0.1米容差再运行“修复几何”最后线转面。这类操作更适合在ArcGIS Pro的模型构建器中串联设置成中间数据自动覆盖。5.2 批量转换成MySQL GeoJSON时优化文件体积利用之前改造过的shp2json.py可以循环目录下多个shp文件for f in *.shp; do python shp2json.py $f ${f%.shp}.json done但完整GeoJSON带缩进文件体积很大用水系面数据测试一个10MB的shp可能膨胀到50MB以上。更稳妥的做法是去掉indent2并只保留必要属性字段在转换脚本里加一个参数。或者改用geojson库配合compress选项输出压缩过的GeoJSON。前端加载时用fetch直接请求无需解压浏览器会自动处理gzip传输。如果数据要入库PostGIS则推荐使用shp2pgsql命令行工具命令示例为shp2pgsql -s 4326 -W GBK 北京市_水系线数据.shp public.river_line | psql -U postgres -d gisdb。注意-W GBK要和dbf编码保持一致否则中文名称入库全是问号。5.3 制作动态水量热力图的加速技巧最后提一个真实项目里踩过的坑用这套水系面数据做热力图先直接按Shape_Area字段做分级渲染结果湖泊面积差异悬殊小坑塘全部变成不可见的点。后来我改用面积等级字段先计算对数分类再映射颜色才让细节显示出来。计算对数分类的Python片段如下import numpy as np gdf_poly[area_log] np.log10(gdf_poly.geometry.area 1e-6) gdf_poly[level] pd.cut(gdf_poly[area_log], bins5, labelsFalse)np.log10能压缩数量级差异pd.cut按分位数切出五档这样面状水体的渲染在ArcGIS Pro和QGIS中都能保持稳定。之后再把level字段导出到新的shp或GeoJSON前端配色直接匹配该字段即可。运行上述脚本前务必确认geometry的面积单位如果坐标系是经纬度面积值是“度²”量纲不对时log变换毫无意义务必要把数据投影到等面积坐标系比如EPSG:6933再计算面积。本文还有配套的精品资源点击获取