Python Basemap 教程:从入门到实战
Basemap 是 Matplotlib 的一个扩展库,它提供了在地图上绘制 2D 数据的强大功能,虽然从 2025 年起 Basemap 已进入维护模式(不再有新功能开发),并且其官方推荐替代品是 Cartopy,但 Basemap 仍然非常成熟、稳定,并且拥有海量的教程和现有代码,对于许多用户来说,它仍然是进行科学数据可视化的首选工具。

本教程将带你一步步掌握 Basemap 的核心用法。
目录
- 环境准备:安装 Basemap
- 第一个地图:
drawcoastlines() - 核心概念:投影
- 地图定制:添加更多元素
- 国家、州/省边界
- 经纬度网格和标签
- 地图填充(陆地、海洋)
- 在地图上绘制数据点
- 实战案例:绘制全球地震分布图
- Basemap vs. Cartopy:我应该选择哪个?
- **总结与资源---
环境准备:安装 Basemap
Basemap 的安装有时可能会遇到一些依赖问题,特别是如果你使用的是 Anaconda。
推荐使用 Conda 安装:
# 创建一个新的虚拟环境(推荐) conda create -n basemap_env python=3.8 conda activate basemap_env # 安装 basemap 和其依赖项 conda install -c conda-forge basemap
使用 Pip 安装(可能不成功):

pip install basemap
Pip 安装失败,通常是因为缺少 geos 库,在 Linux 上,你可能需要先安装 libgeos-dev,在 Windows 上,这个问题会更复杂,因此强烈推荐使用 Conda。
验证安装:
在你的 Python 环境中运行以下代码,如果没有报错,说明安装成功。
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
print("Basemap 安装成功!")
第一个地图:drawcoastlines()
让我们从一个最简单的例子开始:绘制海岸线。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.basemap import Basemap # 1. 创建一个图形和坐标轴 fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(111) # 2. 创建一个 Basemap 实例 # 这里我们使用 'ortho' 投影,即正射投影,看起来像一个球体。 # lat_0=0, lon_0=0 表示将 (0, 0) 这个点(非洲几内亚湾)放在中心。 m = Basemap(projection='ortho', lat_0=0, lon_0=0) # 3. 绘制海岸线 m.drawcoastlines() # 4. 显示图形 plt.show()
代码解释:
fig = plt.figure(...): 创建一个 Matplotlib 图形窗口。m = Basemap(...): 这是核心步骤,我们创建了一个Basemap对象m。projection='ortho': 指定了地图的投影方式。'ortho'是正射投影,模拟从太空看地球的效果。lat_0=0, lon_0=0: 设置了地图的中心点。
m.drawcoastlines(): 调用Basemap对象的方法来绘制海岸线,Basemap 内置了 GSHHS 数据集,可以绘制出非常精细的海岸线。
运行这段代码,你应该能看到一个蓝色的球体,上面有白色的陆地轮廓。
核心概念:投影
地球是一个三维球体,而地图是二维平面。投影就是将三维表面映射到二维平面上的数学方法,不同的投影适用于不同的场景。
Basemap 支持数十种投影,我们来看几个常见的例子:
圆柱投影
# Cylindrical Equidistant (Plate Carrée) # 这是最简单的投影,经纬线都是直线。 m = Basemap(projection='cyl', llcrnrlat=-90, urcrnrlat=90, llcrnrlon=-180, urcrnrlon=180)
墨卡托投影
# Mercator projection # 常用于网络地图(如 Google Maps),但会导致高纬度地区面积失真。 m = Basemap(projection='merc', llcrnrlat=-80, urcrnrlat=80, llcrnrlon=-180, urcrnrlon=180)
兰伯特等角圆锥投影
# Lambert Conformal Conic # 适合绘制中纬度地区的地图,如美国或欧洲。 m = Basemap(projection='lcc', lat_1=45, lat_2=55, lat_0=50, lon_0=-100)
关键参数:
llcrnrlat(lower left corner latitude): 左下角的纬度。urcrnrlat(upper right corner latitude): 右上角的纬度。llcrnrlon(lower left corner longitude): 左下角的经度。urcrnrlon(upper right corner longitude): 右上角的经度。
这些参数定义了你想要显示的地图的矩形边界。
地图定制:添加更多元素
一张好的地图不仅仅是海岸线,Basemap 提供了丰富的定制方法。
# 创建一个墨卡托投影的地图,聚焦于中国及周边地区
fig = plt.figure(figsize=(10, 10))
m = Basemap(projection='merc',
llcrnrlat=0, urcrnrlat=60,
llcrnrlon=70, urcrnrlon=140)
# 1. 绘制填充的陆地和海洋
m.drawmapboundary(fill_color='aqua') # 绘制地图边界并填充海洋颜色
m.fillcontinents(color='coral', lake_color='aqua') # 填充陆地颜色,湖泊用海洋色
# 2. 绘制海岸线、国界、州界
m.drawcoastlines()
m.drawcountries() # 绘制国界
m.drawstates() # 绘制美国州界(在中国地区可能没有效果)
# 3. 绘制经纬度网格
m.drawparallels(np.arange(0, 61, 10), labels=[1, 0, 0, 0]) # 绘制纬度线,只在左边显示标签
m.drawmeridians(np.arange(70, 141, 10), labels=[0, 0, 0, 1]) # 绘制经度线,只在底部显示标签
# 4. 添加标题"Map of China and Surrounding Areas", fontsize=16)
plt.show()
新方法解释:
drawmapboundary(fill_color=...): 绘制地图的边界(通常是矩形)并填充颜色,默认是海洋。fillcontinents(color=..., lake_color=...): 用指定颜色填充大陆,lake_color指定湖泊的颜色(通常与海洋一致)。drawcountries(): 绘制国家边界。drawparallels()/drawmeridians(): 绘制纬线和经线。np.arange(0, 61, 10)表示从 0 到 60,每隔 10 度画一条线。labels=[1, 0, 0, 0]是一个四元组,分别控制[左, 右, 上, 下]是否显示经纬度标签。1表示显示,0表示不显示。
在地图上绘制数据点
这是 Basemap 最强大的功能之一,假设我们有一些城市的经纬度数据,我们想将它们标记在地图上。
关键步骤:
- 准备好你的数据(经度、纬度)。
- 使用 Basemap 的
transform_point()或更方便的x, y = m(lon, lat)将经纬度坐标投影为地图的二维坐标。 - 使用标准的 Matplotlib 绘图函数(如
plot,scatter,text)在(x, y)坐标上绘图。
示例:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# 1. 准备数据:几个主要城市的经纬度
cities = {
'Beijing': (116.4, 39.9),
'Shanghai': (121.47, 31.23),
'Tokyo': (139.69, 35.69),
'Bangkok': (100.50, 13.75),
'Mumbai': (72.82, 18.96)
}
lons, lats = zip(*[(lon, lat) for name, (lon, lat) in cities.items()])
# 2. 创建地图 (使用墨卡托投影)
fig = plt.figure(figsize=(10, 8))
m = Basemap(projection='merc', llcrnrlat=0, urcrnrlat=50, llcrnrlon=70, urcrnrlon=150)
# 3. 绘制地图背景
m.drawcoastlines()
m.drawcountries()
m.drawmapboundary(fill_color='lightblue')
m.fillcontinents(color='lightgray', lake_color='lightblue')
# 4. 将经纬度数据转换为地图坐标
# 这是最关键的一步!
x, y = m(lons, lats)
# 5. 在地图上绘制点
m.scatter(x, y, color='red', s=100, zorder=5, label='Cities')
# 6. 添加城市名称标签
for name, lon, lat in cities.items():
x, y = m(lon, lat)
plt.text(x, y + 0.5, name, fontsize=9, ha='center')
"Major Cities in East Asia")
plt.legend()
plt.show()
代码解释:
x, y = m(lons, lats): 这行代码非常神奇,它接收了经度和纬度的 NumPy 数组,并返回了对应地图投影下的二维坐标x和y,之后,你就可以直接用这些x和y坐标来绘图了。m.scatter(...): 使用 Matplotlib 的scatter函数在地图上绘制散点。zorder=5: 设置绘图顺序,确保点绘制在海岸线之上(海岸线的zorder较低)。
实战案例:绘制全球地震分布图
让我们结合前面所学的知识,绘制一个更有意义的地图:全球 5.0 级以上地震分布图。
我们将使用 USGS 提供的地震数据(CSV 格式)。
准备数据
假设你有一个名为 earthquakes.csv 的文件,内容如下(你可以从 USGS 网站下载):
time,latitude,longitude,depth,mag,magType,place
"2025-10-27T02:10:18.580Z",37.7952,-122.4078,10.4,4.1,ml,"8 km W of The Geysers, CA"
"2025-10-27T01:18:30.580Z",-23.165,179.85,557.8,5.6,m,"342 km ENE of Tadine, New Caledonia"
...
编写 Python 脚本
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# --- 1. 数据加载 ---
# 读取 CSV 文件
# 注意:如果你的文件很大,可能需要使用 chunksize 参数分块读取
try:
df = pd.read_csv('earthquakes.csv')
except FileNotFoundError:
print("错误:请确保 'earthquakes.csv' 文件在当前目录下。")
# 创建一些示例数据以防文件不存在
np.random.seed(42)
num_quakes = 200
df = pd.DataFrame({
'latitude': np.random.uniform(-60, 70, num_quakes),
'longitude': np.random.uniform(-180, 180, num_quakes),
'mag': np.random.uniform(4.0, 7.0, num_quakes)
})
print("已生成示例数据。")
# 筛选震级大于 5.0 的地震
strong_quakes = df[df['mag'] >= 5.0]
# --- 2. 创建地图 ---
fig = plt.figure(figsize=(16, 10))
# 使用 Robinson 投影,这是一种世界地图常用的、视觉上比较平衡的投影
m = Basemap(projection='robin', lon_0=0)
# 绘制地图元素
m.drawcoastlines(linewidth=0.5)
m.drawcountries(linewidth=0.5)
m.drawmapboundary(fill_color='white')
m.fillcontinents(color='lightgray', lake_color='white')
# 绘制经纬度网格
m.drawparallels(np.arange(-90, 91, 30), labels=[1, 0, 0, 0], color='gray')
m.drawmeridians(np.arange(-180, 181, 60), labels=[0, 0, 0, 1], color='gray')
# --- 3. 在地图上绘制地震数据 ---
# 将经纬度转换为地图坐标
lons = strong_quakes['longitude'].values
lats = strong_quakes['latitude'].values
x, y = m(lons, lats)
# 震级越大,点越大,颜色越深
# 使用 mag 列来设置点的大小
sizes = strong_quakes['mag'] * 5
# 使用 scatter 绘制,并添加颜色映射
# cmap='YlOrRd' 表示从黄色到红色的渐变
# c=strong_quakes['mag'] 表示用震级来确定颜色
scatter = m.scatter(x, y, s=sizes, c=strong_quakes['mag'],
cmap='YlOrRd', alpha=0.7, edgecolors='k', linewidths=0.5, zorder=5)
# --- 4. 添加标题和图例 ---"Global Earthquakes (Magnitude >= 5.0)", fontsize=18)
# 添加颜色条
cbar = plt.colorbar(scatter, orientation='horizontal', pad=0.05, shrink=0.7)
cbar.set_label('Magnitude', fontsize=12)
plt.show()
运行结果: 你将得到一张世界地图,上面用不同大小和颜色的点标记了 5.0 级以上的地震,点越大、颜色越红,代表震级越大。
Basemap vs. Cartopy:我应该选择哪个?
这是一个非常重要的问题。
| 特性 | Basemap | Cartopy |
|---|---|---|
| 状态 | 维护模式 (不再有新功能) | 积极开发中 |
| 许可证 | MIT License | LGPLv3 (更宽松) |
| API 设计 | 基于 Basemap 对象,调用其方法绘图 |
基于 Matplotlib 的 Axes (ax),直接在 Axes 上绘图 |
| 语法 | m = Basemap(...)m.plot(x, y) |
ax = plt.gca()ax.add_geometries(...) 或 ax.stock_img() |
| 数据源 | 内置 GSHHS, DCW 等数据 | 内置 Natural Earth 数据,并支持通过 cartopy.feature 动态加载 |
| 投影 | 支持多种投影 | 支持更多、更现代的投影,特别是极地投影 |
| 社区与文档 | 海量教程和现有代码,但不再更新 | 官方文档优秀,是未来的趋势,但社区资源相对较少 |
| 性能 | 性能良好 | 性能同样优秀,甚至在某些方面更优 |
结论与建议:
- 如果你是初学者,或者需要维护/复现旧的 Basemap 代码:继续使用 Basemap,它的教程非常多,概念清晰,足以完成绝大多数地理数据可视化任务。
- 如果你在启动一个新项目,特别是长期项目,或者需要使用最新的地图投影:强烈推荐学习 Cartopy,它是未来的标准,API 设计更符合 Matplotlib 的现代风格,功能也更强大,学习 Cartopy 的初期可能会遇到一些文档和教程较少的问题,但长期来看是值得的投资。
总结与资源
本教程带你走过了 Basemap 的核心使用流程:
- 安装:使用 Conda 是最稳妥的方式。
- 基础绘图:创建
Basemap实例并调用drawcoastlines()。 - 投影选择:理解投影是地图绘图的灵魂,学会使用不同投影。
- 地图美化:添加国界、网格、填充颜色等,让地图更专业。
- 数据可视化:掌握
x, y = m(lon, lat)这一核心转换,将你的数据点绘制到正确的地理位置。 - 实战演练:通过一个完整的案例,将所有知识点串联起来。
进一步学习的资源:
- Basemap 官方文档:https://matplotlib.org/basemap/stable/ (虽然不再更新,但仍然是权威参考)
- 示例画廊:https://matplotlib.org/basemap/stable/users/examples.html (这里有很多可以直接运行的例子,是学习的最佳材料)
- Cartopy 官方文档:如果你决定转向 Cartopy,这里是最好的起点:https://scitools.org.uk/cartopy/docs/latest/
希望这份教程能帮助你顺利入门 Python 地理数据可视化!
