名称:giuh-arcgis-extraction 描述:> 用于构建、运行、调试或打包 ArcGIS 10.6(Python 2.7)地貌瞬时单位线(GIUH)工具箱:DEM -> 河网 与流域提取(Strahler)-> 交互式出口点选择 -> Horton 比率(R_B/R_L/R_A)-> GIUH 概率密度(超指数分布)-> 等效 Nash 单位线 -> 时段单位线(DUH)。涵盖 GIUH 特定的 代码模式(py2.7 安全的 CSV/JSON/matplotlib 写入、无 numpy 的带状 统计、子流域栅格掩膜提取)以及打包 3 文件工具箱。搭配 技能 arcgis10x-py27-compat 适用于通用 ArcGIS 10.x Python 2.7 陷阱。 agent_created: true
GIUH 提取工具箱(ArcGIS 10.6 / Python 2.7)
本技能记录了在 ArcGIS 10.6 Desktop(Python 2.7,Spatial Analyst)内从 DEM 生成地貌单位线的经过验证的工作流程和来之不易的经验。该工具包位于项目工作区中,是一个3 文件自包含工具箱,可复制到任何 ArcGIS 10.6 机器。
通用 ArcGIS 10.x / Python 2.7 兼容性陷阱(全角字符、 ImageServer 999999、红叉、ZonalStatisticsAsTable
MAXIMUM、数据类型关键字) 由技能arcgis10x-py27-compat涵盖。本技能仅涵盖 GIUH 领域的工作流程和 GIUH 特定的 py2.7 代码模式。如果您遇到通用的 ArcGIS 错误,请先阅读该技能。
1. 工具箱文件结构(3 文件包)
| 文件 | 作用 |
|---|---|
watershed_uh_toolbox.pyt |
工具箱入口。ArcGIS“添加工具箱”指向此处。 |
arcgis_uh_workflow.py |
流程:DEM -> 河网 -> 子流域 -> 统计。 |
giuh_calculator.py |
纯 stdlib GIUH 数学引擎(无需 numpy)。 |
导入链是路径无关的:每个模块通过 os.path.dirname(os.path.abspath(__file__)) 将自己的目录插入 sys.path,因此三个文件必须放在同一文件夹,但可以位于磁盘上的任何位置。可选文档:
README_watershed_uh.md。matplotlib 可选(仅 PNG);缺失时会优雅降级(_HAVE_MPL=False 跳过绘图)。
两个工具:
DEMHydrologyExtraction(类DEMHydrologyExtraction)-> 包装arcgis_uh_workflow.extract_network。InteractiveOutletUnitHydrograph(类InteractiveOutletUnitHydrograph)-> 包装arcgis_uh_workflow.run_outlet_and_uh。
2. 工作流程
工具 1 — extract_network(dem, out_ws, threshold=1000, out_name="hydro", ...)
(DEM -> 河网 + 流域):
Fill->FlowDirection(fill, "NORMAL")->FlowAccumulation(flow_dir)。StreamOrder(link_ras, flow_dir, "STRAHLER")->order_ras。- 输出最高 Strahler 级河流图层(供用户选择出口点)+ 一个
hydro_meta.json(像元大小、最高级、空间参考、路径)。 所有栅格输出使用.tif(ESRI GRID 有 13 字符基名限制;hydro_strahler= 14 字符 ->ERROR 010240)。
工具 2 — run_outlet_and_uh(meta_json, pour_features, velocity=None, slope=None, ...)
(交互式出口点 -> 子流域 -> 单位线):
- 用户提供一个点 shapefile 作为出口点(
pour_features)。 (为什么用 shapefile 而不是交互式草图图层:见陷阱 6。) SnapPourPoint(pour_features, flow_acc, snap_dist)(snap_dist = 5 * cell)。Watershed(flow_dir, snapped_pour)->subbasin.shp。- 使用
ExtractByMask将所有栅格(flowacc、dem、flowdir、strahler、link、stream)裁剪到子流域,然后再进行任何统计(见陷阱 2)。 - 不使用 numpy 的统计(陷阱 1):用
ZonalStatisticsAsTable得到 link->order 映射和每个 order 的流量累积均值;用SearchCursor统计河流数量/长度;用GetRasterProperties(flowlen, "MAXIMUM")得到最长流路L_Omega。 compute_horton_ratios(orders)->R_B, R_L, R_A;从L_Omega和坡度estimate_velocity;build_giuh+export_results-> CSV + JSON + PNG。
3. GIUH 数学 API(giuh_calculator.py)
输入 orders = 字典列表:{"order": int, "n": float(河流数), "length": float(km), "area": float(km^2)}。
compute_horton_ratios(orders)->(R_B, R_L, R_A, diag)(几何均值)。estimate_velocity(length_km, slope)->v(m/s)基于sqrt(g*L*S)风格。giuh_pdf(orders, velocity, t, length_unit="km")-> 超指数 PDF。 返回密度单位为 s⁻¹。 组装时间序列时必须乘以sec_per(小时为 3600),否则坐标值会偏差该因子 (仅修复后∫h dt ≈ 0.9995)。giuh_moments(orders, velocity, length_unit="km")->(mean, var)。equivalent_nash(mean, var)->(n, k)水库(n = mean²/var, k = var/mean)。nash_iuh(t, a, k)/nash_duh(t, a, k, D)-> Nash IUH 和时段-UH(DUH 通过归一化下不完全伽马函数;无需 scipy)。build_giuh(orders, velocity, length_unit="km", time_unit="h", ...)-> 网格字典 (t, h, u, cum_h, cum_u, nash_n, nash_k_out)。export_results(orders, velocity, length_unit="km", time_unit="h", out_dir, D=None, make_plot=True, basename="unit_hydrograph")->{"csv", "json", "png"}。 CSV 表头为中文(时间(h)、GIUH瞬时单位线(1/h)、…);JSONsummary有中文note字段(py2.7 安全)。
可复用的 py2.7 安全 I/O 助手(照抄即可):
_write_text(path, text)— py3io.open(encoding="utf-8");py2open(path,"wb").write。_to_unicode(obj)— 递归将 py2str(bytes) 解码为unicode;py3 无操作。_open_csv_writer(path)— py3io.open(path,"w",newline="",encoding="utf-8-sig")(BOM 用于 Excel);py2io.open(path,"wb")(二进制)。返回(f, w)。_csv_row(writer, cells)— py2:在writer.writerow之前将每个单元格编码为utf-8字节;py3:直接写入。
4. GIUH 特定的 ArcGIS 10.6 / Python 2.7 陷阱(不在 arcgis10x-py27-compat 中)
-
ArcGIS 10.6 Python 2.7 默认没有 numpy。 切勿使用
RasterToNumPyArray进行 Horton 统计——它会静默产生全零 面积并导致compute_horton_ratios崩溃(几何均值需要正值)。 全部使用纯 ArcGIS 做统计:ZonalStatisticsAsTable、GetRasterProperties、SearchCursor。 -
掩膜一致性。 当组合多个栅格(例如 strahler vs flowacc vs 子流域)时,首先用
ExtractByMask将它们都 裁剪到同一子流域范围。范围不匹配会产生静默的全零面积——正是引起R_A几何均值崩溃的 bug。 -
py2.7 下的 CSV 写入。 使用 §3 中的
_open_csv_writer/_csv_row。 模式:f, w = _open_csv_writer(p); try: _csv_row(w, row) finally: f.close()。 不要写with _open_csv_writer(p) as (f, w):——返回的元组不是 上下文管理器 ->AttributeError: __exit__。py_compile不会捕获此错误; 运行导出路径验证。 -
py2.7 下的 JSON 写入。 调用
json.dumps(_to_unicode(summary), ensure_ascii=False, indent=2)。任何不是u"..."的中文字符串字面量在 py2.7 中是 UTF-8 字节str,会使json.dumps(ensure_ascii=False)抛出UnicodeDecodeError。切勿裸用json.dumps(obj)。 -
matplotlib 中文标签。 导入
matplotlib后设置matplotlib.rcParams["font.sans-serif"] = ["SimHei","Microsoft YaHei","SimSun", "FangSong","KaiTi",...]和matplotlib.rcParams["axes.unicode_minus"]=False。 传递给 pyplot 的每个 label/title/xlabel/ylabel 必须是u"..."(unicode), 否则set_label内部的'%s' % s会对字节字符串进行 ascii 解码并抛出UnicodeDecodeError。缺少 CJK 字体会显示方框(不会崩溃)。后端已经是Agg(仅文件,无 GUI)。 -
交互式出口点草图图层在 10.6 上已损坏。
GPFeatureRecordSetLayer悬停光标一直是手形(永远不会变成十字准线),即使设置了schema.featureType="Simple"/hasZ=False/hasM=False。修复:将出口点 参数设为GPFeatureLayer并过滤为Point;用户创建一个 1 点 shapefile(与 DEM 相同的坐标系!)并选择它。将点放在最高级河流图层上或旁边(捕捉距离 ≈ 5 个像元)。 -
GRID 13 字符限制 -> 始终输出
.tif栅格(见 §2 工具 1)。 -
模块编辑后需完全重启 ArcMap。
arcgis_uh_workflow.py和giuh_calculator.py由.pyt懒加载并缓存在sys.modules中。编辑它们后,仅刷新工具箱是不够的—— 必须完全关闭并重新打开 ArcMap。(同时禁用后台地理处理以避免 旧模块 / ImageServer 999999 问题;见 arcgis10x-py27-compat 陷阱 7。)
5. 部署打包
将 3 个核心文件(watershed_uh_toolbox.pyt、arcgis_uh_workflow.py、
giuh_calculator.py)+ README_watershed_uh.md 复制到一个文件夹中,压缩,部署
到目标机器,然后“添加工具箱” .pyt。保持它们在一起。不需要
外部 Python 包(matplotlib 可选)。已构建的
分发包位于工作区的 GIUH_Toolbox_Dist/。
6. 快速诊断
如果工具 2 中途失败,回溯前的最后几行 arcpy.AddMessage 会告诉您哪个阶段出错(SnapPourPoint / Watershed / 统计 / GIUH 导出)。
大多数剩余失败来自上述 py2.7 编码陷阱(CSV/JSON/matplotlib)
或 numpy/ZonalStatistics 替换(陷阱 1)。应用相应修复并完全重启 ArcMap 后重新运行。