简介:这份资源面向GIS初学者、地理科研人员及水文流域研究者,提供长江流域岷江、沱江水系的地形图与矢量数据,可直接在ArcGIS中打开使用。压缩包共63个文件,约42.74MB,包含shp、dbf、prj、shx等矢量图层文件,adf、nit、dat等栅格地形数据,以及mxd工程文件、xml元数据和jpg、pdf、eps三种出图成果,覆盖湖区、河流与90米DEM地形信息。对于不熟悉GIS操作的用户,可直接使用已生成的流域地形图图片;具备基础操作能力者则可通过mxd链接图层,一键完成出图与区域调整。目前已有1352人学习下载,适合用于流域分析、地形可视化、科研绘图与教学练习,能帮助读者快速获取岷沱江水系的空间数据基础,节省数据搜集与制图时间。
1. 岷江沱江流域地形图 shp 拿到手之后:先搞清楚它能干什么
岷江和沱江是长江上游两条并行的水系,岷江从松潘高原一路切到宜宾汇入长江,沱江则从九顶山南麓穿过成都平原在泸州注入长江。把这两条水系连同它们的流域边界做成 shp 格式的矢量地形图,本质上是在回答一个空间问题:这片约 13 万平方公里的土地上,分水岭在哪里、河网怎么分级、地形起伏跟水系发育是什么关系。很多人第一次拿到这类数据,第一反应是拖进 ArcGIS 看个热闹,结果发现属性表里字段看不懂、坐标系对不上、河流线跟流域面套不准。这篇东西就是把我自己处理岷江沱江流域 shp 的完整流程拆开讲——从数据检查、坐标系处理、地形因子提取,到裁剪、拓扑修复和出图,每一步都给出可复现的命令和参数。适合手里已经有或准备获取这套数据、需要在 ArcGIS 里做流域分析或专题制图的人,新手能跟着走完,熟手可以重点看避坑那章。
2. 岷江沱江 shp 的数据构成与 ArcGIS 加载前的检查
2.1 一套完整的流域地形图 shp 通常包含哪些图层
流域地形图 shp 不是单个文件,而是一组矢量图层的集合。以岷江沱江流域为例,常见的图层构成如下表。拿到数据后先对照这张表清点,缺哪个补哪个,不要急着做分析。
| 图层类型 | 几何类型 | 典型字段 | 用途 |
|---|---|---|---|
| 流域边界 | Polygon | BASIN_NAME, AREA_KM2 | 裁剪底图、统计面积 |
| 河网水系 | Line | STRAHLER, LENGTH | 分级渲染、流向分析 |
| 子流域分区 | Polygon | SUB_ID, UP_AREA | 分区统计、水文建模 |
| 地形等高线 | Line | ELEV, INDEX | 地形起伏表达 |
| 高程点 | Point | ELEV, X, Y | 插值生成 DEM |
| 行政边界 | Polygon | PROV, CITY | 叠加参考、出图标注 |
岷江和沱江在宜宾—泸州一带交汇区域,流域边界会有重叠或缝隙,这是最常见的拓扑问题来源。清点时重点看流域边界和子流域分区这两个面图层,它们决定了后续所有空间运算的准确性。
2.2 用 ArcGIS 加载 shp 并检查坐标系与属性完整性
加载 shp 本身很简单,但加载之后必须做三件事:确认坐标系、检查几何有效性、核对属性表。下面这段 Python 脚本基于 ArcPy,可以在 ArcGIS Pro 或 ArcMap 的 Python 窗口里直接跑,批量检查一个文件夹下所有 shp 的坐标系和几何状态。
# -*- coding: utf-8 -*- import arcpy import os # 修改为你的 shp 文件夹路径 workspace = r"C:\data\minjiang_tuojiang" arcpy.env.workspace = workspace # 遍历所有 shp 文件 for shp in arcpy.ListFiles("*.shp"): desc = arcpy.Describe(shp) sr = desc.spatialReference print("文件: {}".format(shp)) print(" 几何类型: {}".format(desc.shapeType)) print(" 坐标系: {} (WKID: {})".format(sr.name, sr.factoryCode)) # 检查几何有效性 check_result = arcpy.CheckGeometry_management(shp, "in_memory/check_" + shp) with arcpy.da.SearchCursor(check_result, ["PROBLEM"]) as cursor: problems = [row[0] for row in cursor] if problems: print(" 几何问题: {}".format(set(problems))) else: print(" 几何状态: 正常") # 统计要素数量 count = int(arcpy.GetCount_management(shp).getOutput(0)) print(" 要素数量: {}".format(count)) print("-" * 40)这段脚本的逻辑是:先通过Describe拿到每个 shp 的几何类型和坐标系 WKID,再用CheckGeometry_management把几何问题写到一个临时表里,最后用GetCount统计要素数。参数方面,workspace改成你自己的路径即可,in_memory是临时工作空间,不会在磁盘上留垃圾文件。如果输出里出现 WKID 为 0 或 Unknown,说明这个 shp 没有定义坐标系,需要先补上再往下做。
注意:岷江沱江流域常用的坐标系是 CGCS2000 地理坐标系(WKID 4490)或 CGCS2000 3 度带投影(如 WKID 4544 对应中央经线 102°E)。如果拿到的是 WGS84(WKID 4326),面积和长度计算会有偏差,必须先投影。
2.3 属性表字段的读取与筛选逻辑
属性表是 shp 的灵魂。以河网水系图层为例,STRAHLER字段表示斯特拉勒分级,值越小河流越大。用SearchCursor可以快速筛选出干流和一级支流:
import arcpy river_shp = r"C:\data\minjiang_tuojiang\river.shp" # 筛选 Strahler 分级小于等于 3 的河流 with arcpy.da.SearchCursor(river_shp, ["STRAHLER", "LENGTH", "SHAPE@LENGTH"]) as cursor: for row in cursor: strahler = row[0] length_attr = row[1] length_geom = row[2] if strahler is not None and strahler <= 3: # 对比属性长度和几何长度,差异过大说明投影有问题 if abs(length_attr - length_geom) > 100: print("长度异常: Strahler={}, 属性长度={:.1f}, 几何长度={:.1f}".format( strahler, length_attr, length_geom))这里的关键参数是SHAPE@LENGTH,它返回几何的实际长度(单位取决于坐标系)。如果属性表里的LENGTH字段和几何长度差了一个数量级,大概率是地理坐标系下计算的结果,需要投影后再重新计算。这个检查在岷江这种跨度大的流域尤其重要,因为经度方向一度对应的实际距离在高纬度会明显缩短。
3. 在 ArcGIS 里把岷江沱江 shp 用起来:裁剪、投影与地形因子提取
3.1 用流域边界裁剪河网与等高线
拿到全流域的河网和等高线后,第一步通常是按流域边界裁剪,去掉流域外的部分。ArcGIS 里用Clip工具,但参数设置有讲究。下面用 ArcPy 演示:
import arcpy arcpy.env.workspace = r"C:\data\minjiang_tuojiang" arcpy.env.overwriteOutput = True # 输入:河网线图层、流域边界面图层 river = "river.shp" basin = "basin_boundary.shp" out_river = "river_clipped.shp" # 裁剪:注意 cluster_tolerance 参数 arcpy.Clip_analysis(river, basin, out_river, cluster_tolerance="0.001 Meters") print("裁剪完成,输出: {}".format(out_river))Clip_analysis的第四个参数cluster_tolerance控制裁剪时的容差。对于岷江沱江这种地形复杂的区域,如果容差设得太大,河流线在边界处会出现明显的锯齿或断裂;设得太小又可能导致裁剪失败。我一般先用默认值跑一遍,如果边界处有毛刺,再调到 0.001 米重新跑。裁剪完成后,用GetCount对比裁剪前后的要素数,如果裁剪后要素数反而变多,说明河网在边界处被切成了很多碎线,需要后续用UnsplitLine合并。
提示:等高线裁剪后经常出现短小碎线,可以在属性表里按
SHAPE@LENGTH排序,删掉长度小于 50 米的线段,这些碎线在出图时基本看不见,但会拖慢渲染速度。
3.2 坐标系转换:从地理坐标到投影坐标的完整操作
岷江沱江流域跨了多个 3 度带,如果要做面积和长度统计,必须统一到一个投影坐标系。常见做法是选中央经线 102°E 或 105°E 的 CGCS2000 3 度带。在 ArcGIS 里用Project工具:
import arcpy arcpy.env.workspace = r"C:\data\minjiang_tuojiang" arcpy.env.overwriteOutput = True input_shp = "river_clipped.shp" # CGCS2000 3 度带 中央经线 102°E 对应的 WKID 是 4544 out_coordinate_system = arcpy.SpatialReference(4544) output_shp = "river_projected.shp" arcpy.Project_management(input_shp, output_shp, out_coordinate_system) print("投影完成: {}".format(output_shp))Project_management的第三个参数可以直接传SpatialReference对象,也可以传 .prj 文件路径。WKID 4544 对应的是 CGCS2000 3 度带第 34 带,中央经线 102°E,适合岷江上游和沱江大部分区域。如果数据延伸到 105°E 以东,可以改用 WKID 4545(中央经线 105°E)。投影之后,再用CalculateGeometryAttributes重新计算面积和长度字段,确保属性表里的数值和几何一致。
3.3 从等高线和高程点生成 DEM 并提取坡度坡向
地形图 shp 里的等高线和高程点是生成 DEM 的原料。ArcGIS 里用Topo to Raster工具,它比IDW或Kriging更适合等高线数据,因为能保证等高线不被穿越。操作步骤如下:
第一步,把等高线和高程点放在同一个要素数据集里,确保坐标系一致。第二步,在 ArcToolbox 里找到Spatial Analyst Tools > Interpolation > Topo to Raster。第三步,输入要素选等高线(字段选ELEV)和高程点(字段选ELEV),输出像元大小根据数据精度定,岷江沱江流域一般用 30 米。第四步,Drainage Enforcement选Enforce,这样生成的 DEM 会尊重河网位置,不会出现河流倒流。
import arcpy from arcpy.sa import * arcpy.CheckOutExtension("Spatial") arcpy.env.workspace = r"C:\data\minjiang_tuojiang" arcpy.env.overwriteOutput = True # 输入要素:等高线和高程点 contour = "contour.shp" spot = "spot_height.shp" out_dem = "dem_30m" # Topo to Raster 参数 arcpy.TopoToRaster_3d( in_features=[["contour.shp", "ELEV"], ["spot_height.shp", "ELEV"]], out_surface_raster=out_dem, cell_size=30, extent="basin_boundary.shp", margin=10, minimum_z_value=200, maximum_z_value=6000, drainage_enforcement="ENFORCE", profile_penalty=40, stream_penalty=0.5 ) print("DEM 生成完成: {}".format(out_dem))参数说明:cell_size=30对应 30 米分辨率;extent限定在流域边界内;minimum_z_value和maximum_z_value根据岷江沱江实际高程范围设定,岷江源头雪宝顶海拔约 5588 米,沱江下游河口约 200 米,所以设 200 到 6000 是合理的;drainage_enforcement="ENFORCE"强制 DEM 与河网一致;profile_penalty和stream_penalty控制地形平滑度和河流下切程度,默认值通常够用,如果生成的 DEM 在河谷处过于平坦,可以把stream_penalty调到 0.8 左右。
DEM 生成后,用Slope和Aspect工具提取坡度和坡向:
from arcpy.sa import Slope, Aspect dem = "dem_30m" slope = Slope(dem, "DEGREE") slope.save("slope_degree") aspect = Aspect(dem) aspect.save("aspect") print("坡度坡向提取完成")坡度输出用DEGREE单位,范围 0 到 90 度。坡向输出 0 到 360 度,正北为 0,顺时针增加。这两个栅格可以进一步和河网叠加,分析河流走向与坡向的关系。
4. 岷江沱江 shp 处理中的避坑与排查
4.1 坐标系不一致导致裁剪结果为空
现象:用流域边界裁剪河网,输出图层要素数为 0,或者裁剪结果跑到几千公里外。原因:两个图层的坐标系虽然都显示为 CGCS2000,但一个是地理坐标系(度),一个是投影坐标系(米),ArcGIS 在裁剪时不会自动转换,而是按数值直接运算。解决:先用Project把两个图层统一到同一个投影坐标系,再执行裁剪。检查方法是右键图层属性,看Source里的Spatial Reference是否完全一致,包括 WKID 和单位。
4.2 几何无效导致空间分析报错
现象:运行Intersect或Union时提示「几何无效」或「拓扑错误」。原因:shp 格式本身不支持真正的拓扑,面图层容易出现自相交、缝隙、重叠。岷江沱江流域边界在宜宾附近有多条支流汇入,边界线容易打结。解决:用RepairGeometry工具修复,或者用CheckGeometry先定位问题要素。修复后再跑一次CheckGeometry确认。如果修复后仍有问题,把问题要素导出到新 shp,手动编辑节点。
import arcpy arcpy.RepairGeometry_management("basin_boundary.shp") print("几何修复完成")4.3 属性表中文乱码
现象:属性表里的BASIN_NAME字段显示为乱码。原因:shp 的 .dbf 文件默认编码是系统区域设置,如果数据来自不同环境,中文可能被错误解码。解决:在 ArcGIS Pro 里可以用AlterField修改字段,但更稳妥的方法是用 Python 的dbfread库读取后重新写入。或者在 ArcMap 里通过Table to Table转换时指定编码。我一般会在拿到数据后先导出为 File Geodatabase 格式,GDB 对中文支持更稳定。
4.4 裁剪后河流线断裂
现象:裁剪后的河网在流域边界处变成很多短线段,无法做流向分析。原因:Clip工具会把跨越边界的线在边界处切断。解决:用UnsplitLine工具按河流名称或 ID 合并,或者改用Intersect工具并设置output_type为LINE。如果河流没有唯一 ID,可以先用Dissolve按STRAHLER字段合并,但这样会丢失单条河流的独立性。
4.5 投影后面积字段未更新
现象:投影之后,属性表里的AREA_KM2字段还是旧值,和几何面积对不上。原因:Project工具只改变几何坐标,不会自动重算属性字段。解决:用CalculateGeometryAttributes重新计算面积和长度字段。注意单位选择,投影坐标系下面积单位选SQUARE_KILOMETERS,长度选KILOMETERS。
import arcpy arcpy.CalculateGeometryAttributes_management( "basin_projected.shp", [["AREA_KM2", "AREA"], ["PERIM_KM", "PERIMETER"]], area_unit="SQUARE_KILOMETERS", length_unit="KILOMETERS" ) print("面积和周长字段已更新")5. 把岷江沱江 shp 做成可复用的地形分析模板
5.1 用模型构建器固化处理流程
每次拿到新的流域 shp 都手动跑一遍工具太累,ArcGIS 的模型构建器可以把上面这些步骤串起来。在 ArcMap 或 ArcGIS Pro 里打开ModelBuilder,依次拖入Project、Clip、TopoToRaster、Slope、CalculateGeometryAttributes,用连接线把输出连到下一个工具的输入。关键是把坐标系 WKID、像元大小、裁剪容差这些参数暴露为模型参数,这样换一个流域只需要改参数,不用重新搭流程。模型保存为.tbx工具箱,以后直接双击运行。
5.2 批量处理多个子流域的脚本写法
岷江沱江流域可以进一步分成多个子流域,如果每个子流域都要单独出图,用循环批量处理更高效。下面这段脚本遍历子流域面图层,逐个裁剪 DEM 并计算平均坡度:
import arcpy from arcpy.sa import * import os arcpy.CheckOutExtension("Spatial") arcpy.env.workspace = r"C:\data\minjiang_tuojiang" arcpy.env.overwriteOutput = True sub_basins = "sub_basin.shp" dem = "dem_30m" slope = "slope_degree" out_folder = r"C:\data\minjiang_tuojiang\sub_output" if not os.path.exists(out_folder): os.makedirs(out_folder) # 遍历每个子流域 with arcpy.da.SearchCursor(sub_basins, ["SUB_ID", "SHAPE@"]) as cursor: for row in cursor: sub_id = row[0] geom = row[1] # 用子流域几何裁剪 DEM dem_clip = ExtractByMask(dem, geom) dem_clip.save(os.path.join(out_folder, "dem_sub_{}.tif".format(sub_id))) # 裁剪坡度并计算平均值 slope_clip = ExtractByMask(slope, geom) mean_slope = arcpy.GetRasterProperties_management(slope_clip, "MEAN") print("子流域 {}: 平均坡度 = {:.2f} 度".format(sub_id, float(mean_slope.getOutput(0))))这段脚本的核心是ExtractByMask,它按几何范围裁剪栅格。SUB_ID是子流域的唯一标识,用来命名输出文件。GetRasterProperties_management的MEAN参数返回栅格平均值。跑完之后,每个子流域的 DEM 和平均坡度就都有了,可以直接拿去做水文分析或制图。
5.3 出图时的符号化与标注技巧
最后一步是出图。河网用STRAHLER字段做分级渲染,值越小线越粗。流域边界用空心填充加粗边框。等高线只显示计曲线(INDEX字段为 1 的),首曲线太密会糊成一片。标注用Maplex引擎,河流名称沿河流方向放置,流域名称放在面中心。出图分辨率至少 300 dpi,岷江沱江流域全图用 A1 幅面比较合适。
我自己的习惯是,每次处理完一套流域 shp,都会把坐标系、投影参数、裁剪容差、DEM 像元大小这几个值记在一个文本文件里,下次换流域直接改这几个数。这套流程在岷江沱江上跑通之后,换成嘉陵江或乌江,基本只需要改 WKID 和裁剪范围。希望帮到你。
本文还有配套的精品资源,点击获取