简介:面向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,而不是单独装 Jupyter
1.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(r"C:\data.gdb\地块", r"C:\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.7,Pro 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: pip's 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,把版本指定为
scipy==1.10.0这类兼容版本往往能解决问题。
还有一个非常隐蔽的原因:当前目录下恰好有一个和你要安装的包同名的.py文件,比如你要装一个叫demo的包,而工作目录里有个demo.py,pip 在构建过程中被这个文件干扰,也可能触发类似问题。遇到奇葩报错时,换个干净的目录再试一次,往往就正常了。
2.3 Notebook 无法打开和运行的排查清单
Notebook 打不开或者运行不了,这是群里被问得最多的一类问题,我把几个常见原因按排查顺序整理一下,你可以照着查。
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 打开 Notebook 后一直转圈不出来 | 默认端口 8888 被占用 | 打开arcgispro-py3环境的终端,输入jupyter notebook --port=8890换个端口启动 |
可以新建文件,但运行单元格报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 = r"C:\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, columns=fields) # 检查 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, columns=fields) # 保留两位小数并生成统计表 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(r"C:\Projects\outputs\area_summary.csv", index=False, encoding="utf-8-sig") # 查看结果 print(summary.head(10))这段代码里有两个细节值得记住:一是encoding="utf-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, columns=fields) 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(parents=True, exist_ok=True) summary.to_csv(out_csv, index=False, encoding="utf-8-sig") return summary这样封装之后,你在 notebook 里调用就只需要一行:
from scripts.calc_area import export_area_summary result = export_area_summary(r"C:\Projects\test.gdb", "Parcels", "LandUse", r"C:\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(r"C:\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 很方便;但一旦流程固定下来要被反复执行,就果断把它抽成独立脚本,放进项目目录里。这两个习惯养成之后,同样的工作量能省下两倍不止的时间。
本文还有配套的精品资源,点击获取