Cartopy画地图第八天(冷空气南下,NCL色标使用)

相信很多朋友都看过这张漂亮的图吧

这是中国气象爱好者公众号画的一张反映冷空气的图片,当时就被惊艳到了,本帖就来复刻一下这张图。
本次的知识点大概总结一下就是:
1.画风的箭头流场
2.单画某一根等值线,比如588,0℃
3.引入NCL色标
4.制作gif图片
先上个效果图

一、分析图片

中国气象爱好者的图片拿到手以后开始分析
1.500的位势高度画等值线
2.850的温度填色
3.0℃等值线
4.588画等值线
5.850风场的箭头流场
6.注意投影方式
其实也不难,一个一个画就好了。

二、函数准备

(一)、使用NLC色标的函数

import re
import matplotlib.cm
from matplotlib import colors
import matplotlib.pyplot as plt
import numpy as np
class Colormap(colors.ListedColormap):def __init__(self, c, name='from_list', n=None):self.colors = cself.name = nameself.N = nsuper(Colormap, self).__init__(self.colors, name=self.name, N=self.N)def __getitem__(self, item):return Colormap(self.colors[item], name='sliced_' + self.name)def show(self):a = np.outer(np.ones(10), np.arange(0, 1, 0.001))plt.figure(figsize=(2.5, 0.5))plt.subplots_adjust(top=0.95, bottom=0.05, left=0.01, right=0.99)plt.subplot(111)plt.axis('off')plt.imshow(a, aspect='auto', cmap=self, origin='lower')plt.text(0.5, 0.5, self._name,verticalalignment='center', horizontalalignment='center',fontsize=12, transform=plt.gca().transAxes)plt.show()
def coltbl(cmap_file):pattern = re.compile(r'(\d\.?\d*)\s+(\d\.?\d*)\s+(\d\.?\d*).*')with open(cmap_file) as cmap:cmap_buff = cmap.read()cmap_buff = re.compile('ncolors.*\n').sub('', cmap_buff)if re.search(r'\s*\d\.\d*', cmap_buff):return np.asarray(pattern.findall(cmap_buff), 'f4')else:return np.asarray(pattern.findall(cmap_buff), 'u1') / 255.
def get_my_cmaps(cname):try:if cname in matplotlib.cm._cmap_registry:return matplotlib.cm.get_cmap(cname)except:passcmap_file = os.path.join( cname+ ".rgb")cmap = Colormap(coltbl(cmap_file), name=cname)matplotlib.cm.register_cmap(name=cname, cmap=cmap)return cmap

一个类,俩函数,大家可以研究一下怎么实现引入NCL色标的,这里因为篇幅的关系,就不介绍了,有兴趣的朋友可以留言,下次单独出一期来介绍引入NCL色标的原理。

(二)、数据读取的函数

本次数据使用的是Micaps导出的二进制欧细资料,读取函数如下

from read_mdfs import MDFS_Grid
from scipy.interpolate import interpolate
def get_lat_lon(filepath):#获取经纬度数据a = MDFS_Grid(filepath)lon = a.data['Lon']lat = a.data['Lat'][::-1]#翻了纬度lon_scipy = np.arange(lon.min(), lon.max(), 0.05)#插值lat_scipy = np.arange(lat.min(), lat.max(), 0.05)return lon,lat,lon_scipy,lat_scipy
def read_data_hgt_or_tmp(filepath,lon,lat,lon_scipy,lat_scipy):#读位势高度和温度a = MDFS_Grid(filepath)data = a.data['Grid'][::8,::8]#为了数据更平滑,降低了精度spline = interpolate.RectBivariateSpline(lat[::8], lon[::8],data,)data = spline(lat_scipy,lon_scipy)#插值return data[::-1,:]#翻了纬度
def read_data(filepath):#读取一般数据,这里是风a = MDFS_Grid(filepath)data = a.data['Grid']return data[::-1,:]#翻了纬度

(三)、地图数据读取

后面画图为了做gif图片,所以要画好几次地图,但是读取地图数据可以一次完成,想办法减少运行时间是个好习惯哦。

with open('CN-border-La.dat') as src:context = src.read()blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]

(四)、其他准备

fig = plt.figure(figsize=(47, 30), dpi=30)#画布的设置,也是一次就够了,画完一张图清空一次就好了,减少运行内存。
frames = []#用来存放图片的列表,为的是制作gif
TIMES = ['000','003','006','009','012']#做循环用的时次

三、循环画图

(一)、读取数据

for TIME in TIMES:#读取经纬度、500位势高度file_path = r"ECMWF_HR\ECMWF_HR_HGT_500_21122420." + TIMElon ,lat,lon_scipy,lat_scipy = get_lat_lon(file_path)hgt_500 = read_data_hgt_or_tmp(file_path,lon ,lat,lon_scipy,lat_scipy)#读取850温度file_path = r"ECMWF_HR\ECMWF_HR_TMP_850_21122420." + TIMEtem_850 = read_data_hgt_or_tmp(file_path,lon ,lat,lon_scipy,lat_scipy)#读取850U风file_path = r"ECMWF_HR\ECMWF_HR_UGRD_850_21122420." + TIMEu_850 = read_data(file_path)#读取850V风file_path = r"ECMWF_HR\ECMWF_HR_VGRD_850_21122420." + TIMEv_850 = read_data(file_path)

(二)、画图和地图设置

#加子图,做一些地图设置ax = fig.add_axes([0.02, 0.05, 0.9, 0.9], projection=ccrs.LambertConformal(central_latitude=90, central_longitude=105))extent = [80,130,20,55]ax.set_extent(extent,crs=ccrs.Geodetic())gl = ax.gridlines( draw_labels=True, linewidth=2, color='k', alpha=0.5, linestyle='--')gl.xformatter = LONGITUDE_FORMATTER  ##坐标刻度转换为经纬度样式gl.yformatter = LATITUDE_FORMATTERgl.xlabel_style = {'size': 30}gl.ylabel_style = {'size': 30}resolution_map = '50m'ax.add_feature(cfeature.OCEAN.with_scale(resolution_map))ax.add_feature(cfeature.LAND.with_scale(resolution_map))ax.add_feature(cfeature.RIVERS.with_scale(resolution_map))ax.add_feature(cfeature.LAKES.with_scale(resolution_map))for line in borders:ax.plot(line[0::2], line[1::2], '-', color='k',transform=ccrs.Geodetic())

这些也不介绍了,在之前的帖子有介绍,可以往前学习。

(三)、500位势高度和588、0℃线绘制

#画500位势高度ct = ax.contour(lon_scipy, lat_scipy, hgt_500, 20, colors='k',linewidths=3, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')#单画一遍588,红色clev = [588]ct = ax.contour(lon_scipy, lat_scipy, hgt_500, clev, colors='r',linewidths=3, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')#画0℃线,白色clev = [0.0]ct = ax.contour(lon_scipy, lat_scipy, tem_850, clev, colors='w',linewidths=5, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')

(四)、850温度绘制

#画850温度clevs = range(-45,46,3)#引入NCL色标my_cmap = get_my_cmaps("MPL_hsv")#翻转色标my_cmap = my_cmap.reversed()#填色cf = ax.contourf(lon_scipy, lat_scipy, tem_850, clevs, transform=ccrs.PlateCarree(), cmap=my_cmap)#设置色标position = fig.add_axes([0.92, 0.05, 0.02, 0.9])cb = fig.colorbar(cf, cax=position, orientation='vertical',ticks=range(-45,46,3))cb.set_label('Temperature ℃', fontdict={'size': 30})cb.ax.tick_params(which='major', direction='in', length=6, labelsize=30)

这里使用了 get_my_cmaps()函数,这是自己写的,在文章开头有说明,要使用他得到NCL的色标MPL_hsv,同时需要在文件夹中放入MPL_hsv.rgb文件,有需要的朋友可以留下邮箱,作者给你们发。

(五)、850风场箭头绘制

#画风流场step = 5#设置步长,防止箭头过密ax.quiver(lon[::step],lat[::step],u_850[::step,::step],v_850[::step,::step],color='w',scale=600, width=0.002, pivot='mid', transform=ccrs.PlateCarree())

(六)、其他设置,制作GIF

#显示预报时次ax.text(0.85, -0.03, '21122420+' + TIME,transform=ax.transAxes, fontsize=50)#设置图片标题ax.set_title('ECMWF 850mb Temperature(shaded),Wind(vector)&500mb Geopotential Height(contour)',color='k',fontsize= 60)#保存单张图片plt.savefig(TIME+'.png', dpi=30)#清理画布plt.clf()#将绘制gif需要的静态图片名放入列表frames.append(imageio.imread(TIME+'.png'))
#跳出循环,制作GIF并保存
imageio.mimsave('aa.gif', frames, 'GIF', duration=1.0)

三、完整代码

from read_mdfs import MDFS_Grid
import re
import matplotlib.cm
from matplotlib import colors
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interpolateimport cartopy.crs as ccrs
from cartopy.mpl.gridliner import LATITUDE_FORMATTER, LONGITUDE_FORMATTER
import cartopy.feature as cfeature
import os
import imageioclass Colormap(colors.ListedColormap):def __init__(self, c, name='from_list', n=None):self.colors = cself.name = nameself.N = nsuper(Colormap, self).__init__(self.colors, name=self.name, N=self.N)def __getitem__(self, item):return Colormap(self.colors[item], name='sliced_' + self.name)def show(self):a = np.outer(np.ones(10), np.arange(0, 1, 0.001))plt.figure(figsize=(2.5, 0.5))plt.subplots_adjust(top=0.95, bottom=0.05, left=0.01, right=0.99)plt.subplot(111)plt.axis('off')plt.imshow(a, aspect='auto', cmap=self, origin='lower')plt.text(0.5, 0.5, self._name,verticalalignment='center', horizontalalignment='center',fontsize=12, transform=plt.gca().transAxes)plt.show()
def coltbl(cmap_file):pattern = re.compile(r'(\d\.?\d*)\s+(\d\.?\d*)\s+(\d\.?\d*).*')with open(cmap_file) as cmap:cmap_buff = cmap.read()cmap_buff = re.compile('ncolors.*\n').sub('', cmap_buff)if re.search(r'\s*\d\.\d*', cmap_buff):return np.asarray(pattern.findall(cmap_buff), 'f4')else:return np.asarray(pattern.findall(cmap_buff), 'u1') / 255.
def get_my_cmaps(cname):try:if cname in matplotlib.cm._cmap_registry:return matplotlib.cm.get_cmap(cname)except:passcmap_file = os.path.join( cname+ ".rgb")cmap = Colormap(coltbl(cmap_file), name=cname)matplotlib.cm.register_cmap(name=cname, cmap=cmap)return cmapdef get_lat_lon(filepath):#获取经纬度数据a = MDFS_Grid(filepath)lon = a.data['Lon']lat = a.data['Lat'][::-1]#翻了纬度lon_scipy = np.arange(lon.min(), lon.max(), 0.05)#插值lat_scipy = np.arange(lat.min(), lat.max(), 0.05)return lon,lat,lon_scipy,lat_scipy
def read_data_hgt_or_tmp(filepath,lon,lat,lon_scipy,lat_scipy):#读位势高度和温度a = MDFS_Grid(filepath)data = a.data['Grid'][::8,::8]#为了数据更平滑,降低了精度spline = interpolate.RectBivariateSpline(lat[::8], lon[::8],data,)data = spline(lat_scipy,lon_scipy)#插值return data[::-1,:]#翻了纬度
def read_data(filepath):#读取一般数据,这里是风a = MDFS_Grid(filepath)data = a.data['Grid']return data[::-1,:]#翻了纬度with open('CN-border-La.dat') as src:context = src.read()blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]
#画布的设置,也是一次就够了,画完一张图清空一次就好了,减少运行内存。
fig = plt.figure(figsize=(47, 30), dpi=30)
#用来存放图片的列表,为的是制作gif
frames = []
#做循环用的时次
TIMES = ['000','003','006','009','012']
#循环开始
for TIME in TIMES:#读取经纬度、500位势高度file_path = r"ECMWF_HR\ECMWF_HR_HGT_500_21122420." + TIMElon ,lat,lon_scipy,lat_scipy = get_lat_lon(file_path)hgt_500 = read_data_hgt_or_tmp(file_path,lon ,lat,lon_scipy,lat_scipy)#读取850温度file_path = r"ECMWF_HR\ECMWF_HR_TMP_850_21122420." + TIMEtem_850 = read_data_hgt_or_tmp(file_path,lon ,lat,lon_scipy,lat_scipy)#读取850U风file_path = r"ECMWF_HR\ECMWF_HR_UGRD_850_21122420." + TIMEu_850 = read_data(file_path)#读取850V风file_path = r"ECMWF_HR\ECMWF_HR_VGRD_850_21122420." + TIMEv_850 = read_data(file_path)#加子图,做一些地图设置ax = fig.add_axes([0.02, 0.05, 0.9, 0.9], projection=ccrs.LambertConformal(central_latitude=90, central_longitude=105))extent = [80,130,20,55]ax.set_extent(extent,crs=ccrs.Geodetic())gl = ax.gridlines( draw_labels=True, linewidth=2, color='k', alpha=0.5, linestyle='--')gl.xformatter = LONGITUDE_FORMATTER  ##坐标刻度转换为经纬度样式gl.yformatter = LATITUDE_FORMATTERgl.xlabel_style = {'size': 30}gl.ylabel_style = {'size': 30}resolution_map = '50m'ax.add_feature(cfeature.OCEAN.with_scale(resolution_map))ax.add_feature(cfeature.LAND.with_scale(resolution_map))ax.add_feature(cfeature.RIVERS.with_scale(resolution_map))ax.add_feature(cfeature.LAKES.with_scale(resolution_map))for line in borders:ax.plot(line[0::2], line[1::2], '-', color='k',transform=ccrs.Geodetic())#画500位势高度ct = ax.contour(lon_scipy, lat_scipy, hgt_500, 20, colors='k',linewidths=3, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')#单画一遍588,红色clev = [588]ct = ax.contour(lon_scipy, lat_scipy, hgt_500, clev, colors='r',linewidths=3, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')#画0℃线,白色clev = [0.0]ct = ax.contour(lon_scipy, lat_scipy, tem_850, clev, colors='w',linewidths=5, transform=ccrs.PlateCarree())ax.clabel(ct, inline=True, fontsize=30, fmt='%d')#画850温度clevs = range(-45,46,3)#引入NCL色标my_cmap = get_my_cmaps("MPL_hsv")#翻转色标my_cmap = my_cmap.reversed()#填色cf = ax.contourf(lon_scipy, lat_scipy, tem_850, clevs, transform=ccrs.PlateCarree(), cmap=my_cmap)#设置色标position = fig.add_axes([0.92, 0.05, 0.02, 0.9])cb = fig.colorbar(cf, cax=position, orientation='vertical',ticks=range(-45,46,3))cb.set_label('Temperature ℃', fontdict={'size': 30})cb.ax.tick_params(which='major', direction='in', length=6, labelsize=30)#画风流场step = 5#设置步长,防止箭头过密ax.quiver(lon[::step],lat[::step],u_850[::step,::step],v_850[::step,::step],color='w',scale=600, width=0.002, pivot='mid', transform=ccrs.PlateCarree())#显示预报时次ax.text(0.85, -0.03, '21122420+' + TIME,transform=ax.transAxes, fontsize=50)#设置图片标题ax.set_title('ECMWF 850mb Temperature(shaded),Wind(vector)&500mb Geopotential Height(contour)',color='k',fontsize= 60)#保存单张图片plt.savefig(TIME+'.png', dpi=30)#清理画布plt.clf()#将绘制gif需要的静态图片名放入列表frames.append(imageio.imread(TIME+'.png'))
#跳出循环,制作GIF并保存
imageio.mimsave('aa.gif', frames, 'GIF', duration=1.0)

这样,图片就复刻成功了

需要数据文件和代码的请留言邮箱,作者给发

Cartopy画地图第八天(冷空气南下,NCL色标使用)相关推荐

  1. Cartopy画地图第七天(python画浮雕地图和比例尺)

    Cartopy画地图第七天(python画浮雕地图和比例尺) 本文利用了python.cartopy进行了浮雕地图的绘制,同时还画了比例尺. 先上图为敬,一些图例符号不对请不要介意,随便表示的 第一. ...

  2. 小白学习cartopy画地图的第六天

    小白学习cartopy画地图的第六天 从开始学习画地图开始,就是打算用cartopy的,但是不知不觉跑偏了,跑去了Basemap,最近感觉这样不对,因为Basemap已经停止更新了,主要还是个人觉得c ...

  3. 小白学习cartopy画地图的第一天(中国行政区域图,含南海)

    小白学习cartopy画地图的第一天(中国行政区域图,含南海) 这是地图小白的我学习用cartopy画地图的第一天,慢慢摸索慢慢学习,一步一步学会使用cartopy.后面会持续更新.其中很多是从各个博 ...

  4. ncl显著性打点问题or画地图问题

    ncl显著性打点出错: 只能单独画出panel组图,无法overlay叠加打点图,但是打点图可以单独画出来 一开始一直以为是panel在作怪,最后才发现是没有给prob变量设置经纬度的属性: ( 内心 ...

  5. python用cartopy包画地图_python绘制地图的利器Cartopy使用说明

    python绘制地图一般使用Basemap绘图包,但该包配置相对较繁琐,自定义性不强,这里介绍一个绘制地图的利器Cartopy,个人认为该工具方便.快捷,附上一些自己写的程序. 准备工作,工欲善其事, ...

  6. python三维图能画地图_使用Python绘制地图的三大秘密武器

    原标题:使用Python绘制地图的三大秘密武器 Python地图可视化库有大家熟知的pyecharts.plotly.folium,还有稍低调的bokeh.basemap.geopandas,也是地图 ...

  7. 小白学习Basemap气象画地图的第三天(中国温度分布图,mask外部)

    小白学习Basemap气象画地图的第三天(中国温度分布图,mask外部) 首先还是感谢公众号(气象学家),代码和测试数据来自与他,不过这次有长进了,自己学会修改了.还是逐条向大家解释. (和大家分享一 ...

  8. echarts geo地图示例_python小白的画地图合集(使用pyecharts)

    经过今晚的小摸索,终于可以画出世界地图.省级地图以及全国的热力图.所以特此决定出一个小的合集,建议先去阅读上一篇写的画中国地图,可能那样子你会很快速了解到画图的精髓. 画世界地图 依旧是上次的套路: ...

  9. 阻止地图的放大和缩小_Arcgis画地图详细步骤(真的!!)

    在学习了python画地图之后,继续进行地图的学习,Arcgis画地图的详细步骤来也!!! 1.打开Arcgis点击取消 2.点击添加数据 3.导入shp文件:找到电脑中shp文件的位置,单击选择之后 ...

最新文章

  1. menu.php,menu.php
  2. 如何用Netty实现一个轻量级的HTTP代理服务器
  3. PYTHON2.day06
  4. 印度软件水平和中国的程序员
  5. NUC1131 Triangle【DP】
  6. Python开发手册
  7. 10款国外知名杀软的免费试用版(三个月、半年或一年)
  8. 【数据库实验一】基础操作
  9. 车载android播放器,KX万能播放器
  10. Icon图标格式(用于生成*.ico图标)
  11. matlab求条件概率密度_你真的会用程序求多重积分吗?
  12. 兼容android 6.0以上获取设备编号等权限
  13. 常用十大免费建站程序介绍
  14. mysql 1033 frm_修复mysqldump Incorrect information in file frm (1033)
  15. 软考中级之系统集成项目管理工程师备考
  16. 使用Tensorflow Object Detection API进行集装箱识别并对集装箱号进行OCR识别
  17. Android 设置铃声——给app设置自定义铃声功能
  18. 111、Flutter 实现动画颜色渐变效果
  19. SIR传染模型Matlab代码,sir传染病模型 MATLAB代码运行不了,
  20. 操作系统 - Linux

热门文章

  1. java和python中函数式编程
  2. 网络层(2.网际协议IP)
  3. ftl模板导出excel_freemarker导出定制excel
  4. 微信公众号可以改名称了,只限个人订阅号!
  5. AI圣经《深度学习》作者斩获2018年图灵奖,100 万奖励!...
  6. 【Chips】如何启动第一个Quartus/Vivado下的Verilog仿真过程
  7. Python量策风指标
  8. [刷题]leetcode\167_两数之和Ⅱ
  9. android设置背景平铺
  10. unity打包游戏后物体的移动速度不一样?