JupyterGIS 是面向 Jupyter 环境的 GIS 扩展。0.16 版本把重点放在协作、实时编辑、大规模数据处理与遥感场景上,同时改进可视化能力并扩大对 R 用户的兼容性。这些变化的价值不只是“在 Notebook 里多一张地图”,而是让数据、样式、分析代码和协作过程进入同一个可复现工作空间。
声明式符号系统为什么重要
传统 GIS 项目常把图层样式封装在桌面软件的项目文件或用户界面状态中。地图可以正常显示,但颜色、分类阈值和透明度为何如此设置,往往很难通过代码审查。
声明式符号系统把地图表现转化为结构化配置。例如,一个土地覆盖图层可以明确记录:
- 哪个属性参与分类;
- 每个类别对应什么颜色;
- 图层透明度和显示顺序;
- 缺失值采用什么回退样式。
这种表示方式适合放入 Git,也更容易进行差异比较、复用和自动生成。JupyterGIS 0.16 对可视化与声明式工作流的强化,使地图样式更接近分析项目中的正式产物,而不是某位操作者电脑上的临时状态。
社区对可移植性的关注也说明了边界:声明式并不自动等于跨工具兼容。字段类型、颜色表达、分类算法以及坐标参考系仍可能被不同客户端解释得不一致。团队需要同时版本化数据模式和样式配置,并在目标运行环境中验证结果。
实时协作改变了什么
Notebook 协作过去经常停留在“共享代码”层面,地图编辑则通过截图、导出文件或口头说明传递。实时编辑把图层选择、视图调整和地图修改带入协作会话,适合数据核验、遥感判读和多人制图。
但多人同时操作也会引入新的工程问题:
- 哪些改动属于分析结果,哪些只是个人视图状态;
- 两个人同时修改同一图层样式时如何处理冲突;
- 外部数据更新后,协作者看到的是否仍是同一版本;
- 导出的项目能否在另一台机器或 R 环境中还原。
实践中,应把实时协作视为交互层,把 Git、对象存储版本或数据目录快照作为持久化审计层。协作会话提高沟通速度,但不能替代数据版本管理。
可以这样组织一个可移植项目
下面是一个可直接运行的最小项目。它不依赖未在摘要中说明的 JupyterGIS Python API,而是生成通用 GeoJSON 和独立样式配置,随后可在 JupyterGIS 中导入并按界面能力映射样式。运行前只需要 Python 3。
mkdir -p jupytergis-demo/data jupytergis-demo/styles
cd jupytergis-demo
cat > data/zones.geojson <<'EOF'
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "North", "risk": "high"},
"geometry": {
"type": "Polygon",
"coordinates": [[[116.30, 39.95], [116.40, 39.95], [116.40, 40.02], [116.30, 40.02], [116.30, 39.95]]]
}
},
{
"type": "Feature",
"properties": {"name": "South", "risk": "low"},
"geometry": {
"type": "Polygon",
"coordinates": [[[116.30, 39.86], [116.40, 39.86], [116.40, 39.93], [116.30, 39.93], [116.30, 39.86]]]
}
}
]
}
EOF
cat > styles/zones.style.json <<'EOF'
{
"version": 1,
"layer": "zones",
"geometry": "polygon",
"classification": {
"field": "risk",
"type": "categorical",
"values": {
"high": {"fill": "#d73027", "stroke": "#7f0000"},
"low": {"fill": "#1a9850", "stroke": "#005a32"}
},
"fallback": {"fill": "#bdbdbd", "stroke": "#636363"}
},
"opacity": 0.75
}
EOF
python -m json.tool data/zones.geojson >/dev/null
python -m json.tool styles/zones.style.json >/dev/null
printf 'GeoJSON and style JSON are valid.\n'
这里的 zones.style.json 是用于说明工程组织方式的可移植约定,并非声称它是 JupyterGIS 0.16 的原生样式格式。接入实际项目时,需要把字段映射到 JupyterGIS 当前支持的样式模型。关键原则是:数据和样式分文件保存,样式引用稳定字段名,并为未知分类提供回退颜色。
推荐的目录结构如下:
jupytergis-demo/
├── data/
│ └── zones.geojson
├── styles/
│ └── zones.style.json
├── notebooks/
│ └── analysis.ipynb
├── environment.yml
└── README.md
对于大型遥感数据,不应把完整栅格直接嵌入 Notebook。更稳妥的方式是保存数据 URI、处理参数和输出摘要,读取时采用窗口、分块或金字塔层级。下面的示例使用 Rasterio 分块统计单波段 GeoTIFF;把 scene.tif 改成自己的文件即可运行:
from pathlib import Path
import numpy as np
import rasterio
raster_path = Path("scene.tif")
with rasterio.open(raster_path) as src:
valid_sum = 0.0
valid_count = 0
for _, window in src.block_windows(1):
block = src.read(1, window=window, masked=True)
values = block.compressed()
valid_sum += float(values.sum(dtype=np.float64))
valid_count += values.size
mean_value = valid_sum / valid_count if valid_count else float("nan")
print({"file": str(raster_path), "valid_pixels": valid_count, "mean": mean_value})
这种模式把计算限制在数据块内,避免一次性载入整幅影像。JupyterGIS 可以承担交互式查看与协作入口,而批量计算仍应交给适合分块、并行和远程数据访问的处理库。
R 兼容性的实际意义
扩展对 R 用户的兼容性,意味着 GIS 项目不必把 Python 设为唯一入口。团队可以让 Python 负责遥感预处理,让 R 完成空间统计,再在同一个 Jupyter 工作空间中检查结果。
真正的互操作层应建立在文件和数据契约上,例如 GeoJSON、GeoParquet、Cloud Optimized GeoTIFF,以及明确的坐标参考系和字段类型。不要让某个内核中的临时变量成为跨语言协作接口。对于大型矢量数据,GeoJSON 便于检查但效率有限,生产流程通常更适合使用 GeoParquet 等列式格式。
采用前的检查清单
引入 JupyterGIS 0.16 时,可以从一个低风险项目开始,并检查以下事项:
- 固定 JupyterGIS、JupyterLab、Python 或 R 依赖版本;
- 将原始数据、派生数据、样式和 Notebook 分开管理;
- 为分类字段、坐标参考系和缺失值建立明确约定;
- 用两名用户实际测试实时编辑和冲突场景;
- 在另一台机器上执行一次完整还原,验证可移植性;
- 对遥感影像采用分块读取或远程优化格式,避免 Notebook 内存成为瓶颈;
- 导出关键地图或统计结果,保留可审计的发布产物。
JupyterGIS 0.16 展示的方向,是把 GIS 从单机桌面操作推进到可协作、可编程的 Jupyter 工作流。它能够缩短分析人员与制图人员之间的反馈回路,但团队仍需自行处理版本锁定、数据契约、访问控制和跨环境复现。声明式样式与实时协作提供了基础,工程纪律决定这些能力能否真正进入生产流程。