在python环境中,利用地图利器Cartopy可以方便、快捷地进行地图的绘制。
准备工作,工欲善其事,必先利其器
Cartopy下载地址:
linux平台直接去官网下载:http://scitools.org.uk/cartopy/download.html
windows平台下的Cartopy下载地址:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#cartopy
注意:需要一些必须的软件包Shapely、pyshp,Cartopy所依赖的这两个库也都从上面的网址下载。
官网自带的示例网址:http://scitools.org.uk/cartopy/docs/latest/gallery.html
安装Cartopy之后,建立一个.py文件并输入以下代码,测试Cartopy库是否可以正常运行。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
plt.figure(figsize=(6, 3))
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.coastlines(resolution='110m')
ax.gridlines()
plt.show()
Natural Earth地图数据的下载地址为http://www.naturalearthdata.com/downloads/
,
下载10m、50m和110m分辨率的cultural 和physical类型数据。下载之后,解压并分别放置到类似于C:\Users\Administrator.local\share\cartopy\shapefiles\natural_earth\cultural和C:\Users\Administrator.local\share\cartopy\shapefiles\natural_earth\physical文件夹下。
下面是示例程序,scale参数用于调整使用哪种分辨率的地图,全球地图建议用1:110的,小尺度地图可以用1:50的或1:10的。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
scale = '110m'
fig = plt.figure(figsize=(8, 10))
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.set_global()
land = cfeature.NaturalEarthFeature('physical', 'land', scale, edgecolor='face',
facecolor=cfeature.COLORS['land'])
ax.add_feature(land, facecolor='0.75')
ax.coastlines(scale)
# 标注坐标轴
ax.set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
ax.set_yticks([-90, -60, -30, 0, 30, 60, 90], crs=ccrs.PlateCarree())
# zero_direction_label用来设置经度的0度加不加E和W
lon_formatter = LongitudeFormatter(zero_direction_label=False)
lat_formatter = LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
# 添加网格线
# gl = ax.gridlines()
ax.grid()
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
box = [100, 150, 0, 50]
scale = '50m'
xstep, ystep = 10, 10
fig = plt.figure(figsize=(8, 10))
ax = plt.axes(projection=ccrs.PlateCarree())
# set_extent需要配置相应的crs,否则出来的地图范围不准确
ax.set_extent(box, crs=ccrs.PlateCarree())
land = cfeature.NaturalEarthFeature('physical', 'land', scale, edgecolor='face',
facecolor=cfeature.COLORS['land'])
ax.add_feature(land, facecolor='0.75')
ax.coastlines(scale)
# ===================================================
# 图像地址D:\Program Files\WinPython-32bit-2.7.9.3\python-2.7.9\Lib\site-packages\
# cartopy\data\raster\natural_earth\50-natural-earth-1-downsampled.png
# 如果有其它高精度图像文件,改名替换即可
ax.stock_img()
# ===================================================
#标注坐标轴
ax.set_xticks(np.arange(box[0], box[1]+xstep,xstep), crs=ccrs.PlateCarree())
ax.set_yticks(np.arange(box[2], box[3]+ystep,ystep), crs=ccrs.PlateCarree())
# zero_direction_label用来设置经度的0度加不加E和W
lon_formatter = LongitudeFormatter(zero_direction_label=False)
lat_formatter = LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
# 添加网格线
ax.grid()
plt.show()
import matplotlib.path as mpath
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker
import cartopy.crs as ccrs
import cartopy.feature as cfeature
fig = plt.figure(figsize=(6, 6))
ax = plt.axes(projection=ccrs.NorthPolarStereo())
box = [-180, 180, 55, 90]
xstep, ystep = 30, 15
# Limit the map to -60 degrees latitude and below.
ax.set_extent(box, crs=ccrs.PlateCarree())
scale = '50m'
land = cfeature.NaturalEarthFeature('physical', 'land', scale, edgecolor='face',
facecolor=cfeature.COLORS['land'])
ocean = cfeature.NaturalEarthFeature('physical', 'ocean', scale, edgecolor='face',
facecolor=cfeature.COLORS['water'])
ax.add_feature(land, facecolor='0.75')
ax.add_feature(ocean, facecolor='blue')
ax.coastlines(scale, linewidth=0.9)
# 标注坐标轴
line = ax.gridlines(draw_labels=False)
line.ylocator = mticker.FixedLocator(np.arange(40, 90, 20)) # 手动设置x轴刻度
line.xlocator = mticker.FixedLocator(np.arange(-180, 210, 30)) # 手动设置x轴刻度
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2 * np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax.set_boundary(circle, transform=ax.transAxes)
# 创建要标注的labels字符串
ticks = np.arange(0, 210, 30)
etick = ['0'] + ['%d$^\circ$E' % tick for tick in ticks if (tick != 0) & (tick != 180)] + ['180']
wtick = ['%d$^\circ$W' % tick for tick in ticks if (tick != 0) & (tick != 180)]
labels = etick + wtick
# 创建与labels对应的经纬度标注位置
# xticks=[i for i in np.arange(0,210,30)]+[i for i in np.arange(-32,-180,-30)]
xticks = [-0.8, 28, 58, 89.1, 120, 151, 182.9, -36, -63, -89, -114, -140]
yticks = [53] + [53] + [54] + [55] * 2 + [54.5] + [54] + [50] + [49] * 3 + [50.6]
# 标注经纬度
# ax.text(0.01,0.23,'60$^\circ$W',transform=ax.transAxes,rotation=25)
# ax.text(-63,50,'60$^\circ$W',transform=ccrs.Geodetic(),rotation=25)
for xtick, ytick, label in zip(xticks, yticks, labels):
ax.text(xtick, ytick, label, transform=ccrs.Geodetic())
x = [180, 180, 0, 0]
y = [50, 90, 90, 50]
ax.plot([-180, 0], [80, 80], ':', transform=ccrs.Geodetic(), color='k', linewidth=0.4)
ax.plot([-90, 90], [80, 80], ':', transform=ccrs.Geodetic(), color='k', linewidth=0.5)
# ax.plot([90,0],[50,50],'-.',transform=ccrs.Geodetic(),color='r', linewidth=6)
ax.text(11.9333, 78.9166, r'\bigstar', transform=ccrs.Geodetic(), size=15, color='r')
plt.show()
当然也可以画出更漂亮的地图