器→工具, 开源项目

Python地理空间数据可视化利器:Cartopy

钱魏Way · · 3 次浏览

Cartopy是一个基于Matplotlib构建的Python库,专门用于地理空间数据处理和地图绘制。它将Matplotlib强大的绘图功能与专业的地理空间数据处理能力相结合,为科研工作者、数据分析师和开发者提供了一个高效、灵活的地理可视化解决方案。

核心特性与优势

丰富的地图投影系统

Cartopy支持多种地图投影方式,包括:

  • 等距圆柱投影(PlateCarree):最基本投影,适用于小范围区域
  • 墨卡托投影(Mercator):保持方向不变,适合航海图和台风路径图
  • 兰勃特投影(LambertCylindrical):适合中纬度大范围区域
  • 正射投影(Orthographic):呈现从太空看地球的立体效果
  • 罗宾逊投影(Robinson)和摩尔魏特投影(Mollweide):常用于世界地图

内置地理要素库

Cartopy提供了预定义的地理特征,包括:

  • 海岸线(COASTLINE)
  • 陆地(LAND)和海洋(OCEAN)
  • 河流(RIVERS)和湖泊(LAKES)
  • 国家边界(BORDERS)
  • 州/省边界(STATES)

强大的数据可视化能力

  • 支持等值线图、填充图、散点图等多种可视化形式
  • 可与NumPy数组、Pandas DataFrame无缝集成
  • 支持自定义颜色映射和样式

开放源代码与活跃社区

作为开源项目,Cartopy拥有活跃的社区支持和丰富的文档资源。

安装与配置

基础安装

# 使用pip安装
pip install cartopy

# 使用conda安装(推荐)
conda install -c conda-forge cartopy

安装依赖库

# 建议安装的配套库
pip install matplotlib numpy pandas
pip install geopandas  # 用于处理Shapefile和GeoJSON

基础使用示例

示例1:创建基本世界地图

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

# 创建图形和GeoAxes
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())

# 添加地理要素
ax.add_feature(cfeature.LAND, color='lightgray')
ax.add_feature(cfeature.OCEAN, color='lightblue')
ax.add_feature(cfeature.COASTLINE, linewidth=0.8)
ax.add_feature(cfeature.BORDERS, linestyle=':', linewidth=0.5)

# 设置全局视图
ax.set_global()

# 添加网格线
ax.gridlines(draw_labels=True, linestyle='--', alpha=0.7)

plt.title('World Map with Cartopy')
plt.show()

示例2:创建区域地图

# 聚焦中国区域
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())

# 设置中国区域范围 [西经, 东经, 南纬, 北纬]
ax.set_extent([70, 140, 15, 55], crs=ccrs.PlateCarree())

# 添加详细地理要素
ax.add_feature(cfeature.COASTLINE, linewidth=1.0)
ax.add_feature(cfeature.RIVERS.with_scale('50m'), linewidth=0.5, color='blue')
ax.add_feature(cfeature.LAKES.with_scale('50m'), alpha=0.5, color='blue')

# 自定义网格线
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter

ax.set_xticks(range(70, 141, 10), crs=ccrs.PlateCarree())
ax.set_yticks(range(15, 56, 10), crs=ccrs.PlateCarree())
ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))
ax.yaxis.set_major_formatter(LatitudeFormatter())

ax.gridlines(linestyle='--', color='gray', alpha=0.5)

plt.title('China Regional Map')
plt.show()

进阶功能示例

示例3:使用不同投影

# 创建不同投影的地图
projections = [
    ('PlateCarree', ccrs.PlateCarree()),
    ('Mercator', ccrs.Mercator()),
    ('LambertCylindrical', ccrs.LambertCylindrical(central_longitude=105)),
    ('Orthographic', ccrs.Orthographic(central_longitude=105, central_latitude=35))
]

fig, axes = plt.subplots(2, 2, figsize=(15, 12),
                         subplot_kw={'projection': projections[1]})

for idx, (name, proj) in enumerate(projections):
    ax = axes[idx//2, idx%2]
    ax = plt.subplot(2, 2, idx+1, projection=proj)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':', linewidth=0.5)
    ax.set_title(f'{name} Projection')
    if name == 'Orthographic':
        ax.set_global()

plt.tight_layout()
plt.show()

示例4:数据可视化 – 等值线填充图

import numpy as np

# 生成模拟温度数据
lon = np.linspace(70, 140, 100)
lat = np.linspace(15, 55, 80)
lon_mesh, lat_mesh = np.meshgrid(lon, lat)

# 模拟温度场(随纬度变化)
temperature = 25 + 15 * np.cos(np.radians(lat_mesh)) + \
              5 * np.sin(np.radians(2 * lon_mesh))

# 创建地图
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.set_extent([70, 140, 15, 55])

# 绘制等值线填充图
contour = ax.contourf(lon_mesh, lat_mesh, temperature, 60,
                      transform=ccrs.PlateCarree(),
                      cmap='RdBu_r', alpha=0.8)

# 添加海岸线
ax.add_feature(cfeature.COASTLINE, linewidth=1.0)

# 添加色标
cbar = plt.colorbar(contour, ax=ax, shrink=0.8, pad=0.05)
cbar.set_label('Temperature (°C)')

plt.title('Temperature Distribution over China')
plt.show()

示例5:绘制轨迹线

# 定义城市坐标
cities = {
    'Beijing': (116.4, 39.9),
    'Shanghai': (121.5, 31.2),
    'Guangzhou': (113.3, 23.1),
    'Chengdu': (104.1, 30.6)
}

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.set_extent([100, 125, 20, 45])

# 添加底图
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.LAND, color='lightgray', alpha=0.3)

# 绘制城市点和连接线
for name, (lon, lat) in cities.items():
    ax.plot(lon, lat, 'ro', markersize=8, 
            transform=ccrs.PlateCarree())
    ax.text(lon+0.5, lat+0.5, name, 
            transform=ccrs.PlateCarree(),
            fontsize=10, fontweight='bold')

# 绘制大圆航线(最短路径)
ax.plot([cities['Beijing'][0], cities['Shanghai'][0]],
        [cities['Beijing'][1], cities['Shanghai'][1]],
        color='blue', linewidth=2, linestyle='--',
        transform=ccrs.Geodetic(),
        label='Beijing-Shanghai Great Circle')

plt.legend()
plt.title('Major Cities in China with Flight Path')
plt.show()

自定义图层与高级功能

示例6:加载自定义Shapefile数据

import geopandas as gpd

# 加载自定义Shapefile(需要先下载数据)
try:
    # 示例:加载中国省级边界
    gdf = gpd.read_file('path/to/china_provinces.shp')
    
    fig = plt.figure(figsize=(12, 10))
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
    ax.set_extent([70, 140, 15, 55])
    
    # 绘制省级边界
    gdf.plot(ax=ax, facecolor='none', 
             edgecolor='darkblue', linewidth=0.8,
             transform=ccrs.PlateCarree())
    
    # 添加底图要素
    ax.add_feature(cfeature.COASTLINE, linewidth=1.0)
    ax.add_feature(cfeature.RIVERS.with_scale('50m'), 
                   linewidth=0.5, color='blue')
    
    plt.title('China Provincial Boundaries')
    plt.show()
    
except FileNotFoundError:
    print("请确保Shapefile文件路径正确")

示例7:创建专题地图

# 创建人口密度专题地图示例
fig = plt.figure(figsize=(14, 10))

# 创建主地图
ax1 = fig.add_subplot(1, 2, 1, projection=ccrs.PlateCarree())
ax1.set_extent([70, 140, 15, 55])

# 模拟人口密度数据
population_density = np.random.rand(80, 100) * 500

# 绘制人口密度
im = ax1.pcolormesh(lon_mesh, lat_mesh, population_density,
                    transform=ccrs.PlateCarree(),
                    cmap='YlOrRd', shading='auto')

ax1.add_feature(cfeature.COASTLINE, linewidth=1.0)
ax1.add_feature(cfeature.BORDERS, linestyle=':', linewidth=0.5)

# 添加色标
cbar1 = plt.colorbar(im, ax=ax1, shrink=0.8)
cbar1.set_label('Population Density (persons/km²)')
ax1.set_title('Population Density Map')

# 创建插入小图(南海诸岛)
ax2 = fig.add_axes([0.72, 0.15, 0.25, 0.25], 
                   projection=ccrs.PlateCarree())
ax2.set_extent([105, 125, 0, 25])
ax2.add_feature(cfeature.COASTLINE, linewidth=0.8)
ax2.add_feature(cfeature.LAND, color='lightgray')
ax2.set_title('South China Sea Islands')

plt.tight_layout()
plt.show()

实用技巧与注意事项

  1. 安装问题解决
# 使用国内镜像加速安装
pip install cartopy -i https://pypi.tuna.tsinghua.edu.cn/simple

# 安装特定版本
pip install cartopy==0.21.1
  1. 坐标轴标签优化
# 解决非矩形投影的坐标轴标签问题
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.LambertCylindrical())

# 添加地理要素
ax.add_feature(cfeature.COASTLINE)

# 设置坐标轴格式
ax.set_xticks(range(-180, 181, 30), crs=ccrs.PlateCarree())
ax.set_yticks(range(-90, 91, 30), crs=ccrs.PlateCarree())
ax.xaxis.set_major_formatter(LongitudeFormatter())
ax.yaxis.set_major_formatter(LatitudeFormatter())

plt.show()
  1. 性能优化建议
# 使用较低分辨率数据提高性能
ax.add_feature(cfeature.COASTLINE.with_scale('110m'))  # 110m分辨率
ax.add_feature(cfeature.COASTLINE.with_scale('50m'))   # 50m分辨率
ax.add_feature(cfeature.COASTLINE.with_scale('10m'))   # 10m分辨率(最详细)
  1. 地图保存与导出
# 高质量保存地图
fig.savefig('high_quality_map.png', dpi=300, bbox_inches='tight')
fig.savefig('vector_map.pdf', format='pdf', bbox_inches='tight')

# 透明背景保存
fig.savefig('transparent_map.png', dpi=300, 
            bbox_inches='tight', transparent=True)

典型工作流程

导入必要库

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

创建地图投影和坐标轴

fig = plt.figure(figsize=(width, height))
ax = fig.add_subplot(1, 1, 1, projection=selected_projection)

添加基础地理要素

ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.LAND, color='color')
ax.add_feature(cfeature.OCEAN, color='color')

设置地图范围

ax.set_extent([west, east, south, north], crs=ccrs.PlateCarree())

绘制数据

# 确保正确设置transform参数
ax.plot(x_data, y_data, transform=data_crs)
ax.contourf(x_grid, y_grid, z_data, transform=data_crs)

美化地图

ax.gridlines(draw_labels=True)
ax.set_title('Map Title')
plt.colorbar(ax=ax, label='Data Label')

保存或显示

plt.savefig('output.png', dpi=300, bbox_inches='tight')
plt.show()

应用场景

  • 气象与气候分析:绘制温度、降水、气压等气象要素分布
  • 海洋科学研究:可视化海温、洋流、盐度等海洋数据
  • 环境监测:展示污染物扩散、植被指数变化
  • 地理信息系统:创建专题地图、空间分析可视化
  • 教育与科研:制作教学材料、科研成果展示图

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注