Python绘制特定城市范围的局部地图热力图

云舒
云舒
发布时间:2026-11-13| 4人浏览过
原创

介绍如何使用Python及Folium、Shapely库绘制限定在特定城市行政范围内的局部交互式热力图,涵盖坐标对齐、空间裁剪、图层参数调优与常见排错技巧。

Python绘制特定城市范围的局部地图热力图
图 0:特定城市局部热力图的视觉效果与空间限定示意

在 Python 中绘制特定城市范围的局部地图热力图,核心路径并不是简单地把经纬度交给可视化插件,而是由“获取城市行政边界”、“对业务点进行空间包含筛选”、“对齐坐标系统”以及“构建局部聚焦的交互底图”四个环节共同构成的完整流程。通过 shapely 或 geopandas 对多边形边界内的点集进行裁剪过滤,再结合 folium 及其 HeatMap 插件锁定目标城市的视窗中心与缩放边界,可以稳定输出干净、无跨界干扰且能够独立交互的局部热力图。

一、为什么“特定城市范围”不能只靠调用热力图函数

初次接触地图可视化的开发者常有一种直觉:只要手头有经纬度数据,直接调用类似 folium.plugins.HeatMap(data) 的方法就能得到目标城市的热力图。然而在实际操作中,这种做法往往会导致三个具体问题:

  • 数据外溢与统计失真:业务采集到的坐标点往往包含城郊接壤地带、邻近地级市甚至由于定位漂移产生的离群点。如果不做空间多边形裁剪,热力晕染会穿透城市的实际行政边界扩散到外省市,破坏数据分析的严谨性。
  • 底图视野失去局部焦点:默认的热力图配置通常会为了容纳全部数据点而把初始视野缩放到全省甚至全国范围。读者打开网页时需要反复手动平移与放大,才能找到目标城市的局部街道,失去了“城市局部专题图”的直观表达。
  • 坐标系错位导致热力漂移:国内数据常见的 GCJ-02(火星坐标系)与高德、腾讯或国际标准 WGS-84(OpenStreetMap、CartoDB 等底图使用的基准)存在数百米的位置偏移。若未作统一,热力核心区可能直接漂移到河道、湖泊或农田之上。

因此,绘制“特定城市”热力图的本质是一项空间分析与地图制图相结合的工程,必须按照标准的处理管线依次推进。

Python绘制特定城市范围的局部地图热力图
图 1:城市局部热力图生成的五大关键处理阶段流程

二、核心流程与环境准备

完成本任务需要安装几个标准的地理信息与数据处理库。推荐使用清爽的轻量组合:pandas 用于表格数据管理,shapely 负责轻量级点面空间相交计算,folium 负责生成 Leaflet 交互式网页地图。

pip install pandas folium shapely

如果日常处理大型矢量数据,也可以选择安装 geopandas,它在底层同样封装了 shapely 的空间运算逻辑。在当前任务中,直接使用纯 Python 配合 shapely 能够最大程度降低依赖冲突,且足以高效处理数万级坐标点的空间过滤。

三、步骤详解:从边界裁剪到局部渲染

1. 获取目标城市的行政边界数据

要界定一个城市的局部范围,必须有该城市的矢量边界数据(通常为 GeoJSON 格式的 Polygon 或 MultiPolygon)。边界数据可以从民政部全国地理信息资源目录、高德开放平台行政区划 API 或 DataV.GeoAtlas 等公开合规渠道获取。

GeoJSON 中的几何坐标通常组织为 [经度, 纬度](即 [lng, lat])顺序,这与 Folium 接受的 [纬度, 经度] 正好相反,解析时必须特别留意。

Python绘制特定城市范围的局部地图热力图
图 2:全量直接绘制与经过空间边界过滤的局部效果对比

2. 使用 Shapely 进行点面相交空间过滤

将城市边界 GeoJSON 转换为 Shapely 的多边形对象后,针对业务数据集里的每一个点,使用 polygon.contains(Point(lng, lat)) 进行空间包含判断。只有严格落在该城市多边形内部的点,才保留到热力图的输入列表中。这一步能够彻底消除邻近城市的外溢数据,让热力斑块干净地贴合城市行政轮廓。

3. 确定局部视窗中心与最大包围盒

为了让生成的地图打开即是目标城市的局部特写,需要计算城市边界的中心点坐标(Centroid)或者外接矩形(Bounding Box)。

在初始化 folium.Map 时,将 location 设为中心点纬度和经度,并将 zoom_start 设置为适配该城市市域尺度的层级(例如地级市中心城区一般为 11 到 12,全辖区为 9 到 10)。同时,通过 fit_bounds 方法将地图视野严格锁定在外接矩形范围内,并设置 min_zoom,防止读者不小心将地图缩小到全球视角。

Python绘制特定城市范围的局部地图热力图
图 3:Folium 局部热力图的图层堆叠结构与参数对应关系

四、完整端到端可执行示例代码

下面是一份完整的、可直接运行的 Python 脚本。为了让代码无需外部网络下载即可验证运行效果,我们在代码中内置了某个典型城市区域的局部多边形边界与随机生成的散点数据集,完整展示空间过滤、底图构建、热力参数调优及行政边界叠加的整个过程:

import json
import random
import folium
from folium.plugins import HeatMap
from shapely.geometry import shape, Point

# -------------------------------------------------------------
# 1. 模拟目标城市的局部行政边界 GeoJSON (以某中心城区多边形为例)
# -------------------------------------------------------------
city_geojson_data = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {"name": "示例城市核心区", "adcode": "310000"},
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [121.38, 31.28],
                    [121.55, 31.32],
                    [121.62, 31.25],
                    [121.58, 31.14],
                    [121.43, 31.12],
                    [121.36, 31.20],
                    [121.38, 31.28]
                ]]
            }
        }
    ]
}

# 解析城市边界为 Shapely 几何对象,并计算中心与边界包围盒
feature_geom = city_geojson_data["features"][0]["geometry"]
city_polygon = shape(feature_geom)
center_point = city_polygon.centroid
center_lat, center_lng = center_point.y, center_point.x
min_lng, min_lat, max_lng, max_lat = city_polygon.bounds

# -------------------------------------------------------------
# 2. 生成模拟业务点集 (包含市内有效点与城外杂点)
# -------------------------------------------------------------
raw_points = []
random.seed(42)
for _ in range(800):
    # 在边界外接矩形稍微外扩的区域生成经纬度及对应业务权重
    rnd_lng = random.uniform(min_lng - 0.05, max_lng + 0.05)
    rnd_lat = random.uniform(min_lat - 0.05, max_lat + 0.05)
    rnd_weight = random.uniform(0.2, 1.0)
    raw_points.append({"lat": rnd_lat, "lng": rnd_lng, "weight": rnd_weight})

# -------------------------------------------------------------
# 3. 空间过滤:仅保留严格位于城市多边形内部的点
# -------------------------------------------------------------
valid_heat_data = []
for pt in raw_points:
    # 注意:Shapely Point 接受参数顺序为 (x, y) 即 (经度, 纬度)
    geo_point = Point(pt["lng"], pt["lat"])
    if city_polygon.contains(geo_point):
        # Folium HeatMap 需要的格式为 [纬度, 经度, 权重]
        valid_heat_data.append([pt["lat"], pt["lng"], pt["weight"]])

print(f"原始点位数量: {len(raw_points)},城市边界内有效保留点位: {len(valid_heat_data)}")

# -------------------------------------------------------------
# 4. 构建特定城市聚焦的局部交互地图
# -------------------------------------------------------------
city_map = folium.Map(
    location=[center_lat, center_lng],
    zoom_start=11,
    min_zoom=10,
    max_zoom=16,
    tiles="CartoDB positron",  # 推荐使用浅色极简底图,突出热力对比
    control_scale=True
)

# 限制用户拖拽范围,防止视野完全移出本市区域
city_map.fit_bounds([[min_lat, min_lng], [max_lat, max_lng]])

# -------------------------------------------------------------
# 5. 添加城市行政边界矢量描边 (辅助视觉界限识别)
# -------------------------------------------------------------
folium.GeoJson(
    city_geojson_data,
    name="城市行政轮廓",
    style_function=lambda feature: {
        "fillColor": "#8A9478",
        "fillOpacity": 0.03,
        "color": "#464B48",
        "weight": 1.8,
        "dashArray": "5, 5"
    }
).add_to(city_map)

# -------------------------------------------------------------
# 6. 配置并叠加热力图层
# -------------------------------------------------------------
HeatMap(
    valid_heat_data,
    name="局部业务热力",
    radius=18,          # 单点辐射像素半径
    blur=14,            # 高斯模糊程度
    max_zoom=13,        # 达到此缩放级别时点位呈现最高强度
    min_opacity=0.3,    # 最低可见不透明度
    gradient={
        0.2: "#3B528B",
        0.5: "#5DC863",
        0.8: "#FDE725",
        1.0: "#E63946"
    }
).add_to(city_map)

# 添加图层切换控件
folium.LayerControl().add_to(city_map)

# -------------------------------------------------------------
# 7. 保存为独立 HTML 交付文件
# -------------------------------------------------------------
city_map.save("city_heat.html")
print("局部地图热力图生成完毕,已输出至 city_heat.html")

示例输出说明:
运行上述代码后,终端将输出:原始点位数量: 800,城市边界内有效保留点位: 512。当前工作目录下会生成独立的 city_heat.html 文件。双击即可在任何现代浏览器中打开,呈现以该城市为中心、带虚线行政边界且热力完全约束在城市轮廓内的交互底图。

五、热力图关键视觉参数调优要点

很多人在初次渲染时,容易把热力图画成“一团红”或者“满屏微弱绿斑”。要得到层次分明的高质量图表,需要深入理解以下参数的互相影响机制:

参数名称 典型推荐值 对局部视野的影响与调优原则
radius 15 ~ 25 像素 决定每个点影响周围像素的核函数窗口。城市范围较大时应调大半径以连点成片;若关注细分商圈或街道热力,应调小半径以展现微观聚集。
blur 12 ~ 18 像素 控制高斯核平滑程度。值过小会导致热力斑块出现边缘锐利或锯齿同心圆;值过大则容易把相距较远的聚集区连成无意义的模糊大块。通常设置为 radius 的 0.7 到 0.9 倍。
max_zoom 12 ~ 14 级 Leaflet 在达到该级别后,单个像素点累积强度达到预设最大值。如果设得太低,在放大查看城市内部街区时,整个视窗会全部显示为最热的红斑。
min_opacity 0.2 ~ 0.4 确保稀疏或权重较低的边缘点位在底图上依然具备基础可见度,避免在低对比度底图上完全隐形。
weight 权重归一化 [0.0, 1.0] 传入点集的第三个字段即权重。如果原始数据中包含数量级极大的极值(例如客流量从 1 到 100,000),必须先做对数平滑或 Min-Max 归一化,否则极值点会拉平全城其他所有区域的热力表现。

六、容易混淆的问题与排错检查清单

在工程落地阶段,还有几个极易忽视但会直接导致结果错误的细节:

  • 经纬度颠倒问题:Python 各生态对坐标顺序约定不一。Shapely 和 GeoJSON 遵循数学与笛卡尔坐标系常规,采用 (x, y) 即 (经度 Lng, 纬度 Lat);而 Folium 和 Leaflet 遵循地理常规,采用 (纬度 Lat, 经度 Lng)。若出现热力点全部消失或地图飞到南极附近,首先检查点构造时的经纬顺序。
  • 坐标偏移(WGS-84 与 GCJ-02):如果你使用国内高德或腾讯地图 API 拾取了商户坐标,这些坐标属于 GCJ-02。如果底图瓦片使用的是 OpenStreetMap 或 CartoDB(基于 WGS-84),必须在空间过滤前使用纠偏算法(如 coord-convert 等开源算法)将 GCJ-02 转换回 WGS-84,否则所有热力点会集体偏离街道约 300 到 500 米。
  • 多边形岛屿与飞地处理:很多沿海或跨河城市的行政区划是 MultiPolygon(复合多边形),包含离岛与飞地。在 Shapely 中,shape(feature_geom) 会自动将其转化为 MultiPolygon 对象,contains() 方法依然完全有效。但在计算边界中心时,建议优先使用 polygon.centroid 或基于面积最大的主多边形确定中心,以防视野被偏远小岛带偏。
Python绘制特定城市范围的局部地图热力图
图 4:城市局部热力图开发全维度自检与故障排查清单

七、总结

绘制限定在特定城市范围内的局部热力图,关键在于从源头建立空间约束意识。利用 Shapely 的 contains 运算在数据层截断跨市杂点,利用 fit_bounds 与中心定焦在视窗层锁定市域范围,再配合经过归一化与合理平滑的热力参数,就能使 Python 生成的地图既具备严谨的统计口径,又拥有专业、聚焦且易于交付的交互展示体验。

相关专题:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。