当前位置:首页 > Python > 正文

Cartopy教程:Python地理数据可视化完全指南 | Python地图绘制库

Cartopy教程

Cartopy是什么?

Cartopy 是一个Python库,专门用于地理空间数据处理和地图绘制。它建立在Matplotlib之上,提供了简单而强大的工具来创建专业质量的地图。

Cartopy简化了地图投影、地理特征添加和地理坐标处理等复杂任务,使地理数据可视化变得简单高效。

主要功能:

  • 支持多种地图投影(30+种)
  • 地理特征绘制(海岸线、国界等)
  • 与Matplotlib无缝集成
  • 地理坐标转换
  • 支持Shapefile读取
  • 图像瓦片(如OpenStreetMap)支持

Cartopy vs Basemap

Cartopy

  • 现代、活跃维护
  • 面向对象API
  • 更好的性能
  • 支持最新Python版本

Basemap

  • 不再积极开发
  • 过程式API
  • 性能较差
  • Python 3支持有限

官方推荐使用Cartopy替代Basemap进行新的地理可视化项目

安装Cartopy

Cartopy可以通过pip或conda安装。由于它依赖GEOS和PROJ等C库,推荐使用conda安装以避免编译问题。

使用conda安装

# 创建新环境(可选)
conda create -n geo python=3.9

# 激活环境
conda activate geo

# 安装Cartopy及依赖
conda install -c conda-forge cartopy

使用pip安装

# 需要先安装依赖库
# Ubuntu/Debian:
sudo apt-get install libgeos-dev libproj-dev

# macOS (使用Homebrew):
brew install geos proj

# 然后安装Cartopy
pip install cartopy

验证安装

安装完成后,可以通过以下代码验证Cartopy是否安装成功:

import cartopy

print(f"Cartopy版本: {cartopy.__version__}")

Cartopy基础用法

使用Cartopy创建地图主要涉及以下步骤:

1

创建地图投影

选择并初始化地图投影(如PlateCarree、Mercator等)

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

# 创建图形和坐标轴
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
2

添加地理特征

添加海岸线、国界、河流、湖泊等地理特征

import cartopy.feature as cfeature

# 添加海岸线
ax.coastlines()

# 添加国家边界
ax.add_feature(cfeature.BORDERS, linestyle=':')

# 添加陆地、海洋特征
ax.add_feature(cfeature.LAND, edgecolor='black')
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.LAKES, alpha=0.5)
3

设置地图范围

使用set_extent方法设置地图显示区域

# 设置地图范围 [min_lon, max_lon, min_lat, max_lat]
ax.set_extent([70, 140, 15, 55])  # 亚洲区域

# 添加网格线
ax.gridlines(draw_labels=True, linewidth=0.5, 
             color='gray', alpha=0.5, linestyle='--')
4

添加自定义数据

在地图上绘制点、线、面等自定义地理数据

# 绘制城市位置
cities = {
    '北京': (116.4, 39.9),
    '上海': (121.47, 31.23),
    '广州': (113.26, 23.11)
}

for city, (lon, lat) in cities.items():
    ax.plot(lon, lat, 'ro', markersize=8, 
            transform=ccrs.PlateCarree())
    ax.text(lon+1, lat, city, 
            transform=ccrs.PlateCarree())

Cartopy示例

示例1:中国地图

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

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

# 设置地图范围为亚洲
ax.set_extent([70, 140, 15, 55])

# 添加地理特征
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.LAND, edgecolor='black')
ax.add_feature(cfeature.LAKES, edgecolor='black')
ax.add_feature(cfeature.RIVERS)
ax.add_feature(cfeature.BORDERS, linestyle='--')
ax.coastlines(resolution='10m')

# 添加省份边界
provinces = cfeature.NaturalEarthFeature(
    category='cultural',
    name='admin_1_states_provinces_lines',
    scale='10m',
    facecolor='none')
ax.add_feature(provinces, edgecolor='gray')

# 添加主要城市
cities = {
    '北京': (116.4, 39.9),
    '上海': (121.47, 31.23),
    '广州': (113.26, 23.11),
    '成都': (104.06, 30.67),
    '乌鲁木齐': (87.62, 43.82)
}

for city, (lon, lat) in cities.items():
    ax.plot(lon, lat, 'ro', markersize=6, transform=ccrs.PlateCarree())
    ax.text(lon+0.5, lat+0.5, city, 
            transform=ccrs.PlateCarree(),
            fontsize=10, fontweight='bold')

# 添加标题和网格
plt.title('中国地图', fontsize=16, pad=20)
ax.gridlines(draw_labels=True, linewidth=0.5, 
             color='gray', alpha=0.5, linestyle='--')

plt.tight_layout()
plt.savefig('china_map.png', dpi=300)
plt.show()

示例2:全球温度数据

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point

# 生成模拟温度数据
lons = np.linspace(-180, 180, 360)
lats = np.linspace(-90, 90, 180)
lons, lats = np.meshgrid(lons, lats)
temperature = 30 * np.cos(2 * np.pi * lats / 180) - 0.003 * lons**2

# 创建图形
fig = plt.figure(figsize=(14, 8))
ax = fig.add_subplot(1, 1, 1, 
                    projection=ccrs.Robinson())

# 添加循环点以避免白线
temp_cyclic, lons_cyclic = add_cyclic_point(temperature, coord=lons)

# 绘制填色图
contour = ax.contourf(lons_cyclic, lats, temp_cyclic, 60,
                      transform=ccrs.PlateCarree(),
                      cmap='coolwarm')

# 添加地理特征
ax.add_feature(cfeature.COASTLINE, linewidth=0.8)
ax.add_feature(cfeature.BORDERS, linestyle=':', linewidth=0.5)

# 添加色标
cbar = plt.colorbar(contour, ax=ax, shrink=0.5, 
                    orientation='horizontal', pad=0.05)
cbar.set_label('温度 (°C)', fontsize=12)

# 添加标题
plt.title('全球温度分布模拟', fontsize=16, pad=20)

plt.tight_layout()
plt.savefig('global_temperature.png', dpi=300)
plt.show()

实用技巧

  • 使用add_cyclic_point避免数据在经度0°处出现白线
  • 通过resolution参数控制海岸线精度('110m'、'50m'、'10m')
  • 使用GeoAxes.add_wms()添加Web地图服务
  • 利用crs.transform_points()转换坐标系统
  • 使用ax.stock_img()添加NASA提供的背景图像
  • 通过cfeature.NaturalEarthFeature加载更多自然地理特征

进阶应用

1. 使用不同地图投影

Cartopy支持多种地图投影,可根据需要选择:

  • ccrs.PlateCarree() - 等距圆柱投影
  • ccrs.Mercator() - 墨卡托投影
  • ccrs.Orthographic() - 正射投影
  • ccrs.Robinson() - 罗宾森投影
  • ccrs.LambertConformal() - 兰勃特等角圆锥投影

2. 添加底图

# 添加OpenStreetMap底图
ax.add_wms(wms='http://ows.terrestris.de/osm/service',
           layers='OSM-WMS')

3. 处理Shapefile数据

import cartopy.io.shapereader as shpreader

# 加载中国省级边界Shapefile
shp_path = shpreader.natural_earth(
    resolution='10m',
    category='cultural',
    name='admin_1_states_provinces')

# 读取并绘制边界
reader = shpreader.Reader(shp_path)
provinces = list(reader.geometries())

# 只绘制中国部分
CHINA_NAME = 'China'
ax.add_geometries(
    [province for province, record in zip(provinces, reader.records()) 
        if record.attributes['admin'] == CHINA_NAME],
    ccrs.PlateCarree(),
    edgecolor='black',
    facecolor='none',
    linewidth=0.8)

4. 保存高质量图像

# 设置DPI和图像尺寸
plt.savefig('high_quality_map.png', 
            dpi=300, 
            bbox_inches='tight',
            pad_inches=0.1,
            transparent=False)

发表评论