前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Basemap 和 Cartopy 绘制子图实例

使用 Basemap 和 Cartopy 绘制子图实例

作者头像
bugsuse
发布2020-04-20 13:46:08
2.8K0
发布2020-04-20 13:46:08
举报
文章被收录于专栏:气象杂货铺

平时绘制地图时,经常会将多个图放到同一个 figure 中,而这些图的地图范围通常是相同的,所以可以设置共享 x-y 轴。

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from matplotlib import cm,colors
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
import netCDF4 as nc

fip = "F:\\"
fin1 = "wrfout_v2_Lambert.nc"

ti = [6,7,8,9]
xs = 0;   xe = -1
ys = 0;   ye = -1
zs = 0;   ze = -1

data = nc.Dataset(fip + fin1, "r")
truelat = data.TRUELAT1
truelat = data.TRUELAT2
stalon  = data.CEN_LON
stalat  = data.CEN_LAT

fn = "Arial"
fs = 10
ld = 0.
nrows = 2
ncols = 2

def sharexy(ax, nrows, ncols, i, sharex = True, sharey = True):
    
    if sharex:
        if i+1 in np.arange(1, (nrows - 1)*ncols + 1):
            labelsx = [0, 0, 0, 0]
        else:
            labelsx = [0, 0, 0, 1]
    else:
        labelsx = None
    if sharey:
        if i+1 not in np.arange(1, ncols*nrows, ncols):
            labelsy = [0, 0, 0, 0]
        else:
            labelsy = [1, 0, 0, 0]
    else:
        labelsy = None
    
    return labelsx, labelsy

fig,axes  =  plt.subplots(nrows = nrows, ncols = ncols, subplot_kw= dict(aspect = 'auto'))
for i, ax in zip(np.arange(0, nrows*ncols), axes.flat):
    rain = data.variables["RAINC"][ti[i], xs:xe, ys:ye]
    lat  = data.variables["XLAT"][ti[i], xs:xe, ys:ye]
    lon  = data.variables["XLONG"][ti[i], xs:xe, ys:ye]

    map = Basemap(ax= ax, projection="lcc", llcrnrlon = lon[-1,0], llcrnrlat = lat[0,0],\
              urcrnrlon = lon[0,-1], urcrnrlat=lat[-1,-1], lat_0 = stalat,\
              lon_0 = stalon, resolution ="h")
    x, y = map(lon, lat)
# 添加经度,纬度坐标,海岸线,国界线
    labelsx, labelsy = sharexy(ax, nrows, ncols, i)
#  labels 参数用于控制经纬度 labels 的显示
    map.drawmeridians(np.arange(int(lon[-1,0]), int(lon[0,-1])+1, 2), labels = [0,0,0,1], \
                    fontname = fn, fontsize= fs, linewidth = ld, ax = ax)
    map.drawparallels(np.arange(int(lat[0,0]), int(lat[-1,-1])+1), labels = [1,0,0,0], \
                    fontname = fn, fontsize= fs, linewidth = ld, ax = ax)
    
    con  = map.contourf(x, y, rain)
    
    ax.set_adjustable('box-forced') # 防止绘图和坐标区域不一致
  
fig.colorbar(con, ax=axes.ravel().tolist())   
#plt.savefig("panel.eps")    
plt.show()

sharexy 函数用以设置 basemap 地图共享 x-y 轴。

未共享x-y轴

将上述语句替换为以下两句即可共享x-y轴

代码语言:javascript
复制
map.drawmeridians(np.arange(int(lon[-1,0]), int(lon[0,-1])+1, 2), labels = labelsx, \
                    fontname = fn, fontsize= fs, linewidth = ld, ax = ax)
map.drawparallels(np.arange(int(lat[0,0]), int(lat[-1,-1])+1), labels = labelsy, \
                    fontname = fn, fontsize= fs, linewidth = ld, ax = ax)

共享 x-y轴

共享 x-y 轴后,中间空白间隔太大,可以使用 subplots_adjust 方法控制

将以下语句放到 fig.colorbar 命令前一行(具有相同的缩进)

代码语言:javascript
复制
fig.subplots_adjust(top = 0.9, bottom = 0.1, left = 0.12, right = 0.77, 
                    hspace = 0.05, wspace = 0.05)                 

如果感觉 colorbar 和 panel 之间的间隔大的话, 可以设置 pad 参数并传递给 colorbar 方法。

最后说一下:一定会有人好奇,为什么不使用 subplots 的 sharex 和 sharey 参数来控制 x-y 轴共享。下面就上一张使用这种方法的图看看什么效果

可以看到并没有产生任何影响,drawmeridians 和 drawparallels 方法的 labels 参数起到了关键的作用,使 subplots 的 sharex 和 sharey 参数效果失效了。

注意:

以上图中的 colorbar 和 panel 图的对齐程度并不是很好,需要出图后再进行调整,或是直接设置 figsize 为合适的大小(但很难控制),即使传递 aspect 参数给 subplots 方法也没什么效果。而 cartopy 可以很好的解决以上遇到的问题。

下面上一张 cartopy 绘制子图的效果图

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# plot dbz-panel by WRF model data using cartopy 

from matplotlib import cm,colors
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import netCDF4 as nc

fip = "/home/storm/python/sample_file/"
fin1 = "wrfout_v2_Lambert.nc"

ti = [6,7,8,9]
xs = 0;   xe = -1
ys = 0;   ye = -1
zs = 0;   ze = -1

data = nc.Dataset(fip + fin1, "r")
truelat1 = data.TRUELAT1
truelat2 = data.TRUELAT2
stalon  = data.CEN_LON
stalat  = data.CEN_LAT

fn = "Arial"
fs = 10
ld = 0.     
nrows = 2
ncols = 2
                             
fig,axes  =  plt.subplots(nrows = nrows, ncols = ncols, sharex = True, sharey = True, \
    subplot_kw=dict(projection=ccrs.PlateCarree(), aspect = 'auto'))

for i, ax in zip(np.arange(0, nrows*ncols), axes.flat):
    rain  = data.variables["RAINC"][ti[i],xs:xe,ys:ye]
    lat  = data.variables["XLAT"][ti[i], xs:xe, ys:ye]
    lon  = data.variables["XLONG"][ti[i], xs:xe, ys:ye]

    ax.set_xticks(range(int(lon[-1,0]), int(lon[0,-1])+1, 2))
    ax.set_yticks(range(int(lat[0,0]), int(lat[-1,-1])+1, 1))
    lon_formatter = LongitudeFormatter(number_format='.0f',
                                       degree_symbol='',
                                       dateline_direction_label=True)
    lat_formatter = LatitudeFormatter(number_format='.0f',
                                       degree_symbol='')
    ax.xaxis.set_major_formatter(lon_formatter)
    ax.yaxis.set_major_formatter(lat_formatter)
    con = ax.contourf(lon, lat, rain)
    ax.hold(True)
    ax.coastlines(resolution = '10m')

    # 设置坐标轴范围
    ax.set_xlim([lon[-1,0], lon[0,-1]])
    ax.set_ylim([lat[0,0], lat[-1,-1]])
    ax.set_adjustable('box-forced')
    
fig.subplots_adjust(hspace = 0.05, wspace = 0.05)    
leg = fig.colorbar(con, ax= axes.ravel().tolist(), pad = 0.01)
#plt.savefig("panel.eps")    
plt.show()

除了这尴尬的 colormap ,其它的都很不错,而且能够和 matplotlib 很好的结合。这就是我比较喜欢使用 Cartopy 的


注:https://stackoverflow.com/questions/13784201/matplotlib-2-subplots-1-colorbar

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气象杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档