社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

气象编程 | 如何用python绘制高空环流图(精美出图)

气象学家 • 1 年前 • 1063 次点击  

  第一时间获取气象科研资讯

气象学家公众号交流群

加入


日常天气预报业务和科研工作,都离不开高空环流分析,尤其是一些比较重要的天气过程,都需要我们绘制850hPa、700hPa、500hPa等常见等压面的高度场、温度场、风场、湿度场等一个要素或多个要素的叠加图,来分析天气形势。
我比较喜欢把绘图代码以类class()的形式写出来,后面如果有要修改升级的,就可以直接通过类的继承来写新的代码。这样,原先的代码也会继续保存,有需要时也能挖出来顶一顶
类的具体解释可以见旧文:
如何用python写类(class)并继承
写代码第一步,把需要的包都import进来:
import matplotlib.pyplot as pltimport xarray as xr    #读取nc文件import numpy as npimport osimport cartopy.crs as ccrs   #投影方式import cartopy.feature as cfeat   #使用shp文件from cartopy.io.shapereader import Reader  #读取自定的shp文件from cartopy.mpl.ticker import LongitudeFormatter,LatitudeFormatter  #将x,y轴换成经纬度import metevaimport meteva.base as mebimport meteva.product as mpdfrom meteva.base.tool.plot_tools import add_china_map_2basemapfrom cal_time import delta_time, cal_time_targetimport cmapsimport metpy.calc as mpcalcplt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

然后,写我最喜欢的类:
class draw_plevel(object):    def __init__(self,level='500',save_path='./高空天气图',title='高空天气图',\                 lon = np.linspace(0.0,359.75,1440), lat = np.linspace(-90.0,90.0,721),\


    
                 z=None, rh=None, t=None, u=None, v=None,map_extend=None,add_minmap='right',dpi=300):        '''        z: 位势高度        rh: 相对湿度        t: 温度        u: 纬向风        v: 经向风        map_extend: 绘图区域,[lon_min, lon_max, lat_min, lat_max]        add_minmap: 是否绘制南海小图。False: 不画; 'right': 画在右下角,'left': 画在左下角        '''        self.level = level        self.save_path = save_path        self.title = title        self.lon = lon        self.lat = lat        self.z = z        self.rh = rh        self.t = t        self.u = u        self.v = v        self.map_extend = map_extend        self.add_minmap = add_minmap        self.dpi = dpi
下面开始写具体的函数:
    def draw_circulation(self):        lons, lats = np.meshgrid(self.lon,self.lat)        proj = ccrs.PlateCarree()        # 通过经纬度范围设置画幅        hight = 5.6        title_hight = 0.3        legend_hight = 0.6        left_plots_width = 0        right_plots_width = 0        width = (hight - title_hight - legend_hight) * len(self.lon) / len(self.lat) + left_plots_width + right_plots_width        map_width = width - left_plots_width - right_plots_width
fig = plt.figure(figsize=(width, hight),dpi=self.dpi) # 设置画幅的布局方式 rect = [left_plots_width / width, 0.05, (width - right_plots_width - left_plots_width) / width, 0.95] # 左下宽
ax = fig.subplots(1, 1, subplot_kw={'projection':proj})        # 设置绘图区域 if self.map_extend is None: ax.set_extent(self.map_extend, proj) # 设置绘图区域
下面,进行地图属性的设置:
        country_shp = Reader('./shp/CHN_adm1.shp')        pro_shp = Reader('./shp/provinces.shp')        fea_country = cfeat.ShapelyFeature(country_shp.geometries(), proj,                                           edgecolor='darkolivegreen', facecolor='ivory')
ax.add_feature(fea_country, linewidth=0.2, alpha=0.2) fea_pro = cfeat.ShapelyFeature(pro_shp.geometries(), proj, edgecolor='darkolivegreen', facecolor='none') ax.add_feature(fea_pro, linewidth=0.3, alpha=0.5) ax.add_feature(cfeat.OCEAN, alpha=0.5)

# 设置地图属性:加载国界、海岸线、河流、湖泊 ax.add_feature(cfeat.BORDERS.with_scale('50m'), linewidth=0.8, zorder=1) ax.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=0.6, zorder=1) ax.add_feature(cfeat.RIVERS.with_scale('50m'), zorder=1) ax.add_feature(cfeat.LAKES.with_scale('50m'), zorder=1)
# 绘制中国省界 ax.add_geometries(Reader('./shp/CHN_adm1.shp').geometries(), ccrs.PlateCarree(), \ facecolor = 'none', edgecolor = 'gray', linewidth = 0.8)

接下来是经纬度设置:
        # 打开绘图边框及经纬度。'on'为打开,'off'为关闭        ax.axis('on')
# 设置经纬度格式,指定标出的经纬度 ax.set_xticks([80,90,100,110,120,130]) ax.set_yticks([10,20,30,40,50]) ax.xaxis.set_major_formatter(LongitudeFormatter()) ax.yaxis.set_major_formatter(LatitudeFormatter())

下面,就开始绘制等高线、等温线、风向杆、湿度填色图啦。其中,等高线除了588线用红色并加粗表示外,其他都为蓝色曲线:
        # 画等高线        z_levels = np.arange(0, 2000+10, 4)        z_levels = np.delete(z_levels, np.where(z_levels==588))
ac = ax.contour(lons[lat_id1:lat_id2,lon_id1:lon_id2], lats[lat_id1:lat_id2,lon_id1:lon_id2],\ self.z[lat_id1:lat_id2,lon_id1:lon_id2], levels=z_levels, extent='both', colors='mediumblue', linewidths=0.8) plt.clabel(ac, inline=True, fontsize=8, fmt='%.0f') ac588 = ax.contour(lons[lat_id1:lat_id2,lon_id1:lon_id2], lats[lat_id1:lat_id2,lon_id1:lon_id2],\ self.z[lat_id1:lat_id2,lon_id1:lon_id2], levels=np.arange(588,590,4), extent='both', colors='red', linewidths=0.9) plt.clabel(ac588, inline=True, fontsize=9, fmt='%.0f')
# 画等温线(虚线) t_levels = np.arange(-40, 30, 4) at = ax.contour(lons[lat_id1:lat_id2,lon_id1:lon_id2], lats[lat_id1:lat_id2,lon_id1:lon_id2],\ self.t[lat_id1:lat_id2,lon_id1:lon_id2], levels=t_levels, extent='both', colors='red', linewidths=0.5, linestyle=np.where(self.t>=0,'-','--')) plt.clabel(at, inline=True, fontsize=5, fmt='%.0f')
# 画风向杆 ax.barbs(lons[lat_id1:lat_id2:12,lon_id1:lon_id2:12], lats[lat_id1:lat_id2:12,lon_id1:lon_id2:12], self.u[lat_id1:lat_id2:12,lon_id1:lon_id2:12],self.v[lat_id1:lat_id2:12,lon_id1:lon_id2:12], barb_increments={'half':2,'full':4,'flag':20}, zorder=5, length=5, linewidth=0.2)
ax.set_title(self.title,fontsize=12)
# 画湿度 rh_levels = (60,70,80,90,95,100) aq = ax.contourf(lons[lat_id1:lat_id2,lon_id1:lon_id2], lats[lat_id1:lat_id2,lon_id1:lon_id2],\ self.rh[lat_id1:lat_id2,lon_id1:lon_id2],levels=rh_levels,transform=ccrs.PlateCarree(), cmap=cmaps.CBR_wet[:-2])        cbar = fig.colorbar(aq,shrink=0.8) cbar.ax.set_title('%') cbar.set_ticks((60,70 ,80,90,95,100)) plt.clabel(ac, inline=True, fontsize=8, fmt='%.0f')
图区域果涵盖了南海九段线覆盖区域,则需要绘制南海小图。这里,绘图函数最早计算的图形相关参数就都用上了,用以保证南海小图在整个图片的右下角
        # 画南海小图        if self.add_minmap is not False:            draw_minmap(self.add_minmap, rect, hight, width)
保存图片:
        # 保存图片        fig.savefig(self.title+'.png',dpi=self.dpi)        fig.show()

这里贴一下绘制南海小图的函数,绘图的时候直接调用就可以:
def draw_minmap(add_minmap,rect1, height, width):    minmap_lon_lat = [103, 123, 0, 25]    minmap_height_rate = 0.27    height_bigmap = rect1[3]    height_minmap = height_bigmap * minmap_height_rate    width_minmap = height_minmap * (minmap_lon_lat[1] - minmap_lon_lat[0]) * height / (    minmap_lon_lat[3] - minmap_lon_lat[2]) / width
width_between_two_map = height_bigmap * 0.01
width_minmap = 0.2 width_between_two_map = 0.1 sy_minmap = width_between_two_map + rect1[1] if add_minmap == "left": sx_minmap = rect1[0] + width_between_two_map else: sx_minmap = rect1[0] + rect1[2] - width_minmap - width_between_two_map rect_min = [sx_minmap, sy_minmap, width_minmap, height_minmap] rect_min = [0.63, 0.112, 0.1, 0.13] ax_min = plt.axes(rect_min) plt.xticks([]) plt.yticks([]) ax_min.set_xlim((minmap_lon_lat[0], minmap_lon_lat[1])) ax_min.set_ylim((minmap_lon_lat[2], minmap_lon_lat[3])) ax_min.spines["top"].set_linewidth(0.3) ax_min.spines["bottom"].set_linewidth(0.3) ax_min.spines["right"].set_linewidth(0.3) ax_min.spines["left"].set_linewidth(0.3) add_china_map_2basemap(ax_min, name="world", edgecolor='k', lw=0.2, encoding='gbk', grid0=None) # "国界" add_china_map_2basemap(ax_min, name="nation", edgecolor='k', lw=0.2, encoding='gbk', grid0=None) # "省界"

这样,就实现了高空环流图的绘制。我们可以根据需要注释掉部分绘图模块,比如注释掉温度场,只留高度场、风场和湿度场的叠加。以500hPa为例,绘图效果如下:






声明:欢迎转载、转发本号原创内容,可留言区留言或者后台联系小编(微信:gavin7675)进行授权。气象学家公众号转载信息旨在传播交流,其内容由作者负责,不代表本号观点。文中部分图片来源于网络,如涉及作品内容、版权和其他问题,请后台联系小编处理。


往期推荐

 获取ERA5-Land陆面高分辨率再分析数据(32TB)

 1942-2022年中国地面气象站观测数据免费分享

 获取全球GPM降水数据,半小时/逐日(4TB)

 获取1998-2019 TRMM 3B42逐日降水数据

★ 获取最新版本CMIP6降尺度数据集30TB

★ 获取ERA5常用变量再分析数据26TB

 EC数据商店推出Python在线处理工具箱

★ EC打造实用气象Python工具Metview

★ 机器学习简介及在短临天气预警中的应用

★ Nature-地球系统科学领域的深度学习及理解

★ 采用神经网络与深度学习来预报降水、温度

★ 灵魂拷问:ChatGPT对气象人的饭碗是福是祸?

★ 气象局是做啥的?气象局的薪水多少?

★ 一位气象学家尝试ChatGPT复现Nature子刊的研究,他真的会面临失业吗?!

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/163283
 
1063 次点击