多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ArcGIS Pro内置Jupyter环境配置、arcpy报错排查与面积统计实战

ArcGIS Pro内置Jupyter环境配置、arcpy报错排查与面积统计实战 简介面向ArcGIS Pro用户与GIS开发者的项目源码包聚焦在ArcGIS Pro中快速启用Jupyter Notebook并自定义工作目录。资源定位清晰适合希望用Python/ArcPy提升空间数据处理效率的初中级GIS人员。压缩包内共3个文件包含inscode启动配置、html说明页面及.gitignore工程管理文件整体仅4KB轻量易用。借助此源码包可了解到默认文件保存于C:\Users\admin的问题通过生成配置文件并修改c.NotebookApp.notebook_dir永久固定工作目录或直接从ArcGIS Pro的Python环境打开Notebook到指定目录。由于源码极小重点在于配置思路与起点模板适合作为个人环境参考或教学演示已有95人浏览学习内容精炼便于快速上手。 以前总有同行问我我电脑上装了Anaconda为什么在 Jupyter 里 import arcpy 死活不成功这个问题我一开始也答不明白直到被项目里一次数据批处理逼着翻了小半天的文档才彻底想明白一个事——ArcGIS Pro 自己就带了一套完整的 Python 环境和 Jupyter Notebook压根不需要你在外面再搭一套环境去迁就 arcpy。这篇文章就围绕 ArcGIS Pro Jupyter Notebook 这套组合把环境怎么配、安装遇到报错怎么排、一个常用的面积统计需求怎么写、以及最后怎么把 Notebook 整理成能反复用的项目源码一次讲透。1. 为什么我坚持用 Pro 自带的 Notebook而不是单独装 Jupyter1.1 环境一体化的价值不折腾才是最大的效率很多人觉得 Jupyter 就是个写 Python 的网页编辑器随便装一个就行。但在 ArcGIS Pro 的场景里这个想法会带来一堆连锁麻烦。ArcGIS Pro 安装完之后会在你的电脑上自动创建一个由 conda 管理的 Python 环境默认名字是arcgispro-py3。arcpy 这个核心库已经装在里面了而且和 Pro 的版本严格绑定。你如果在外面单独装了 Anaconda就算用 pip 强行安装某个名称相近的包最终 import 的时候大概率还是告诉你找不到模块或者找到了却因为底层动态库版本对不上而直接崩溃。所以我的建议很直接不要再单独折腾一套 Python 环境直接用 Pro 内置的 Notebook。打开 Pro 之后在“分析”选项卡里点一下“Python”就能启动一个绑定到当前项目环境的 Notebook也可以在开始页里直接新建。这个 Notebook 用的解释器就是arcgispro-py3环境arcpy、pandas、numpy、matplotlib 这些常用的库都是预装好的直接就能用不需要任何额外配置。用这套组合处理数据时我可以直接在单元格里写arcpy.management.CopyFeatures(rC:\data.gdb\地块, rC:\data.gdb\地块_备份)跑完马上看结果再回到 Pro 地图里刷新一下图层修改立刻可见。整个过程不需要切窗口、不需要手动刷新、不需要在几个工具之间来回点。1.2 Notebook 能替代传统工作流的三个典型场景我自己用下来Notebook 真正体现出压倒性优势的是下面三类工作。第一类是批量数据处理前的探索性检查。传统方式是你可能要先在目录里找数据用“属性表”看一眼字段再用工具箱跑一遍工具发现报错再回去改。Notebook 的好处是数据和代码放在同一个流程里你可以一条命令把要素类的属性全部读成 pandas 的 DataFrame然后直接打印、切片、统计快速发现问题。第二类是需要把处理逻辑讲给别人的场景。Notebook 天然支持 Markdown 和代码混排你可以在这个单元格下面写一句“为什么这里要转成投影坐标系”在下一个单元格里写代码。给领导汇报或者给同事交接的时候一个.ipynb文件就相当于一份可执行的说明文档。第三类是和 Pro 项目文件联动的场景。Notebook 里可以直接用arcpy.mp.ArcGISProject打开当前项目修改地图文档里的图层符号、布局元素甚至批量导出地图。比如我有一个项目需要把几十个行政区分别出一张图之前手动出了一下午后来用 Notebook 写了个循环从图斑属性里逐个读取名称更新布局里的标题文本一键导出 PDF十分钟搞完。注意Notebook 适合做过程探索和结果展示不适合长时间跑的大规模处理。如果你要跑一个几十 G 数据的批量裁剪最好还是把逻辑整理成一个独立的.py脚本去运行而不是在 Notebook 里挂着这个我们第 4 节会专门讲。2. 环境配置与两个高频报错的完整排雷2.1 先确认你的版本和 Python 环境ArcGIS Pro 从 2.x 到 3.x内置的 Python 版本一直在变。Pro 2.9 对应 Python 3.7Pro 3.0 开始对应 Python 3.9到了 Pro 3.2 之后的版本也基本维持在 3.9 或更高。这个版本信息看起来没什么用但当你遇到 pip 安装报错的时候它就变成了排查问题的第一步依据。想在 Notebook 里装新包的时候注意不要直接在 Notebook 的单元格里用!pip install 包名这种方式。偶尔装个纯 Python 的小包没问题但遇到下面要说的subprocess-exited-with-error报错多半就是这个操作引起的。最稳的做法是在 Windows 开始菜单里找到Python Command Prompt安装 Pro 时自带的那个在那个终端里先执行conda activate arcgispro-py3然后用conda install 包名或者pip install 包名安装包装完再回到 Notebook 重启内核。2.2 subprocess-exited-with-error多半不是 pip 的锅这个报错文案经常长这样ERROR: pips dependency resolver does not currently take into account all the packages that are installed... Running command pip subprocess to install build dependencies did not run successfully. exit code: 1 subprocess-exited-with-error我第一次遇到时以为是 pip 坏了重装了半天后来才明白真正的原因是你在arcgispro-py3这个环境里尝试用 pip 安装一个需要编译的包比如 gdal、rasterio、scipy 这类带 C/C 扩展的库而当前环境缺少对应的编译工具链或者包的版本和 Python 版本不兼容。处理办法分两步优先用conda install从 conda 源安装因为 conda 的包是预编译好的不需要现场编译。如果必须用 pip先确认包版本是否支持当前 Python 版本。比如 Python 3.9 下就不要尝试安装只支持 3.10 以上的最新版 scipy把版本指定为scipy1.10.0这类兼容版本往往能解决问题。还有一个非常隐蔽的原因当前目录下恰好有一个和你要安装的包同名的.py文件比如你要装一个叫demo的包而工作目录里有个demo.pypip 在构建过程中被这个文件干扰也可能触发类似问题。遇到奇葩报错时换个干净的目录再试一次往往就正常了。2.3 Notebook 无法打开和运行的排查清单Notebook 打不开或者运行不了这是群里被问得最多的一类问题我把几个常见原因按排查顺序整理一下你可以照着查。现象可能原因处理方式打开 Notebook 后一直转圈不出来默认端口 8888 被占用打开arcgispro-py3环境的终端输入jupyter notebook --port8890换个端口启动可以新建文件但运行单元格报Kernel error内核配置损坏或环境路径变动执行jupyter kernelspec list查看内核路径是否正确不对就重新执行python -m ipykernel install --user --name arcgispro-py3重装内核运行代码卡在In [*]状态上一次运行没结束内核崩溃菜单 Kernel - Restart实在不行就重启 Pro打开.ipynb文件报Unreadable Notebook文件是旧版格式或已损坏换用jupyter nbconvert --to notebook --stdin --output 文件名.ipynb 文件名.ipynb尝试转换修复Notebook 能打开但无法访问本机文件权限不足以管理员身份运行 Pro或给数据目录加上当前用户的读写权限这里再额外提醒一句如果你的电脑上同时装了 Anaconda 和 ArcGIS Pro不要在 Anaconda 的 Jupyter 里尝试 import arcpy。两个环境的包管理是独立的硬混在一起只会让两边都出问题。老老实实从 Pro 里打开 Notebook省心得多。3. 面积统计保留两位小数一个需求教你串起整个 Notebook 流程热搜词里有“arcgis pro 面积统计 只保留小数点后两位”这个需求看起来简单实际做的时候有个很容易忽略的坑。我先说结论在 Notebook 里处理这类统计需求核心不是round()那一步而是搞清楚你要修改的是“显示精度”还是“存储精度”。3.1 为什么不能只写一行 round()如果你只是想在表格里看到两位小数直接在 Pro 的字段上设置数字格式就够不用改数据。但如果你的目标是把面积字段变成真正的小数点后两位数值再导出给其他系统用那就要在数据层面处理。这里有个底层知识点计算机里的浮点数是用二进制表示的0.1 0.2的结果并不是0.3而是一个非常接近的浮点数。所以你直接对面积字段做round()得到的数值可能在打印时显示两位但底层依然带着浮点噪声。如果后续再对这个字段做汇总计算这些噪声会累积最后结果出现莫名其妙的几分钱误差。3.2 三种实现路径与选择逻辑我实际处理过这个需求可以给你三种路径按场景选只在显示层面修改在 Pro 的图层属性 - Fields 里找到面积字段设置 Number Format 为保留两位小数。这种改法最快但不会修改底层数据导出的数据该多少位还是多少位。用字段计算或 UpdateCursor 改数据直接用arcpy.management.CalculateField对目标字段重新赋值。适合数据量不大、需要持久化修改的场景。用 pandas 格式化输出把要素类读成 DataFrame用round(2)处理然后导出 CSV 或 Excel。适合做统计分析和报表输出的场景不改原始数据。我个人最推荐第三种因为它在 Notebook 工作流里最顺手。下面是一段可以直接复制运行的示例代码。3.3 完整示例代码可直接复制路径一改就能跑import arcpy import pandas as pd # 配置工作空间和数据路径 gdb rC:\Projects\LandUse.gdb fc gdb r\Parcels arcpy.env.workspace gdb # 读取要素类属性到 DataFrame fields [OBJECTID, LandUse, Shape_Area] data [] with arcpy.da.SearchCursor(fc, fields) as cursor: for row in cursor: data.append(row) df pd.DataFrame(data, columnsfields) # 检查 Shape_Area 的坐标系单位 desc arcpy.Describe(fc) sr desc.spatialReference print(f坐标系名称: {sr.name}) print(f线性单位: {sr.linearUnitName})运行到这里如果你看到线性单位是Meter那面积就是平方米可以直接用。如果看到是Degree说明这个面数据是地理坐标系算出来的 Shape_Area 单位是平方度没有任何实际意义必须先投影转换。# 如果是以度为单位的地理坐标系先投影到米制投影坐标系 # 这里简单判断如果不是米制单位就投影到 Albers 等面积投影 if sr.linearUnitName ! Meter: out_fc gdb r\Parcels_Projected arcpy.management.Project(fc, out_fc, arcpy.SpatialReference(5070)) # 5070是NAD83 Albers fc out_fc # 重新读数据 data [] with arcpy.da.SearchCursor(fc, fields) as cursor: for row in cursor: data.append(row) df pd.DataFrame(data, columnsfields) # 保留两位小数并生成统计表 df[Shape_Area_2] df[Shape_Area].round(2) # 按用地类型汇总面积 summary df.groupby(LandUse)[Shape_Area_2].sum().reset_index() summary.columns [LandUse, Area_Sum] # 导出到工作空间内的表格 out_table gdb r\Area_Summary if arcpy.Exists(out_table): arcpy.management.Delete(out_table) summary.to_csv(rC:\Projects\outputs\area_summary.csv, indexFalse, encodingutf-8-sig) # 查看结果 print(summary.head(10))这段代码里有两个细节值得记住一是encodingutf-8-sig这样导出的 CSV 用 Excel 打开时中文不会乱码二是投影坐标系用了arcpy.SpatialReference(5070)这是北美常用的等面积投影国内场景可以换成 CGCS2000 的等面积投影比如 Albers 双标准纬线单位同样是米不影响面积计算逻辑。到这里你可能会问round(2)不是刚才说底层有浮点噪声吗确实有。所以如果对精度有严格要求的场景更稳的做法是转成数值型 Decimal或者干脆用df[Shape_Area_2] df[Shape_Area].round(2).astype(float64)先 round 再转一次类型把参与后续计算的值的精度压到可控范围。实际交付报表时这种做法完全够用。4. 把临时探索整理成项目源码的目录思维标题里带着“项目源码”三个字很多人可能以为源码就是能跑的代码。但在 GIS 数据分析这个领域一套真正能交付、能复现、能交接的项目源码三分是代码七分是目录和流程设计。我见过太多 notebook 文件代码写得天花乱坠但路径写死、变量命名随意、没有任何中间产物说明三个月后自己都看不懂。4.1 一个可以“抄作业”的目录结构我现在做项目基本固定用下面这套结构project_root/ ├── data/ │ ├── raw/ # 原始数据只读不写 │ ├── intermediate/ # 中间处理结果 │ └── final/ # 最终交付数据 ├── scripts/ # 可复用/可执行的py脚本 ├── notebooks/ # 按顺序编号的notebook │ ├── 01_explore.ipynb │ ├── 02_clean.ipynb │ └── 03_analysis.ipynb ├── outputs/ │ ├── tables/ # 统计表格 │ └── maps/ # 导出的地图 └── config.yaml # 全局配置路径参数都放这里为什么要把脚本和 notebook 分开因为 notebook 适合探索和展示但它不适合被其他程序引用。如果你在 notebook 里定义了一个函数另一个脚本想调用import 一个 .ipynb 文件是很别扭的事情。更合理的方式是在 notebooks 里写过程、做验证在 scripts 里放真正可以被调用的函数和类两边都舒服。4.2 从 Notebook 到可维护脚本的封装技巧拿第 3 节的面积统计代码举例如果这只是项目里的一小块处理我不会让它一直躺在 notebook 里。我会把它抽成scripts/calc_area.py里的一个函数# scripts/calc_area.py import arcpy import pandas as pd from pathlib import Path def feature_class_to_dataframe(fc, fields): 将要素类读取为DataFrame返回数据和空间参考名称 data [] with arcpy.da.SearchCursor(fc, fields) as cursor: for row in cursor: data.append(row) return pd.DataFrame(data, columnsfields) def export_area_summary(gdb, fc_name, landuse_field, out_csv): 计算面积汇总并导出CSV fc str(Path(gdb) / fc_name) desc arcpy.Describe(fc) sr desc.spatialReference if sr.linearUnitName ! Meter: out_fc str(Path(gdb) / (fc_name _Projected)) arcpy.management.Project(fc, out_fc, arcpy.SpatialReference(5070)) fc out_fc df feature_class_to_dataframe(fc, [OBJECTID, landuse_field, Shape_Area]) df[Shape_Area_2] df[Shape_Area].round(2) summary df.groupby(landuse_field)[Shape_Area_2].sum().reset_index() summary.columns [landuse_field, Area_Sum] Path(out_csv).parent.mkdir(parentsTrue, exist_okTrue) summary.to_csv(out_csv, indexFalse, encodingutf-8-sig) return summary这样封装之后你在 notebook 里调用就只需要一行from scripts.calc_area import export_area_summary result export_area_summary(rC:\Projects\test.gdb, Parcels, LandUse, rC:\Projects\outputs\area_summary.csv)好处很明显函数逻辑可以被复用、测试不会被 notebook 里各种临时变量干扰另外路径作为参数传进来换项目时不用改函数体只改调用处。4.3 数据质量检查真正让项目能交付的环节很多人拿到源码跑一遍看到输出没有报错就算完事。但在 GIS 项目里“没报错”和“结果正确”之间差着一整套数据检查。我在 Notebook 工作流里给自己定了一条规则每次数据处理结束后必须做 4 项检查缺一不可。要素类是否为空用arcpy.management.GetCount确认记录数特别是裁剪、相交、投影这种会产生新要素类的操作结果为空往往说明源数据范围不对。字段值是否有空值用arcpy.analysis.Frequency或 pandas 的isna().sum()检查关键字段。面积总量是否合理投影前和投影后总面积误差应该控制在 0.1% 以内如果误差超过这个数说明投影参数或字段选择有问题。空间参考是否和项目要求一致交付的要素类坐标系必须是项目约定好的不是源数据自带什么就是什么。第 3 节代码里的投影判断本质上就是第二项检查的自动化。把这类检查写进你的源码项目里别人拿到手跑出来心里才有底。另一个实用技巧是在 notebook 的每个关键步骤后加一行print(f当前记录数: {arcpy.management.GetCount(fc)})或类似的输出。整个流程跑完滚动日志就能看出每一步的数据量变化排查问题会快很多。5. 功能和场景扩展别把 Notebook 只当成写代码的地方5.1 在线底图与三维数据的 Notebook 玩法ArcGIS Pro 的 Notebook 不只是处理属性表的工具它还可以通过arcpy.mp模块直接操作项目里的地图文档。比如你想给当前项目换一套在线底图在 Notebook 里可以直接写import arcpy aprx arcpy.mp.ArcGISProject(rC:\Projects\MyProject.aprx) m aprx.listMaps()[0] m.addBasemap(Imagery) # 添加影像底图 aprx.save() print(底图已更新)这段代码在做什么不用我解释你也能看出来它打开项目文件、找到第一个地图、添加底图、保存。如果你的项目有几十个地图页面需要挨个调整底图样式或者更新数据源手工操作点一天都不一定点完用这个逻辑写个循环几分钟就搞定。三维数据也是一样。Pro 里加载了 Scene Layer 或 3D 对象要素之后可以用arcpy.ddd相关的工具在 Notebook 里做读取和转换。当然三维数据的底层处理逻辑比二维要复杂得多我更建议在 Notebook 里做的只是“读取、统计、预处理”这类轻操作真正的建模计算可以放到 Pro 的现有工具链里去跑。5.2 从 Notebook 到批处理脚本脱离交互界面跑必须认清一点Notebook 是给人看的不是给电脑看的。当你的处理流程稳定下来需要每天定时跑的时候正确做法是把它导出成.py脚本用 Windows 计划任务定时执行。具体操作是在 notebook 里点击 File - Export as - Python file导出的.py文件里会保留所有代码但 Markdown 部分会变成注释。然后你在命令行执行python scripts/area_batch.py执行前记得做两件事把路径全部改成参数或配置文件读取以及加一段日志输出。我习惯用 Python 自带的logging模块把处理过程中每个阶段的耗时和结果写进日志文件这样就算夜里定时任务跑挂了第二天早上看日志就能定位问题不需要重新跑一遍。还有一个容易被忽略的点导出后的脚本要用arcgispro-py3环境的 python 去执行而不是系统默认的 python。在命令行里先执行conda activate arcgispro-py3再运行上面的命令否则大概率会报模块找不到。把我这几年的实际体会放在最后说一句ArcGIS Pro 里的 Notebook 和单独的 Jupyter 不是竞争关系而是各管一段。你自己写点小探索、做交互分析用 Pro 内置的 Notebook 很方便但一旦流程固定下来要被反复执行就果断把它抽成独立脚本放进项目目录里。这两个习惯养成之后同样的工作量能省下两倍不止的时间。本文还有配套的精品资源点击获取
返回列表