1. 效果图

在这里插入图片描述
前序博文cnmaps填色图介绍了cnmaps在线地图库如何绘制省级边界和白化,cartopy白化介绍了如何用cartopy白化中国地区(包含南海小地图和九段线),这篇博文可以说是两者的结合,即用cnmaps+cartopy白化中国地区并添加南海小地图,是更为方便简洁的中国地区白化方法。

2. 绘制基于中国地区的填色图(大地图)

这块主要绘制的是填色的中国大地区,并白化,和前序博文cnmaps填色图的思路基本一致,即:

  1. 利用get_adm_maps获取地图边界
  2. ax.contourf绘制填色图
  3. clip_contours_by_map 对中国地区进行白化
  4. draw_maps绘制中国地图边界
  5. ax.coastlines() 绘制海岸线
  6. ax.set_extent确定大地图显示的经纬度范围
  7. 设置标题、添加经纬度和colorbar

值得注意的是,如果要添加南海九段线,绘制地图的时候要用map的返回值,如果用map_oneline,则没有九段线,只有南海诸岛。而对于白化来说,一定要使用map的地图返回,不然会报错,所以,代码里地图的返回值用了两种方式。本人还没发现更好的解决这个问题的办法,如果其他同学发现了,欢迎在评论区交流。

def map_plot(fig,ax,lat,lon,data, is_mask, is_province_boundary,title):
  # 获取地图
  big_map = get_adm_maps(country='中华人民共和国', level='国')  #包含南海九段线,用于地图绘制
  big_map_oneline = get_adm_maps(country='中华人民共和国', level='国', record='first', only_polygon=True)  #用于白化
  #绘制填色图
  cf = ax.contourf(lon, lat,data, cmap=plt.cm.jet,levels=np.linspace(-12, 30, 43),transform=ccrs.PlateCarree())
  
  #设置是否白化,白化必须基于一条边界(jingjinji2)
  if is_mask:
     clip_contours_by_map(cf, big_map_oneline)

  #绘制地图
  draw_maps(big_map,linewidth=1.2, color='k')    #仅绘制所有省份的一条边界

  #添加海岸线
  ax.coastlines()

  #设置显示区域
  ax.set_extent([70,140,15,55], crs=ccrs.PlateCarree())

  #设置标题
  ax.set_title(title)

  #添加经纬度格网
  gl=ax.gridlines(draw_labels=True,linestyle=":",linewidth=0.1 ,x_inline=False, y_inline=False,color='k')
  gl.top_labels=False #关闭上部经纬标签                                  
  gl.right_labels=False#关闭右边经纬标签   
  gl.rotate_labels=None#关闭兰伯特经纬标签旋转  
  gl.xformatter = LONGITUDE_FORMATTER  #使横坐标转化为经纬度格式            
  gl.yformatter = LATITUDE_FORMATTER   
  
  #添加coloarbar
  fig.colorbar(cf,ax=ax, shrink=0.9,  extendfrac='auto',extendrect=True,location='bottom',fraction=0.05, pad=0.08) 

3. 添加南海小地图

添加南海小地图就是图中图的概念,最关键的有以下几点:

  1. 确定南海小地图的经纬度范围,即box_nanhai
  2. 生成南海小地图的ax_nanhai = fig.add_axes(pos,projection = ccrs.PlateCarree()) ,其中pos为南海小地图在fig中的位置和大小
  3. 按照大地图的方法,用ax_nanhai绘制填色图并白化

这里需要注意的是,绘制南海填色图时,lat, lon, data一定要用南海小地图范围内的数据,不要用全部大地图的数据,不然会出现两个大地图在同一图中。

#----------添加南海小地图------------------
def add_nanhai (ax, pos, lat, lon, data):
    #--------------右下角添加南海地图------------------------------------------
    lon1, lon2, lat1, lat2 = 103, 125, 2, 25
    box_nanhai=[lon1, lon2, lat1, lat2]  #南海小地图的经纬度位置
    ax_nanhai = fig.add_axes(pos,projection = ccrs.PlateCarree())  #定义ax_nanhai
    
   #  #重新选择data数据,削减掉box_nanhai以外的数据,不然会把整个大地图填色再添加到图中
   #  lon_new = lon[]
    # 重复大地图的画图步骤
    nanhai = get_adm_maps(country='中华人民共和国', level='国') #包含南海九段线,用于地图绘制
    nanhai_oneline = get_adm_maps(country='中华人民共和国', level='国', record='first', only_polygon=True) #用于白化
    ax_nanhai.set_extent(box_nanhai, crs=ccrs.PlateCarree())
    cf = ax_nanhai.contourf(lon.loc[lon1:lon2], lat.loc[lat1:lat2],data.loc[lat1:lat2, lon1:lon2], cmap=plt.cm.jet,levels=np.linspace(-12, 30, 43),transform=ccrs.PlateCarree())
    clip_contours_by_map(cf, nanhai_oneline)
    draw_maps(nanhai,linewidth=0.8, color='k')
    ax_nanhai.coastlines()

4. 读取数据并传入绘图函数

  1. 读取数据:使用的是ERA5的2m温度日均值(nc数据),并用xarray读取并做月平均,最后得到的temp是二维数组(lat, lon),比较简单,不用介绍了。
# read data
data_path = "D:/ERA5/era5_for_o3/download_daily_mean_2m_temperature_2022_04.nc"
ds = xr.open_dataset(data_path)
temp = ds['t2m'].mean('time')-273.17    #求月均值,并换算为百帕
lat, lon = ds['lat'], ds['lon']
  1. 定义画布并将数据传入绘图函数
    将fig, ax, lat, lon, data等先后传入大地图函数map_plot和南海小地图函数add_nanhai中,大功告成啦,也可用此函数绘制多个子图。
# 定义画布
proj = ccrs.PlateCarree()
fig = plt.figure(figsize=(6, 6))
#调入参数,画图
ax1 = fig.add_subplot(1,1,1, projection=proj)
map_plot(fig, ax1, lat, lon, temp, True, True, 'T2 in April 2022') #绘制大地图
pos1 = [0.78, 0.213, 0.12, 0.12]  #南海小地图位置和长宽,根据画布自己调试
add_nanhai(ax1,pos1,lat,lon,temp)  #添加南海小地图
plt.savefig('t2.jpg')

5. 代码完整版

# %%
import xarray as xr
import numpy as np 
import matplotlib.pyplot as plt
import matplotlib as mpl
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
from cnmaps import get_adm_maps, draw_maps,clip_contours_by_map, draw_map
mpl.rcParams["font.size"] = 13
# %%
#----------------绘制大地图------------------------------
def map_plot(fig,ax,lat,lon,data, is_mask, is_province_boundary,title):
  # 获取地图
  big_map = get_adm_maps(country='中华人民共和国', level='国')  #包含南海九段线,用于地图绘制
  map_oneline = get_adm_maps(country='中华人民共和国', level='国', record='first', only_polygon=True)  #用于白化
  #绘制填色图
  cf = ax.contourf(lon, lat,data, cmap=plt.cm.jet,levels=np.linspace(-12, 30, 43),transform=ccrs.PlateCarree())
  
  #设置是否白化,白化必须基于一条边界(jingjinji2)
  if is_mask:
     clip_contours_by_map(cf, big_map_oneline)

  #绘制地图
  draw_maps(big_map,linewidth=1.2, color='k')    #仅绘制所有省份的一条边界

  #添加海岸线
  ax.coastlines()

  #设置显示区域
  ax.set_extent([70,140,15,55], crs=ccrs.PlateCarree())

  #设置标题
  ax.set_title(title)

  #添加经纬度格网
  gl=ax.gridlines(draw_labels=True,linestyle=":",linewidth=0.1 ,x_inline=False, y_inline=False,color='k')
  gl.top_labels=False #关闭上部经纬标签                                  
  gl.right_labels=False#关闭右边经纬标签   
  gl.rotate_labels=None#关闭兰伯特经纬标签旋转  
  gl.xformatter = LONGITUDE_FORMATTER  #使横坐标转化为经纬度格式            
  gl.yformatter = LATITUDE_FORMATTER   
  
  #添加coloarbar
  fig.colorbar(cf,ax=ax, shrink=0.9,  extendfrac='auto',extendrect=True,location='bottom',fraction=0.05, pad=0.08) 

# %%
#----------添加南海小地图------------------
def add_nanhai (ax, pos, lat, lon, data):
    #--------------右下角添加南海地图------------------------------------------
    lon1, lon2, lat1, lat2 = 103, 125, 2, 25
    box_nanhai=[lon1, lon2, lat1, lat2]  #南海小地图的经纬度位置
    ax_nanhai = fig.add_axes(pos,projection = ccrs.PlateCarree())  #定义ax_nanhai
    
   #  #重新选择data数据,削减掉box_nanhai以外的数据,不然会把整个大地图填色再添加到图中
   #  lon_new = lon[]
    # 重复大地图的画图步骤
    nanhai = get_adm_maps(country='中华人民共和国', level='国') #包含南海九段线,用于地图绘制
    nanhai_oneline = get_adm_maps(country='中华人民共和国', level='国', record='first', only_polygon=True) #用于白化
    ax_nanhai.set_extent(box_nanhai, crs=ccrs.PlateCarree())
    cf = ax_nanhai.contourf(lon.loc[lon1:lon2], lat.loc[lat1:lat2],data.loc[lat1:lat2, lon1:lon2], cmap=plt.cm.jet,levels=np.linspace(-12, 30, 43),transform=ccrs.PlateCarree())
    clip_contours_by_map(cf, nanhai_oneline)
    draw_maps(nanhai,linewidth=0.8, color='k')
    ax_nanhai.coastlines()

# %%
# read data
data_path = "D:/ERA5/era5_for_o3/download_daily_mean_2m_temperature_2022_04.nc"
ds = xr.open_dataset(data_path)
temp = ds['t2m'].mean('time')-273.17    #求月均值,并换算为百帕
lat, lon = ds['lat'], ds['lon']

# %%
# 定义画布
proj = ccrs.PlateCarree()
fig = plt.figure(figsize=(6, 6))
#调入参数,画图
ax1 = fig.add_subplot(1,1,1, projection=proj)
map_plot(fig, ax1, lat, lon, temp, True, True, 'T2 in April 2022') #绘制大地图
pos1 = [0.78, 0.213, 0.12, 0.12]  #南海小地图位置和长宽,根据画布自己调试
add_nanhai(ax1,pos1,lat,lon,temp)  #添加南海小地图
plt.savefig('t2.jpg')
# %%

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐