Python 地理信息处理:geopy、shapely、folium 地图可视化实战

小飞兽 Python 8 次阅读 2026-07-24

Introduction

地理信息处理是很多应用场景的基础。本文讲解用 geopy 做地址编码和距离计算、用 shapely 做几何运算(点、线、面)、用 folium 绑 Leaflet 做交互地图可视化。

---

geopy:地址与地理编码

pip install geopy
from geopy.geocoders import Nominatim
from geopy.distance import geodesic
from geopy.exc import GeocoderTimedOut
import time

geocoder = Nominatim(user_agent='my_app')

# 地址 → 坐标
location = geocoder.geocode('杭州市西湖区')
print(f"地址: {location.address}")
print(f"坐标: ({location.latitude}, {location.longitude})")

# 坐标 → 地址(反向编码)
location = geocoder.reverse('30.2741, 120.0001')
print(location.address)

# 计算两点距离(公里)
hangzhou = (30.2741, 120.0001)
shanghai = (31.2304, 121.4737)
dist = geodesic(hangzhou, shanghai).kilometers
print(f"杭州到上海: {dist:.1f} 公里")

# 批量编码(注意频率限制)
def batch_geocode(addresses):
    results = []
    for addr in addresses:
        try:
            loc = geocoder.geocode(addr)
            results.append((addr, loc.latitude, loc.longitude) if loc else (addr, None, None))
            time.sleep(1)  # Nominatim 要求每秒最多一次
        except GeocoderTimedOut:
            results.append((addr, None, None))
    return results

shapely:几何运算

pip install shapely
from shapely.geometry import Point, LineString, Polygon, MultiPolygon
from shapely.ops import unary_union
import matplotlib.pyplot as plt

# 点
p1 = Point(120.0, 30.0)
p2 = Point(121.0, 31.0)
print(f"两点距离: {p1.distance(p2):.3f} 度")

# 线
road = LineString([(120.0, 30.0), (120.5, 30.5), (121.0, 30.0)])
print(f"线长度: {road.length:.3f}")
print(f"线的中心: {road.centroid}")

# 面(矩形)
park = Polygon([(120.0, 30.0), (120.1, 30.0), (120.1, 30.1), (120.0, 30.1)])
print(f"公园面积: {park.area:.6f} 平方度")

# 判断包含/相交
point = Point(120.05, 30.05)
print(f"点在公园内: {park.contains(point)}")  # True
print(f"点在公园边界上: {park.touches(point)}")  # False

# 缓冲区分析(半径1度圆)
circle = point.buffer(1)
print(f"圆形面积: {circle.area:.3f}")

# 多边形合并(做辐射区域合并)
polygons = [Point(120, 30).buffer(0.5), Point(121, 31).buffer(0.5)]
merged = unary_union(polygons)
print(f"合并后类型: {merged.geom_type}")

folium:交互地图

pip install folium
import folium

# 创建地图(以杭州为中心)
m = folium.Map(location=[30.27, 120.15], zoom_start=12, tiles='OpenStreetMap')

# 添加标记
folium.Marker(
    location=[30.2741, 120.0001],
    popup='杭州西湖',
    tooltip='点击查看详情',
    icon=folium.Icon(color='green', icon='star')
).add_to(m)

# 添加弹出信息
folium.Marker(
    location=[30.28, 120.12],
    popup=folium.Popup('<b>灵隐寺</b><br>千年古刹', max_width=200),
).add_to(m)

# 添加圆(辐射范围)
folium.Circle(
    location=[30.27, 120.15],
    radius=2000,  # 米
    color='red', fill=True, fill_color='red', fill_opacity=0.2
).add_to(m)

# 添加热力图层
import random
heat_data = [[30.27 + random.gauss(0, 0.05), 120.15 + random.gauss(0, 0.05)] for _ in range(100)]
folium.plugins.HeatMap(heat_data).add_to(m)

# 地理编码弹窗
from folium.plugins import MousePosition
m.add_child(MousePosition())

m.save('hangzhou_map.html')
print('地图已生成: hangzhou_map.html')

完整实战:门店分布分析

import folium, pandas as pd
from folium.plugins import MarkerCluster

# 模拟门店数据
stores = pd.DataFrame({
    'name': ['武林店', '西湖店', '滨江店', '城西店', '下沙店'],
    'lat': [30.27, 30.25, 30.21, 30.28, 30.30],
    'lon': [120.15, 120.14, 120.21, 120.10, 120.35],
    'sales': [150, 220, 180, 95, 60]
})

m = folium.Map(location=[30.26, 120.18], zoom_start=11)
cluster = MarkerCluster(name='门店标注').add_to(m)

for _, row in stores.iterrows():
    folium.Marker(
        location=[row['lat'], row['lon']],
        popup=f"<b>{row['name']}</b><br>月销: {row['sales']}万",
        tooltip=row['name'],
        icon=folium.Icon(
            color='green' if row['sales'] > 150 else 'orange' if row['sales'] > 100 else 'red'
        )
    ).add_to(cluster)

folium.LayerControl().add_to(m)
m.save('stores_map.html')

常见问题

Q1: folium 地图不显示中文标注?设置 tiles='OpenStreetMap' 时中文可能显示方块,用国内地图服务(如高德)需要申请 API Key。

Q2: shapely 的距离单位是什么?默认是度(经纬度),不是米。1度 ≈ 111公里。要精确米,用 pyproj 投影到平面坐标系。

Q3: 地理编码请求频率限制?Nominatim 要求每秒不超过 1 次,Keyed 功能免费但需申请。生产环境用 Google Maps API 或高德/百度地图 API(需要注册)。

延伸阅读

  • GeoPandas(pandas 的地理扩展)
  • 高德/百度地图 API
  • GIS 数据格式(GeoJSON/Shapefile)

---

作者:小马 | 绍大技术网 shaoda.net