Jupyter Notebook和Python到底有什么区别?城乡规划GIS实战对比(附:数据处理脚本)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

Jupyter Notebook和Python到底有什么区别?城乡规划GIS实战对比(附:数据处理脚本)这个问题,很多刚开始做规划数据分析、GIS制图或空间统计的同学都会遇到:明明都是写 Python,为什么有人打开的是 Jupyter Notebook,有人运行的是 .py 脚本?在城乡规划 GIS 实战里,二者不是“谁替代谁”的关系,而是适合不同阶段、不同工作方式的工具组合。

引言:先把结论说清楚

简单说,Python是一门编程语言,也可以理解为完成 GIS 自动化、空间数据处理、统计分析的“能力本身”;Jupyter Notebook是一个交互式写 Python 的工作环境,更适合边看数据、边画图、边调试。

在城乡规划 GIS 工作中,你可以这样理解:

  • Jupyter Notebook适合探索数据、检查字段、快速画图、写分析过程说明。
  • Python 脚本适合批量处理、重复运行、定时任务、交给同事或服务器执行。
  • 二者都可以调用 GeoPandas、Pandas、Shapely、Rasterio、ArcPy、PyQGIS 等 GIS 常用库。

如果你正在处理居住用地、道路、人口、POI、行政区边界等规划数据,建议先用 Jupyter Notebook 探索流程,再把稳定步骤整理成 Python 脚本。

Jupyter Notebook和Python区别 城乡规划GIS数据处理脚本工作流
Jupyter Notebook 更适合规划 GIS 探索分析,Python 脚本更适合稳定流程的批量自动化处理。

背景:为什么 GIS 学习者容易混淆 Jupyter Notebook 和 Python

很多人第一次接触 Python GIS,是从 Anaconda、Jupyter Notebook 或 ArcGIS Pro 的 Python 窗口开始的。于是容易产生一个误解:以为 Jupyter Notebook 就是 Python,或者以为写 .py 文件才算真正使用 Python。

实际上,它们处在不同层级:

  • Python:语言本身,负责表达逻辑,例如读取数据、筛选字段、空间连接、面积统计。
  • Python 解释器:执行 Python 代码的程序,例如系统里的 python.exe
  • Jupyter Notebook:浏览器里的交互式开发环境,把代码、结果、图表、说明文字放在一个 .ipynb 文件中。
  • Python 脚本:通常是 .py 文件,适合一次性从上到下执行完整流程。

在城乡规划 GIS 项目里,常见任务包括用地现状汇总、缓冲区分析、道路可达性统计、规划范围内指标计算、地块属性清洗等。这些任务既可以在 Jupyter Notebook 中完成,也可以写成 Python 脚本完成,区别主要在于工作方式。

原理:Jupyter Notebook 和 Python 的核心区别

理解 Jupyter Notebook 和 Python 的区别,可以从“运行方式”“文件形态”“适用场景”三个角度看。

1. 运行方式不同

Jupyter Notebook 把代码拆成一个个单元格,每个单元格可以单独运行。你可以先读取规划范围数据,再查看字段,再画地图,再修改筛选条件。

Python 脚本通常从第一行运行到最后一行,更强调完整流程。比如每天自动读取最新 POI 数据、叠加街道边界、输出统计表,就更适合脚本。

2. 文件形态不同

  • Jupyter Notebook 文件扩展名通常是 .ipynb
  • Python 脚本文件扩展名通常是 .py
  • .ipynb可以保存代码、运行结果、图表和文字说明。
  • .py更简洁,适合版本管理、自动运行和工程化维护。

3. 对 GIS 分析的影响不同

对于 GIS 初学者和规划分析人员,Jupyter Notebook 的优势是“看得见中间过程”。例如你做空间叠加时,可以随时查看坐标系、属性表、几何数量和地图效果。

但当流程稳定后,Notebook 里散落的单元格可能带来风险:如果单元格没有按顺序运行,结果可能和你以为的不一样。此时,把流程整理成 Python 脚本更可靠。

步骤:用同一个城乡规划 GIS 任务对比二者

下面用一个常见任务说明:统计每个街道范围内的居住用地面积。假设你有两个数据:

  • street_boundary.geojson:街道边界面数据。
  • landuse.geojson:用地现状面数据,字段 land_type 表示用地类型。

目标是筛选出居住用地,与街道边界叠加,计算每个街道的居住用地面积,并导出 CSV 表格。

步骤 1:在 Jupyter Notebook 中探索数据

Notebook 适合先检查数据是否能正常读取、字段是否正确、坐标系是否适合计算面积。

import geopandas as gpd

streets = gpd.read_file("data/street_boundary.geojson")
landuse = gpd.read_file("data/landuse.geojson")

print(streets.head())
print(landuse.head())

print(streets.crs)
print(landuse.crs)
print(landuse["land_type"].value_counts())

这一步的重点不是马上出结果,而是确认数据质量。尤其要检查:

  • 街道边界和用地数据是否有坐标系。
  • 两个图层坐标系是否一致。
  • land_type 字段里居住用地的实际写法是什么。
  • 是否存在空几何、无效几何或重复地块。

步骤 2:统一坐标系并筛选居住用地

面积计算不能直接依赖经纬度坐标系。经纬度单位是度,不是米。为了得到平方米或公顷,应投影到适合本地的投影坐标系。下面示例使用 EPSG:3857 只是演示,正式项目应改成本地 CGCS2000 高斯克吕格投影或项目指定投影。

target_crs = "EPSG:3857"

streets_proj = streets.to_crs(target_crs)
landuse_proj = landuse.to_crs(target_crs)

residential = landuse_proj[landuse_proj["land_type"].str.contains("居住", na=False)].copy()

print(residential.shape)

如果你的数据来自国土空间规划、控规或现状调查,字段值可能不是“居住”,而是“R”、“城镇住宅用地”、“0701”等代码。正式脚本需要根据实际字段字典调整筛选条件。

步骤 3:空间叠加并计算面积

使用 overlay 做相交叠加,让居住用地按街道边界切分,然后计算每块相交区域的面积。

intersected = gpd.overlay(residential, streets_proj, how="intersection")

intersected["area_sqm"] = intersected.geometry.area
intersected["area_ha"] = intersected["area_sqm"] / 10000

print(intersected[["area_sqm", "area_ha"]].head())

如果数据量较大,空间叠加可能较慢。可以先用边界范围裁剪、简化字段、修复几何,减少计算量。

步骤 4:按街道汇总并导出

假设街道名称字段为 street_name,可以按街道汇总居住用地面积。

summary = (
    intersected
    .groupby("street_name", as_index=False)
    .agg(residential_area_ha=("area_ha", "sum"))
)

summary.to_csv("output/residential_area_by_street.csv", index=False, encoding="utf-8-sig")

print(summary)

到这里,Notebook 已经完成了探索、检查、计算和导出。你可以在 Notebook 中继续画图,检查结果是否符合直觉。

步骤 5:把稳定流程整理成 Python 脚本

当你确认逻辑正确,就可以把流程整理为 planning_residential_area.py。这样更适合重复运行,也方便交给同事使用。

import geopandas as gpd
from pathlib import Path

def calculate_residential_area(
    street_path,
    landuse_path,
    output_csv,
    street_name_field="street_name",
    landuse_field="land_type",
    residential_keyword="居住",
    target_crs="EPSG:3857"
):
    street_path = Path(street_path)
    landuse_path = Path(landuse_path)
    output_csv = Path(output_csv)

    output_csv.parent.mkdir(parents=True, exist_ok=True)

    streets = gpd.read_file(street_path)
    landuse = gpd.read_file(landuse_path)

    if streets.crs is None:
        raise ValueError("街道边界数据缺少坐标系,请先定义 CRS。")
    if landuse.crs is None:
        raise ValueError("用地数据缺少坐标系,请先定义 CRS。")

    streets_proj = streets.to_crs(target_crs)
    landuse_proj = landuse.to_crs(target_crs)

    if street_name_field not in streets_proj.columns:
        raise ValueError(f"街道字段不存在:{street_name_field}")
    if landuse_field not in landuse_proj.columns:
        raise ValueError(f"用地类型字段不存在:{landuse_field}")

    residential = landuse_proj[
        landuse_proj[landuse_field].astype(str).str.contains(residential_keyword, na=False)
    ].copy()

    if residential.empty:
        raise ValueError("没有筛选到居住用地,请检查字段值或筛选关键词。")

    intersected = gpd.overlay(residential, streets_proj, how="intersection")
    intersected["area_ha"] = intersected.geometry.area / 10000

    summary = (
        intersected
        .groupby(street_name_field, as_index=False)
        .agg(residential_area_ha=("area_ha", "sum"))
    )

    summary.to_csv(output_csv, index=False, encoding="utf-8-sig")
    return summary

if __name__ == "__main__":
    result = calculate_residential_area(
        street_path="data/street_boundary.geojson",
        landuse_path="data/landuse.geojson",
        output_csv="output/residential_area_by_street.csv",
        street_name_field="street_name",
        landuse_field="land_type",
        residential_keyword="居住",
        target_crs="EPSG:3857"
    )
    print(result)

这个脚本已经比 Notebook 更接近实际项目使用方式:输入路径、字段名、筛选关键词和目标坐标系都可以调整;同时加入了基本错误提示,便于排查数据问题。

常见坑:城乡规划 GIS 使用 Jupyter Notebook 和 Python 时最容易出错的地方

坑 1:以为 Notebook 运行顺序等于代码显示顺序

Notebook 的单元格可以任意运行。如果你先运行了下面的单元格,再回头修改上面的变量但没有重新运行全部流程,结果可能已经不一致。

建议在提交成果前,使用“重新启动内核并全部运行”的方式检查 Notebook 是否能从头到尾稳定执行。

坑 2:用经纬度直接算面积

很多规划数据是 EPSG:4326 经纬度坐标系,直接执行 geometry.area 得到的不是平方米,而是“度的平方”,没有实际规划统计意义。

面积、长度、缓冲区距离等计算,应优先使用适合项目区的投影坐标系。

坑 3:没有检查 CRS 是否一致

街道边界和用地图层坐标系不同,会导致叠加失败、错位或结果为空。空间分析前应检查:

  • gdf.crs 是否存在。
  • 两个图层是否处于同一坐标系。
  • 是否只是“定义坐标系”错误,而不是需要“投影转换”。

坑 4:字段名称和字段值不稳定

不同来源的规划用地数据字段差异很大。居住用地可能写成“居住用地”“住宅用地”“R”“0701”。脚本里不要盲目写死字段,应在 Notebook 中先查看字段和唯一值。

坑 5:Notebook 适合展示,但不等于适合生产流程

Notebook 很适合写分析说明和结果展示,但如果一个任务需要每天、每周或每个项目反复跑,建议整理成 Python 脚本,减少人工点击和运行顺序错误。

方法比较:Jupyter Notebook 和 Python 脚本在 GIS 实战中的选择

对比项 Jupyter Notebook Python 脚本
适合阶段 数据探索、教学演示、分析说明 批处理、自动化、项目交付
文件类型 .ipynb .py
运行方式 按单元格交互运行 从上到下完整运行
GIS 优势 方便查看属性表、地图和中间结果 适合批量转换、空间处理、自动导出
主要风险 单元格顺序混乱,结果不易复现 调试不如 Notebook 直观
适合人群 GIS 学生、规划分析师、数据探索人员 GIS 工程师、数据处理人员、自动化运维人员

如果你只是在学习 Python GIS,建议优先从 Jupyter Notebook 开始,因为它能让你快速看到每一步的输出。如果你已经在做项目交付,建议逐步训练自己把 Notebook 中验证过的代码整理成 Python 脚本。

检查清单:规划 GIS 数据处理前后应该确认什么

无论你使用 Jupyter Notebook 还是 Python 脚本,城乡规划 GIS 数据处理都建议按下面清单检查。

  • 输入数据:文件路径是否正确,编码是否正常,字段是否完整。
  • 坐标系:是否存在 CRS,是否需要投影转换,面积单位是否为平方米。
  • 几何质量:是否有空几何、无效面、自相交、多部件异常。
  • 字段规则:用地类型代码是否符合项目字典,筛选条件是否遗漏类别。
  • 空间关系:叠加结果是否为空,边界是否错位,是否存在跨界地块。
  • 统计结果:汇总面积是否明显偏大或偏小,单位是否转换为公顷或平方公里。
  • 输出文件:CSV 是否能被 Excel 正确打开,中文是否乱码,字段名是否清晰。
  • 可复现性:Notebook 是否能全部重新运行,脚本是否能在新环境中执行。

实务建议:Notebook 里保留“为什么这样做”的说明,Python 脚本里保留“怎样稳定运行”的参数和错误提示。这样既方便学习复盘,也方便项目复用。

FAQ:Jupyter Notebook 和 Python 在 GIS 学习中的常见问题

Q1:学 GIS 自动化,应该先学 Jupyter Notebook 还是 Python?

应该先理解 Python 基础语法,再用 Jupyter Notebook 练习 GIS 数据读取、字段处理和空间分析。Notebook 只是写 Python 的环境,不是另一门语言。

Q2:Jupyter Notebook 能不能做正式 GIS 项目?

可以,但更适合分析报告、方法验证和过程展示。如果是需要反复运行的正式生产流程,建议整理成 Python 脚本,便于自动化和维护。

Q3:ArcGIS Pro 里的 Python 和 Jupyter Notebook 有关系吗?

ArcGIS Pro 自带 Python 环境,并支持 Notebook 工作方式。你可以在 ArcGIS Pro 的 Notebook 中调用 ArcPy,也可以把成熟代码保存为 .py 脚本执行。

Q4:QGIS 用户需要 Jupyter Notebook 吗?

不一定,但很有用。QGIS 用户可以在 Notebook 中使用 GeoPandas、Shapely、PyProj 等库处理数据,也可以在 QGIS Python 控制台或处理工具箱中使用 PyQGIS。

Q5:为什么我的 Python 脚本在 Notebook 里能跑,保存成 .py 后就报错?

常见原因包括相对路径变化、当前工作目录不同、依赖库环境不同、Notebook 中已有变量没有写入脚本。把路径、参数和导入库写完整,通常可以解决。

Q6:城乡规划 GIS 数据处理中,Notebook 最适合做什么?

最适合做字段检查、坐标系检查、用地类别探索、快速制图、统计逻辑验证和成果说明。它能把代码、文字和结果放在同一个文件里,便于教学和沟通。

Q7:什么时候必须把 Notebook 改成 Python 脚本?

当任务需要批量处理多个区县、多个年份、多个数据版本,或者需要放到服务器、计划任务、项目模板中运行时,就应该改成 Python 脚本。

结论:不要纠结谁更高级,要看 GIS 任务处在哪个阶段

Jupyter Notebook 和 Python 的区别,本质上不是“初级工具”和“高级工具”的区别,而是“交互式探索”和“脚本化自动化”的区别。对于城乡规划 GIS 实战,最稳妥的路线是:先用 Jupyter Notebook 看清数据、验证方法、记录过程,再用 Python 脚本固化流程、批量处理、稳定交付。

如果你刚开始学习 Python GIS,可以从本文的居住用地面积统计示例入手,先在 Notebook 中逐行运行,确认坐标系、字段和结果;等流程跑通后,再整理为可复用的 .py 脚本。这样既能避免“只会点软件”的局限,也能逐步建立真正可复现的 GIS 数据处理能力。