简介:一份面向GIS、水文与地理科研人员的黄河流域基础数据集,整合了干流、支流、湖泊、公路、铁路等交通线路,以及国界、省会、地级市等省市边界要素,地理要素体系较完整。数据统一采用WGS-84坐标系,全部以Shapefile格式存储,几何与属性信息完整准确,可用于流域空间分析、专题制图、实验教学及科研建模。压缩包共84个文件,包含12组要素图层,每组由shp、dbf、prj、shx、sbn、sbx、xml等配套组成,分别对应几何坐标、属性表、投影定义、几何索引、空间索引与元数据,整体体积仅7.94MB,便于快速下载部署。这一数据集已有1891人学习浏览,是一套结构完整的黄河基础地理数据。使用者可直接开展干支流关系分析、湖泊缓冲区构建和交通网络叠加等实验,也适合作为GIS初学者练习Shapefile数据结构的现成素材。
1. 黄河流域基础数据集:为什么我建议从零组装而不是去找打包资源
做黄河流域的生态评估项目时,我从一个公开平台下载了一份“黄河全流域基础数据集”,文件名写得很完整,解压开只有三层:干流一条线、支流几十条短线、外加一个黄河水利委员会边界面。往地图上一叠,问题立刻暴露:无定河到不了源头,渭河在西安城区断了两次,几个水库湖面位置漂移超过五公里。后来我意识到,这类打包数据大多是某一版专题图的再加工,字段、精度、时效都不可控,而标题里描述的“黄河流域基础数据集”本质上是一个组装工程——把干流、支流、湖泊、流域内交通线路等不同来源、不同精度、不同坐标系的矢量数据,统一成一份能直接开工的底图。适合正在做流域水文分析、洪水淹没模拟、路网可达性研究的人参考。
2. 数据源选型与坐标系:底图不对,后面全白做
2.1 六类基础数据的目标来源:多源组合而不是单源硬扛
先确定一件事:没有任何一个单一数据源能同时满足黄河流域的河网密度、湖泊精度和交通线路时效。常见的可靠做法是“全球水文数据集做骨架 + 众源地理数据做细节补丁”。
我一般这样分配来源:
| 数据类别 | 首选来源 | 备选来源 | 关键字段 |
|---|---|---|---|
| 干流与支流河网 | HydroRIVERS 全球河网 | OpenStreetMap(OSM)水系图层 | ORD_STRA(Strahler 级序)、NAME |
| 湖泊与水库 | HydroLAKES 全球湖泊水库数据集 | OSM natural=water 搭配 water=reservoir | LAKE_ID、LAKE_NAME、AREA |
| 流域边界 | HydroBASINS 全球流域多边形 | 基于 DEM 手动提取分水岭 | HYBAS_ID、SUB_BASIN |
| 交通线路 | OSM 道路与铁路图层 | 各省公开的基础地理数据服务 | highway、railway、name |
| 辅助地形 | SRTM / Copernicus DEM | 可选项,用于验证分水岭 | 高程栅格 |
这里要说一下为什么拼起来而不是只信一份。HydroRIVERS 对全球大江大河的表达很稳定,黄河干流、一级支流的属性完整,具备 Strahler 河网分级字段。但它的空间精度有限,在黄土高原的支流段经常被简化为单线,部分源头位置和实际地形偏差明显。OSM 正好相反——河网细节在城镇区域密集很多,能补上双线河道和人工渠系,但数据被切得零碎,同一个黄河干流在不同区段可能使用不同的名称标签。两者叠加,才勉强接近“基础数据集”该有的样子。
选型时还要想清楚输出格式。我强烈建议最终产物用 GeoPackage(.gpkg),而不是 Shapefile。Shapefile 受限于单文件 2GB 上限、属性字段名只有 10 字节、中文编码兼容性问题多;GeoPackage 单文件多图层,字段名、编码、空间索引都省心。真正需要对外交付旧格式的时候,再导出一份 Shapefile。
2.2 坐标系与投影:存储用一个,分析用另一个
这是整个组装过程里最容易被忽略、翻车率最高的地方。黄河流域的东西跨度从东经约 95° 到 119°,南北跨度约 32°N 到 42°N。跨这么大的区域,一套固定投影不可能同时保证面积、距离、方向的精度。
我的分工很明确:
- 存储坐标系:统一用 CGCS2000 地理坐标系,EPSG:4490。所有原始数据先重投影到这个基准,保证大家说的是同一套经纬度。
- 分析投影:做面积量算、缓冲区、密度分析时用 Albers 等积圆锥投影,两条标准纬线可取 32°N 和 40°N,中央经线取 108°E。黄河流域大部分区域落在低变形带内,面积计算不会出现肉眼可见的误差。
- 局部小范围分析:如果你只研究陕西某一段支流,可以用该区域的 3 度高斯-克吕格投影,比如 EPSG:4527 对应的 117°E 中央经线带。但不要拿它去做整个流域的面积统计。
这里最常遇到的坑是数据自带的坐标系被写成 EPSG:3857(Web Mercator)。Web Mercator 是网络地图的标准,拿来量面积非常不靠谱。黄河流域在中纬度,EPSG:3857 下面积会被夸大 20% 到 40%,具体数值取决于纬度。很多二手数据下载下来,.prj 文件里写的是 GCS_WGS_1984,实际坐标数值却明显是米制的,这类数据要先用长度阈值识别出来,再做投影纠正。
2.3 用 ogr2ogr 完成格式转换与重投影的最小命令
把零散数据统一到同一坐标系,我一般用 GDAL 自带的 ogr2ogr 完成,而不是打开 QGIS 手工另存。命令简短、可批量、可重复执行。
# 方案 A:把 WGS84 的 Shapefile 转成 CGCS2000 地理坐标,输出到 GeoPackage ogr2ogr -f GPKG \ -t_srs "EPSG:4490" \ h_yellow_basin_base.gpkg \ source_wgs84.shp # 方案 B:如果交付要求是 Shapefile,记得加编码参数 ogr2ogr -f "ESRI Shapefile" \ -t_srs "EPSG:4490" \ -lco ENCODING=UTF-8 \ output_dir/ \ source_wgs84.shp第一条命令把输入要素全部追加到 GeoPackage 的默认图层,坐标系从源文件直接转换到 EPSG:4490。注意-t_srs不只改坐标系定义,还会真的重算坐标值,所以源文件的坐标系必须写对。如果源文件 .prj 缺失,先确认坐标范围——黄河流域经纬度应该在 95 到 119 之间,如果看到 400 万量级的数字,说明源数据是投影坐标,不能用地理坐标去套。
第二条命令里-lco ENCODING=UTF-8只对 ESRI Shapefile 驱动生效,写入 DBF 属性表时把编码标记为 UTF-8,能缓解大部分中文乱码问题。但老版本 GIS 软件读取这种 UTF-8 标记的 Shapefile 仍可能显示乱码,所以我更推荐直接交付 GeoPackage。执行完成后随手用ogrinfo -so -al查看要素数和范围,确认没有出现要素丢失。
3. 按流域边界裁剪:从全球数据里切出黄河流域
3.1 黄河边界从哪里拿:HydroBASINS 与手动修正
水系、湖泊、交通线路都是全球或全国数据集,第一步永远是先把它们裁剪到黄河流域范围里。裁剪必须有一个“边界底版”。HydroBASINS 从全球 DEM 提取,分多个嵌套级别,低级别是大流域,高级别是更细的子流域。黄河整体一般取 le06 或 le07 级别的多边形,一个面就能覆盖整个外流区。
拿到数据后先做一次边界核查。我遇到过的问题是黄土高原边缘的流域边界和实际地形分水岭差出一条山脊,原因在于原始 DEM 的分辨率不足,细沟地形被过度平滑。因此明确地说:HydroBASINS 边界只能作为初始范围,最终要用 QGIS 手动微调,叠加 SRTM 的 hillshade 底图,沿分水线修正关键区段。
用属性过滤提取边界的命令如下:
# 按流域编号过滤出黄河流域多边形 ogr2ogr -f GeoJSON \ -where "HYBAS_ID = 4050022540" \ yellow_basin_initial.geojson \ HydroBASINS_lev06.shp注意HYBAS_ID是数值型字段,不要加引号。如果不知道具体 ID,先用ogrinfo -al -so查看属性表,再按 “黄河” 或 “Yellow” 关键词筛选,或者直接按边界范围做空间过滤。我更常用后一种:先加载整个 le06 图层,在 QGIS 中浏览,选中覆盖黄河出口的那个多边形,再复制其 HYBAS_ID 回填到命令里。
3.2 干流与支流提取:按名称匹配 + Strahler 分级
流域边界就位后,开始提取河网。我以 HydroRIVERS 做骨架,过程分成两步:先是空间裁剪,再是名称和级序联合筛选。只信属性筛选不可靠,因为跨流域的同名河流很多;只信空间裁剪也不够,因为裁剪后还会残留黄河下游平原上的灌排渠系。
import geopandas as gpd # 读取流域边界,转换成和河网相同的坐标系 basin = gpd.read_file("yellow_basin_initial.geojson") river_full = gpd.read_file("HydroRIVERS.shp") # 先空间裁剪,把范围缩小到黄河流域内部 river_clip = gpd.clip(river_full, basin) # 按名称关键词匹配黄河干流和主要一级支流 target_names = ["黄河", "汾河", "渭河", "无定河", "北洛河", "湟水", "大通河"] river_key = river_clip[ river_clip["NAME"].apply( lambda x: any(n in x for n in target_names) if x else False ) ].copy() # 按 Strahler 级序补漏,提取那些名字对不上但级序足够高的河段 river_major = river_key[river_key["ORD_STRA"] >= 4] # 分图层输出 river_major.to_file("yellow_base.gpkg", layer="major_river", driver="GPKG")这里gpd.clip是空间裁剪,直接按边界几何裁掉范围外要素,速度和稳定性都优于overlay。名称筛选用any(n in x for n in target_names)是模糊匹配,因为 HydroRIVERS 的中文名在不同区段可能带后缀,比如“黄河”“黄河干流”“黄河故道”,精确匹配会漏。
以此为基础,我再从 OSM 提取一次细节河道,专门处理城区和灌区内 HydroRIVERS 缺失的区段。OSM 全国包动辄几 GB,建议先用 osmium 过滤出所有 waterway 要素,缩小数据量。
# 先按标签过滤,导出小体积的 PBF,后续处理快得多 osmium tags-filter china-latest.osm.pbf \ w/waterway=river \ -o yellow_waterway.osm.pbf然后用 ogr2ogr 把 PBF 转成 GeoPackage,按同样的名称关键词过滤一次。OSM 数据里黄河干流在多个区段名称不一致,常见的有“黄河”“黄河干流”“黄 河”,所以模糊匹配这里仍然管用。但 OSM 河段断点非常碎,干流一次提取出来可能被切成几百上千段,需要在第 4 章做拓扑合并。
3.3 湖泊与交通线路批量裁剪:空间裁剪的两个关键参数
湖泊水库来自 HydroLAKES,全球数据集有几百万个面要素,直接读全量再做空间计算会很吃力。我的习惯是先按流域边界裁剪,再按面积阈值过滤——黄河流域的大中型湖泊水库面积基本都在 0.5 平方公里以上,低于这个值的大多是坑塘或 DEM 提取的伪多边形。
lakes = gpd.read_file("HydroLAKES.shp") # 先裁剪,再按面积过滤,这两个顺序不要反 lakes_clip = gpd.clip(lakes, basin) lakes_key = lakes_clip[lakes_clip["AREA"] >= 0.5].copy() # 导出到统一工程库 lakes_key.to_file("yellow_base.gpkg", layer="lake_reservoir", driver="GPKG")交通线路从 OSM 提取时,重点不是裁剪参数,而是标签选择。公路要的是highway里的motorway、trunk、primary、secondary,这些才是流域内干线;铁路要的是railway=rail。如果按highway不区分等级全部提取,结果会混入大量村道,文件体积大且不实用。裁剪时我一般保留边界线两侧 1 公里缓冲区,防止道路恰好压在边界上导致要素被切掉。
roads = gpd.read_file("gis_osm_roads.shp") roads_key = roads[ roads["highway"].isin(["motorway", "trunk", "primary", "secondary"]) ].copy() roads_clip = gpd.clip(roads_key, basin.buffer(0.01)) roads_clip.to_file("yellow_base.gpkg", layer="transport", driver="GPKG")这里的 0.01 是经纬度下的度数缓冲区,约 1 公里。如果你已经在做投影分析,建议把 basin 投影到 Albers 后再 buffer 1000 米,精度更可控。
4. 清洗与拓扑检查:交付前必须过的三道关
4.1 几何有效性检查与修复:ST_IsValid 与 makevalid
数据从不同平台汇合,几何错误几乎是必然的。最常见的是自相交多边形——湖泊边界在绘制时节点顺序乱掉,线段自己穿过自己;还有重复节点和极小狭长面。直接拿这些数据做空间分析,缓冲区和叠加结果会莫名奇妙地冒出错误多边形。
先用 shapely 快速扫一遍全域:
from shapely.validation import make_valid import geopandas as gpd layer = gpd.read_file("yellow_base.gpkg", layer="lake_reservoir") bad = layer[~layer.geometry.is_valid] print(f"invalid geometries: {len(bad)}") # 批量修复,注意修复前后的几何类型可能发生变化 layer["geometry"] = layer.geometry.apply(make_valid) layer = layer[~layer.geometry.is_empty]make_valid是 shapely 1.8 之后的通用修复入口,能处理自相交、环方向错误、重复点等大部分问题。但它有一个副作用:修复后的几何可能是 MultiPolygon,甚至 GeometryCollection,这在后续统计面积时会让逻辑变复杂。修复完成后要确认每个要素的类型是否符合预期,必要时用geopandas.GeoDataFrame.explode()把集合拆开。
如果是 PostGIS 环境,直接用ST_MakeValid(geom)等效,但同样要注意它对 Multi 类型的聚合处理。几何修复是数据集的“后悔药”,没有这一步,后面所有空间分析的错误都会被算在算法头上。
4.2 属性字段统一:命名、编码与类型
多源拼出来的数据,属性表五花八门:HydroRIVERS 有ORD_STRA,HydroLAKES 有AREA,OSM 有name、highway、ref。拼到一起后,下游用数据的人最恨字段名含义不清。
建议在最终数据集里做一套简化但明确的字段规范:
| 标准字段 | 含义 | 取值示例 |
|---|---|---|
| fid | 原始要素唯一标识 | HYR_100234 |
| name_zh | 中文名称 | 渭河 |
| name_en | 英文/拼音名称 | Weihe River |
| ftype | 要素类型 | river / lake / road / railway |
| source | 来源标记 | HydroRIVERS / OSM / HydroLAKES |
| level | 分级字段 | 干流=1,一级支流=2 |
| is_main | 是否主干 | 1 / 0 |
这里有个细节:先确定字段类型再写属性。Shapefile 的 DBF 字段长度有限,字段名超过 10 个字符会被截断;GeoPackage 没有这个限制,所以工程库内字段名可以写清楚,但导出 Shapefile 时要在转换前设计好 10 字以内的别名。
编码问题我踩过不少次。早期拿到的某批河流数据属性表是 GBK,GDAL 读出来全是乱码,用ogr2ogr -lco ENCODING=UTF-8重写也只能保证下次打开不乱码,原始乱码字符串已经救不回来。所以数据一入库就统一转成 UTF-8,用ogrinfo抽查属性,而不是等输出成品时再处理。
4.3 拓扑错误处理:河流断线、重复边与自相交
河网拓扑是水数据分析里最磨人的环节。OSM 提取出来的黄河干流,仅仅因为不同区段的name标签不同,就会被拆成互相断开的线。空间上断开几十米,肉眼看不出来,但做河网连通性分析、算河流长度、做水库汇流关系时全部出错。
处理断线最有效的顺序是先合并再打断:
# 用 GRASS v.clean 处理打断和合并,tool=snap 先把断点吸在一起 v.clean input=rivers_layer output=rivers_clean \ tool=snap,break,rmdupl \ threshold=50,-1,-1snap阈值 50 表示 50 米内的断点会被吸附到一起,break在所有交点处把线打断,rmdupl删除重复线段。执行后还要重新对黄河干流做一次基于名称的分组合并,把name_zh相同且首尾相接的线段用LineString.union连起来。
重复边的问题主要来自两次裁剪叠加。比如 HydroRIVERS 和 OSM 的河流数据在交汇处各有一段方向相反的线,空间上几乎重合。修正方法是把两条线互相symmetric_difference,或者直接以 HydroRIVERS 为准,在裁剪阶段就按名称丢弃 OSM 中与高等级河流重叠的部分。
自相交在交通线网中最常见。一条盘山公路在三维转二维时产生自交叉,会被 GIS 引擎当作环路处理。解决方式是执行v.clean的break步骤,把自相交点变成真正的节点,再删除短到不合理的碎段。这些处理在 QGIS 里用“修复几何”插件也能做,但批量工程数据还是要脚本化,否则没法复现。
5. 避坑:黄河流域数据构建的 5 个典型踩坑记录
5.1 黄河干流在 OSM 里被切碎成上千段
现象:从 OSM 提取黄河干流后,属性表里有上千条线段,长度参差不齐,短段只有几十米。绘制时线条颜色断层,路径规划类分析完全不可用。
原因:OSM 是众源编辑,不同人按不同名称和绘制习惯分段,一段河堤、一段双线河口都被拆成独立要素。部分区段没有name标签,导致自动合并失败。
解决:先按waterway=riverbank和waterway=river分类处理。线状河流用name_zh分组后,对该组内首尾距离小于 50 米的线做合并。并完后人工抽查几个关键节点:青铜峡、三门峡、入海口。这几个位置如果没断,整条干流的连通性基本就保住了。
5.2 流域边界与入海口河网对不上
现象:HydroBASINS 边界在黄河入海口处明显偏西,河口三角洲大面积露在外面,河网裁剪后缺了东营以下河段。
原因:HydroBASINS 基于 DEM 提取,入海口三角洲地势平坦,水流方向在 DEM 上无法正确表达,分水岭边界比实际岸线缩水。
解决:手动修边界。用遥感影像或 OSM 海岸线选一个基准版本,把边界多边形在河口处沿实际岸线向外扩,把现代黄河入海河道包含进来。这个修正只需做一次,但必须记录在数据说明文件里,否则以后重新下载 HydroBASINS 会把错误带回来。
5.3 湖泊边界与河流重叠导致面积重复计算
现象:算黄河流域湖泊总面积时,结果比各湖泊单独统计的累加值明显偏大。
原因:河流双线河段被 HydroLAKES 识别成湖面,或者水库面与河道线未做空间擦除,同一水面在湖泊图层和河流图层各统计了一次。
解决:做一次湖泊图层与河网图层的空间擦除。把双线河道的面几何与湖泊面相交部分从湖泊面积中扣掉,或者按属性LAKE_TYPE过滤掉属于河道的类型。建议保留一个原始面积字段和一个扣减后的净面积字段,方便对账。这个坑如果不排掉,后续算蓄水量、水面蒸发量时会加倍放大误差。
5.4 面积量算数值离谱到难以交代
现象:用户拿数据统计黄河流域水面总面积,结果比官方公报数字大了近三成。
原因:数据在 EPSG:3857 下统计,严重的南北向拉伸导致高纬度地区面积虚高。黄河流域中段约 36°N,面积夸大系数已经在 1.3 到 1.5 之间。
解决:把统计图层投影到 Albers 等积投影(中央经线取 108°E,标准纬线取 32°N 和 40°N),用投影后的平面坐标算面积。所有面积字段在入库时就按等积投影计算完成,避免下游用户在错误投影下自行计算。
5.5 同名支流导致属性筛选串数据
现象:提取以“洛河”命名的支流,结果陕西的北洛河和河南的洛河被并到一条记录里,属性表里出现两条同名异源要素。
原因:中文河流重名普遍,黄河流域内部就有多条“洛河”“汾河”的二级支流,仅靠名称匹配必然混淆。
解决:匹配规则升级为“名称 + 子流域范围”双重条件。先按河流所在子流域边界分组,名称匹配只在同一子流域内部执行。同时保留原始要素的GID作为唯一关联键,避免合并时跨流域误连。此处没有捷径,踩过一次之后,我把所有河流名称匹配都改成“名称 + 空间范围 + 级序”三重校验。
6. 数据验证与进阶用法:我能反悔,但不能让数据对不上
数据集构建完成后,我习惯做三轮验证,缺一轮都不敢交付。第一轮是叠图抽查:把干流、支流、湖泊叠加到卫星影像或在线底图上,重点看河套段、渭河关中段、黄河入海口三条典型区域。第二轮是量化校验:用流域内河流总长度、湖泊总面积两个数值和公开的统计口径做量级对比,偏差超过 10% 就要回头查选型或拓扑问题。第三轮是交叉验证:把黄河干流提取结果连同 DEM 山体阴影叠在一起,用眼扫一遍河流是否贴合谷底线,这能发现 HydroRIVERS 在平原区那类“飞线”错误。
进阶用法方面,我推荐在数据集里增加一个version字段,每次从上游源更新数据时,只更新增量部分,同时记录批次号。这样下游拿到数据后可以随时溯源。如果你需要把这份数据集发布成服务,顺带导出一份 MBTiles 或矢量瓦片,做前端展示时效率会好很多。我做这套数据集时,最后一件事永远是重新打开一遍整个 GeoPackage,把每一层的属性表都点开看三行,确认没有空值、乱码、断线。数据这种东西,能不能让人放心用,不取决于当初处理得有多顺利,而取决于事后能不能复现、能不能解释、能不能修正。希望这份流程对你组装黄河流域基础数据集有用,也少走几趟我走过的弯路。
本文还有配套的精品资源,点击获取