def draw_gh_uv_mslp(gh=None, uv=None, mslp=None, map_extent=(50, 150, 0, 65), regrid_shape=20, add_china=True, city=True, south_China_sea=True, output_dir=None, Global=False): plt.rcParams['font.sans-serif'] = ['SimHei'] # 步骤一(替换sans-serif字体) plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题) # draw figure plt.figure(figsize=(16, 9)) # set data projection if (Global == True): plotcrs = ccrs.Robinson(central_longitude=115.) else: plotcrs = ccrs.AlbersEqualArea( central_latitude=(map_extent[2] + map_extent[3]) / 2., central_longitude=(map_extent[0] + map_extent[1]) / 2., standard_parallels=[30., 60.]) ax = plt.axes([0.01, 0.1, .98, .84], projection=plotcrs) plt.title('[' + gh.attrs['model'] + '] ' + str(int(gh['level'].values[0])) + 'hPa 位势高度场, ' + str(int(uv['level'].values[0])) + 'hPa 风场, 海平面气压场', loc='left', fontsize=30) datacrs = ccrs.PlateCarree() #adapt to the map ratio map_extent2 = utl.adjust_map_ratio(ax, map_extent=map_extent, datacrs=datacrs) #adapt to the map ratio ax.add_feature(cfeature.OCEAN) utl.add_china_map_2cartopy_public(ax, name='coastline', edgecolor='gray', lw=0.8, zorder=5, alpha=0.5) if add_china: utl.add_china_map_2cartopy_public(ax, name='province', edgecolor='gray', lw=0.5, zorder=5) utl.add_china_map_2cartopy_public(ax, name='nation', edgecolor='black', lw=0.8, zorder=5) utl.add_china_map_2cartopy_public(ax, name='river', edgecolor='#74b9ff', lw=0.8, zorder=5, alpha=0.5) # define return plots plots = {} # draw mean sea level pressure if mslp is not None: x, y = np.meshgrid(mslp['lon'], mslp['lat']) clevs_mslp = np.arange(960, 1065, 5) cmap = guide_cmaps(26) plots['mslp'] = ax.contourf(x, y, np.squeeze(mslp['data']), clevs_mslp, cmap=cmap, alpha=0.8, zorder=1, transform=datacrs) #+画高低压中心 res = mslp['lon'].values[1] - mslp['lon'].values[0] nwindow = int(9.5 / res) mslp_hl = np.ma.masked_invalid(mslp['data'].values).squeeze() local_min, local_max = utl.extrema(mslp_hl, mode='wrap', window=nwindow) #Get location of extrema on grid xmin, xmax, ymin, ymax = map_extent2 lons2d, lats2d = x, y transformed = datacrs.transform_points(datacrs, lons2d, lats2d) x = transformed[..., 0] y = transformed[..., 1] xlows = x[local_min] xhighs = x[local_max] ylows = y[local_min] yhighs = y[local_max] lowvals = mslp_hl[local_min] highvals = mslp_hl[local_max] yoffset = 0.022 * (ymax - ymin) dmin = yoffset #Plot low pressures xyplotted = [] for x, y, p in zip(xlows, ylows, lowvals): if x < xmax - yoffset and x > xmin + yoffset and y < ymax - yoffset and y > ymin + yoffset: dist = [ np.sqrt((x - x0)**2 + (y - y0)**2) for x0, y0 in xyplotted ] if not dist or min(dist) > dmin: #,fontweight='bold' a = ax.text(x, y, 'L', fontsize=28, ha='center', va='center', color='r', fontweight='normal', transform=datacrs) b = ax.text(x, y - yoffset, repr(int(p)), fontsize=14, ha='center', va='top', color='r', fontweight='normal', transform=datacrs) a.set_path_effects([ path_effects.Stroke(linewidth=1.5, foreground='black'), path_effects.SimpleLineShadow(), path_effects.Normal() ]) b.set_path_effects([ path_effects.Stroke(linewidth=1.0, foreground='black'), path_effects.SimpleLineShadow(), path_effects.Normal() ]) xyplotted.append((x, y)) #Plot high pressures xyplotted = [] for x, y, p in zip(xhighs, yhighs, highvals): if x < xmax - yoffset and x > xmin + yoffset and y < ymax - yoffset and y > ymin + yoffset: dist = [ np.sqrt((x - x0)**2 + (y - y0)**2) for x0, y0 in xyplotted ] if not dist or min(dist) > dmin: a = ax.text(x, y, 'H', fontsize=28, ha='center', va='center', color='b', fontweight='normal', transform=datacrs) b = ax.text(x, y - yoffset, repr(int(p)), fontsize=14, ha='center', va='top', color='b', fontweight='normal', transform=datacrs) a.set_path_effects([ path_effects.Stroke(linewidth=1.5, foreground='black'), path_effects.SimpleLineShadow(), path_effects.Normal() ]) b.set_path_effects([ path_effects.Stroke(linewidth=1.0, foreground='black'), path_effects.SimpleLineShadow(), path_effects.Normal() ]) xyplotted.append((x, y)) #-画高低压中心 # draw -hPa wind bards if uv is not None: x, y = np.meshgrid(uv['lon'], uv['lat']) u = np.squeeze(uv['u']) * 2.5 v = np.squeeze(uv['v']) * 2.5 plots['uv'] = ax.barbs(x, y, u.values, v.values, length=6, regrid_shape=regrid_shape, transform=datacrs, fill_empty=False, sizes=dict(emptybarb=0.05), zorder=2) # draw -hPa geopotential height if gh is not None: x, y = np.meshgrid(gh['lon'], gh['lat']) clevs_gh = np.append( np.append( np.arange(0, 480, 4), np.append(np.arange(480, 584, 8), np.arange(580, 604, 4))), np.arange(604, 2000, 8)) linewidths_gh = np.zeros(clevs_gh.shape) + 2 idx_588 = np.where(clevs_gh == 588) linewidths_gh[idx_588[0]] = 4 plots['gh'] = ax.contour(x, y, np.squeeze(gh['data']), clevs_gh, colors='purple', linewidths=linewidths_gh, transform=datacrs, zorder=3) ax.clabel(plots['gh'], inline=1, fontsize=20, fmt='%.0f', colors='black') # grid lines gl = ax.gridlines(crs=datacrs, linewidth=2, color='gray', alpha=0.5, linestyle='--', zorder=4) gl.xlocator = mpl.ticker.FixedLocator(np.arange(0, 360, 15)) gl.ylocator = mpl.ticker.FixedLocator(np.arange(-90, 90, 15)) utl.add_cartopy_background(ax, name='RD') #forecast information l, b, w, h = ax.get_position().bounds bax = plt.axes([l, b + h - 0.1, .25, .1], facecolor='#FFFFFFCC') bax.set_yticks([]) bax.set_xticks([]) bax.axis([0, 10, 0, 10]) initTime = pd.to_datetime(str( gh.coords['forecast_reference_time'].values)).replace( tzinfo=None).to_pydatetime() fcst_time = initTime + timedelta( hours=gh.coords['forecast_period'].values[0]) #发布时间 if (sys.platform[0:3] == 'lin'): locale.setlocale(locale.LC_CTYPE, 'zh_CN.utf8') if (sys.platform[0:3] == 'win'): locale.setlocale(locale.LC_CTYPE, 'chinese') plt.text(2.5, 7.5, '起报时间: ' + initTime.strftime("%Y年%m月%d日%H时"), size=15) plt.text(2.5, 5, '预报时间: ' + fcst_time.strftime("%Y年%m月%d日%H时"), size=15) plt.text(2.5, 2.5, '预报时效: ' + str(int(gh.coords['forecast_period'].values[0])) + '小时', size=15) plt.text(2.5, 0.5, 'www.nmc.cn', size=15) # add color bar cax = plt.axes([l, b - 0.04, w, .02]) cb = plt.colorbar(plots['mslp'], cax=cax, orientation='horizontal', ticks=clevs_mslp[:-1], extend='max', extendrect=False) cb.ax.tick_params(labelsize='x-large') cb.set_label('Mean sea level pressure (hPa)', size=20) # add south China sea if south_China_sea: utl.add_south_China_sea(pos=[l + w - 0.091, b, .1, .2]) small_city = False if (map_extent2[1] - map_extent2[0] < 25): small_city = True if city: utl.add_city_on_map(ax, map_extent=map_extent2, transform=datacrs, zorder=6, size=15, small_city=small_city) utl.add_logo_extra_in_axes(pos=[l - 0.02, b + h - 0.1, .1, .1], which='nmc', size='Xlarge') # show figure if (output_dir != None): plt.savefig(output_dir + '最高温度_预报_' + '起报时间_' + initTime.strftime("%Y年%m月%d日%H时") + '预报时效_' + str(gh.coords['forecast_period'].values[0]) + '小时' + '.png', dpi=200, bbox_inches='tight') if (output_dir == None): plt.show()
def draw_gh_uv_mslp(gh=None, uv=None, mslp=None, map_extent=(50, 150, 0, 65), regrid_shape=20, add_china=True, city=True, south_China_sea=True, output_dir=None, Global=False): plt.rcParams['font.sans-serif'] = ['SimHei'] # 步骤一(替换sans-serif字体) plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题) # draw figure plt.figure(figsize=(16, 9)) # set data projection if (Global == True): plotcrs = ccrs.Robinson(central_longitude=115.) else: plotcrs = ccrs.AlbersEqualArea( central_latitude=(map_extent[2] + map_extent[3]) / 2., central_longitude=(map_extent[0] + map_extent[1]) / 2., standard_parallels=[30., 60.]) ax = plt.axes([0.01, 0.1, .98, .84], projection=plotcrs) plt.title('[' + gh.attrs['model'] + '] ' + str(int(gh['level'].values[0])) + 'hPa 位势高度场, ' + str(int(uv['level'].values[0])) + 'hPa 风场, 海平面气压场', loc='left', fontsize=30) datacrs = ccrs.PlateCarree() #adapt to the map ratio map_extent2 = utl.adjust_map_ratio(ax, map_extent=map_extent, datacrs=datacrs) #adapt to the map ratio ax.add_feature(cfeature.OCEAN) utl.add_china_map_2cartopy_public(ax, name='coastline', edgecolor='gray', lw=0.8, zorder=5, alpha=0.5) if add_china: utl.add_china_map_2cartopy_public(ax, name='province', edgecolor='gray', lw=0.5, zorder=5) utl.add_china_map_2cartopy_public(ax, name='nation', edgecolor='black', lw=0.8, zorder=5) utl.add_china_map_2cartopy_public(ax, name='river', edgecolor='#74b9ff', lw=0.8, zorder=5, alpha=0.5) # define return plots plots = {} # draw mean sea level pressure if mslp is not None: x, y = np.meshgrid(mslp['lon'], mslp['lat']) clevs_mslp = np.arange(960, 1065, 5) cmap = guide_cmaps(26) plots['mslp'] = ax.contourf(x, y, np.squeeze(mslp['data']), clevs_mslp, cmap=cmap, alpha=0.8, zorder=1, transform=datacrs) # draw -hPa wind bards if uv is not None: x, y = np.meshgrid(uv['lon'], uv['lat']) u = np.squeeze(uv['u']) * 2.5 v = np.squeeze(uv['v']) * 2.5 plots['uv'] = ax.barbs(x, y, u.values, v.values, length=6, regrid_shape=regrid_shape, transform=datacrs, fill_empty=False, sizes=dict(emptybarb=0.05), zorder=2) # draw -hPa geopotential height if gh is not None: x, y = np.meshgrid(gh['lon'], gh['lat']) clevs_gh = np.append( np.append( np.arange(0, 480, 4), np.append(np.arange(480, 584, 8), np.arange(580, 604, 4))), np.arange(604, 2000, 8)) plots['gh'] = ax.contour(x, y, np.squeeze(gh['data']), clevs_gh, colors='purple', linewidths=2, transform=datacrs, zorder=3) ax.clabel(plots['gh'], inline=1, fontsize=20, fmt='%.0f', colors='black') # grid lines gl = ax.gridlines(crs=datacrs, linewidth=2, color='gray', alpha=0.5, linestyle='--', zorder=4) gl.xlocator = mpl.ticker.FixedLocator(np.arange(0, 360, 15)) gl.ylocator = mpl.ticker.FixedLocator(np.arange(-90, 90, 15)) utl.add_cartopy_background(ax, name='RD') #forecast information l, b, w, h = ax.get_position().bounds bax = plt.axes([l, b + h - 0.1, .25, .1], facecolor='#FFFFFFCC') bax.set_yticks([]) bax.set_xticks([]) bax.axis([0, 10, 0, 10]) initTime = pd.to_datetime(str( gh.coords['forecast_reference_time'].values)).replace( tzinfo=None).to_pydatetime() fcst_time = initTime + timedelta( hours=gh.coords['forecast_period'].values[0]) #发布时间 if (sys.platform[0:3] == 'lin'): locale.setlocale(locale.LC_CTYPE, 'zh_CN.utf8') if (sys.platform[0:3] == 'win'): locale.setlocale(locale.LC_CTYPE, 'chinese') plt.text(2.5, 7.5, '起报时间: ' + initTime.strftime("%Y年%m月%d日%H时"), size=15) plt.text(2.5, 5, '预报时间: ' + fcst_time.strftime("%Y年%m月%d日%H时"), size=15) plt.text(2.5, 2.5, '预报时效: ' + str(int(gh.coords['forecast_period'].values[0])) + '小时', size=15) plt.text(2.5, 0.5, 'www.nmc.cn', size=15) # add color bar cax = plt.axes([l, b - 0.04, w, .02]) cb = plt.colorbar(plots['mslp'], cax=cax, orientation='horizontal', ticks=clevs_mslp[:-1], extend='max', extendrect=False) cb.ax.tick_params(labelsize='x-large') cb.set_label('Mean sea level pressure (hPa)', size=20) # add south China sea if south_China_sea: utl.add_south_China_sea(pos=[l + w - 0.091, b, .1, .2]) small_city = False if (map_extent2[1] - map_extent2[0] < 25): small_city = True if city: utl.add_city_on_map(ax, map_extent=map_extent2, transform=datacrs, zorder=6, size=15, small_city=small_city) utl.add_logo_extra_in_axes(pos=[l - 0.02, b + h - 0.1, .1, .1], which='nmc', size='Xlarge') # show figure if (output_dir != None): plt.savefig(output_dir + '最高温度_预报_' + '起报时间_' + initTime.strftime("%Y年%m月%d日%H时") + '预报时效_' + str(gh.coords['forecast_period'].values[0]) + '小时' + '.png', dpi=200, bbox_inches='tight') if (output_dir == None): plt.show()
def get_plot_attrs(name, clevs=None, min_lev=None, extend='max'): """ 获得预先设置的各种变量绘图属性. Args: name (str): the name of predefined plot attributes. Returns: dict: plot attribute dictionary. """ # convert to lower name = name.lower() if name == 'z_500_contour': if clevs is None: clevs = np.concatenate((np.arange(480, 580, 4), np.arange(580, 604, 4))) clevs = np.asarray(clevs) linewidths = np.full(len(clevs), 1) linewidths[clevs == 588] = 2 return {"levels": clevs, "linewidths": linewidths} elif name == 'qpf_1h_contourf_blues': if clevs is None: clevs = [0.1, 4, 13, 25, 60, 120, 250] clevs = np.asarray(clevs) cmap = cm.truncate_colormap('Blues', minval=0.1) norm = mpl.colors.BoundaryNorm(clevs, cmap.N, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} elif name == 'nmc_accumulated_rainfall': if clevs is None: clevs = [0.1, 10, 25, 50, 100, 250, 400, 600, 800, 1000] clevs = np.asarray(clevs) _colors = [[161, 241, 141], [61, 186, 61], [96, 184, 255], [0, 0, 255], [250, 0, 250], [128, 0, 64], [255, 170, 0], [255, 102, 0], [230, 0, 0], [80, 45, 10]] _colors = np.asarray(_colors) / 255.0 if min_lev is not None: idx = np.where(clevs >= min_lev) clevs = clevs[idx] _colors = _colors[idx, ] cmap, norm = mpl.colors.from_levels_and_colors(clevs, _colors, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} elif name == 'ecmf_accumulated_rainfall': if clevs is None: clevs = [0.5, 10, 30, 50, 70, 100, 130, 160] clevs = np.asarray(clevs) _colors = np.array([ '#a7aaaa', '#5cc8d7', '#3076bc', '#6aaa43', '#f5832a', '#ee2f2d', '#8350a0', '#231f20' ]) if min_lev is not None: idx = np.where(clevs >= min_lev) clevs = clevs[idx] _colors = _colors[idx] cmap, norm = mpl.colors.from_levels_and_colors(clevs, _colors, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} elif name == 'probability_forecast': if clevs is None: clevs = [1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100] clevs = np.asarray(clevs) cmap = cm.guide_cmaps(44) cmap = cm.truncate_colormap(cmap, maxval=0.95) norm = mpl.colors.BoundaryNorm(clevs, cmap.N, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} elif name == 'ndfd_t_summer': if clevs is None: clevs = np.arange(0, 35, 2) clevs = np.asarray(clevs) cmap = cm.ndfd_cmaps('T_summer') norm = mpl.colors.BoundaryNorm(clevs, cmap.N, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} elif name == '2m_temperature': if clevs is None: clevs = [ -45, -30, -20, -10, -5, 0, 0, 5, 5, 10, 20, 20, 30, 30, 40, 45 ] clevs = np.asarray(clevs) r = np.asarray([ 61, 250, 9, 94, 46, 6, 254, 32, 11, 0, 173, 254, 255, 255, 90, 253 ]) g = np.asarray([ 2, 0, 0, 157, 94, 249, 254, 178, 244, 97, 255, 254, 140, 99, 3, 253 ]) b = np.asarray([ 57, 252, 121, 248, 127, 251, 254, 170, 11, 3, 47, 0, 0, 61, 3, 253 ]) _colors = np.stack((r, g, b), axis=-1) _colors = np.asarray(_colors) / 255.0 if min_lev is not None: idx = np.where(clevs >= min_lev) clevs = clevs[idx] _colors = _colors[idx, ] cmap, norm = mpl.colors.from_levels_and_colors(clevs, _colors, extend=extend) return {'clevs': clevs, 'cmap': cmap, 'norm': norm} else: raise ValueError('{} is not supported.'.format(name))
def draw_theta_on_pv(ax, lon, lat, theta, mslp=None, gh500=None, map_extent=(73, 136, 18, 54), theta_clev=np.arange(300, 400, 4), alpha=0, mslp_clev=np.arange(960, 1060, 4), gh500_clev=np.arange(480, 600, 2), cax=None, left_title="850hPa wind", right_title=None, add_china=True, coastline_color='black'): """ Draw potential temperature on pv surface. :param ax: matplotlib axes. :param lon: longitude coordinates. :param lat: latitude coordinates. :param theta: potential temperature. :param mslp: mean sea level pressure. :param gh500: geopotential height 500hpa. :param map_extent: map extent. :param theta_clev: potential temperature. :param alpha: theta contour transparency. :param mslp_clev: mean sea level contour levels. :param gh500_clev: geopotential height 500 contour levels. :param cax: color bar axes. :param left_title: left title. :param right_title: right title. :param add_china: draw china province map or not. :param coastline_color: coast lines color. :return: potential temperature filled contour cf object. """ # set data projection, should be longitude and latitude. datacrs = ccrs.PlateCarree() # clear figure ax.clear # set map extent ax.set_extent(map_extent) # add map boundary ax.coastlines('50m', edgecolor=coastline_color) if add_china: add_china_map_2cartopy(ax, name='province', edgecolor='darkcyan', lw=4) # draw potential temperature x, y = np.meshgrid(lon, lat) cmap = guide_cmaps("27") cf = ax.contourf(x, y, theta, theta_clev, cmap=cmap, alpha=alpha, antialiased=True, transform=datacrs) if cax is not None: cb = plt.colorbar(cf, cax=cax, orientation='horizontal', extendrect=True, ticks=theta_clev) cb.set_label('Potential Temperature [K]', size='large', fontsize=16) cb.ax.tick_params(labelsize=16) # draw mean sea level pressure if mslp is not None: x, y = np.meshgrid(mslp[0], mslp[1]) cs1 = ax.contour(x, y, mslp[2], mslp_clev, colors='k', linewidth=1.0, linestyles='solid', transform=datacrs) plt.clabel(cs1, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True) # draw 500hPa geopotential height if gh500 is not None: x, y = np.meshgrid(gh500[0], gh500[1]) cs2 = ax.contour(x, y, gh500[2], gh500_clev, colors='w', linewidth=1.0, linestyles='dashed', transform=datacrs) plt.clabel(cs2, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True) # add grid lines gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlabels_top = False gl.ylabels_right = False gl.xlabel_style = {'size': 16} gl.ylabel_style = {'size': 16} # add title ax.set_title(left_title, loc='left', fontsize=18) if right_title is not None: ax.set_title(right_title, loc='right', fontsize=18) # return plot return cf
def draw_wind850(ax, lon, lat, u, v, mslp=None, gh500=None, thetae850=None, map_extent=(73, 136, 18, 54), wspeed_clev=np.arange(4, 40, 4), mslp_clev=np.arange(960, 1060, 4), wind_cmap=None, gh500_clev=np.arange(480, 600, 2), thetae850_clev=np.arange(280, 360, 4), draw_barbs=True, left_title="850hPa wind", right_title=None, add_china=True, coastline_color='black', title_font=None, cax=None, cb_title='850hPa wind speed (m/s)', cb_font=None): """ Draw 850hPa wind field. :param ax: matplotlib axes. :param lon: longitude coordinates. :param lat: latitude coordinates. :param u: u wind. :param v: v wind. :param mslp: mean sea level pressure, [lon, lat, mslp_data] :param gh500: 500hPa geopotential height, [lon, lat, gh500_data] :param thetae850: 850hPa equivalent potential temperature, [lon, lat, thetae850_data] :param map_extent: map extent :param wspeed_clev: wind speed filled contour levels. :param mslp_clev: mean sea level contour levels. :param wind_cmap: wind filled contour color map. :param gh500_clev: geopotential height 500 contour levels. :param thetae850_clev: 850hPa theta contour levels. :param draw_barbs: flag for drawing wind barbs. :param cax: color bar axes, if None, no color bar will be draw. :param left_title: left title. :param right_title: right title. :param add_china: draw china province boundary or not. :param coastline_color: coast line color. :param title_font: title font properties, like: title_font = mpl.font_manager.FontProperties( fname='C:/Windows/Fonts/SIMYOU.TTF') :param cb_title: color bar title :param cb_font: color bar title font properties :return: wind filled contour cf and barbs bb object. """ # set data projection, should be longitude and latitude. datacrs = ccrs.PlateCarree() # clear figure ax.clear # set map extent ax.set_extent(map_extent) # add map boundary ax.coastlines('50m', edgecolor=coastline_color) if add_china: add_china_map_2cartopy(ax, name='province', edgecolor='darkcyan') # draw 850hPa wind speed x, y = np.meshgrid(lon, lat) if wind_cmap is None: wind_cmap = guide_cmaps("2") cf = ax.contourf(x, y, np.sqrt(u * u + v * v), wspeed_clev, cmap=wind_cmap, transform=datacrs) if cax is not None: cb = plt.colorbar(cf, cax=cax, orientation='horizontal', extendrect=True, ticks=wspeed_clev) cb.set_label(cb_title, size='large', fontsize=16, fontproperties=cb_font) cb.ax.tick_params(labelsize=16) # draw wind barbs if draw_barbs: bb = ax.barbs(x, y, u, v, length=7, regrid_shape=15, transform=datacrs, sizes=dict(emptybarb=0.05)) # draw mean sea level pressure if mslp is not None: x, y = np.meshgrid(mslp[0], mslp[1]) cs1 = ax.contour(x, y, mslp[2], mslp_clev, colors='k', linewidth=1.0, linestyles='solid', transform=datacrs) plt.clabel(cs1, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True) # draw 500hPa geopotential height if gh500 is not None: x, y = np.meshgrid(gh500[0], gh500[1]) cs2 = ax.contour(x, y, gh500[2], gh500_clev, colors='w', linewidth=1.0, linestyles='dashed', transform=datacrs) plt.clabel(cs2, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True) # draw 850hPa equivalent potential temperature if thetae850 is not None: x, y = np.meshgrid(thetae850[0], thetae850[1]) cmap = plt.get_cmap("hsv") cs3 = ax.contour(x, y, thetae850[2], thetae850_clev, cmap=cmap, linewidth=0.8, linestyles='solid', transform=datacrs) plt.clabel(cs3, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True) # add grid lines gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlabels_top = False gl.ylabels_right = False gl.xlabel_style = {'size': 16} gl.ylabel_style = {'size': 16} # add title ax.set_title(left_title, loc='left', fontsize=18, fontproperties=title_font) if right_title is not None: ax.set_title(right_title, loc='right', fontsize=18, fontproperties=title_font) # return plot if draw_barbs: return cf, bb else: return cf
def draw_gh500_uv850_mslp(ax, gh500=None, uv850=None, mslp=None, map_extent=(50, 150, 0, 65), add_china=True, regrid_shape=20): """ Draw 500-hPa geopotential height contours, 850-hPa wind barbs and mean sea level pressure filled contours. :param ax: `matplotlib.axes.Axes`, the `Axes` instance used for plotting. :param gh500: 500-hPa gh, dictionary: necessary, {'lon': 1D array, 'lat': 1D array, 'data': 2D array} optional, {'clevs': 1D array} :param uv850: 850-hPa u-component and v-component wind, dictionary: necessary, {'lon': 1D array, 'lat': 1D array, 'udata': 2D array, 'vdata': 2D array} :param mslp: MSLP, dictionary: necessary, {'lon': 1D array, 'lat': 1D array, 'data': 2D array} optional, {'clevs': 1D array} :param map_extent: [lonmin, lonmax, latmin, latmax], longitude and latitude range. :param add_china: add china map or not. :param regrid_shape: control the wind barbs density. :return: plots dictionary. :Examples: See dk_tool_weather_map.synoptic.gh500_uv850_mslp """ # set data projection datacrs = ccrs.PlateCarree() # plot map background ax.set_extent(map_extent, crs=datacrs) ax.add_feature(cfeature.LAND, facecolor='0.6') ax.coastlines('50m', edgecolor='black', linewidth=0.75, zorder=100) if add_china: add_china_map_2cartopy(ax, name='province', edgecolor='darkcyan', lw=1, zorder=100) # define return plots plots = {} # draw mean sea level pressure if mslp is not None: x, y = np.meshgrid(mslp['lon'], mslp['lat']) clevs = mslp.get('clevs') if clevs is None: clevs = np.arange(960, 1065, 5) cmap = guide_cmaps(26) plots['mslp'] = ax.contourf(x, y, np.squeeze(mslp['data']), clevs, cmap=cmap, alpha=0.8, zorder=10, transform=datacrs) # draw 850-hPa wind bards if uv850 is not None: x, y = np.meshgrid(uv850['lon'], uv850['lat']) u = np.squeeze(uv850['udata']) * 2.5 v = np.squeeze(uv850['vdata']) * 2.5 plots['uv850'] = ax.barbs(x, y, u, v, length=6, regrid_shape=regrid_shape, transform=datacrs, fill_empty=False, sizes=dict(emptybarb=0.05), zorder=20) # draw 500-hPa geopotential height if gh500 is not None: x, y = np.meshgrid(gh500['lon'], gh500['lat']) clevs = gh500.get('clevs') if clevs is None: clevs = np.append(np.arange(480, 584, 8), np.arange(580, 604, 4)) plots['gh500'] = ax.contour(x, y, np.squeeze(gh500['data']), clevs, colors='purple', linewidths=2, transform=datacrs, zorder=30) plt.clabel(plots['gh500'], inline=1, fontsize=16, fmt='%.0f') # grid lines gl = ax.gridlines(crs=datacrs, linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xlocator = mpl.ticker.FixedLocator(np.arange(0, 360, 15)) gl.ylocator = mpl.ticker.FixedLocator(np.arange(-90, 90, 15)) # return plots return plots
def draw_uv850(ax, uv850=None, gh850=None, map_extent=(73, 136, 18, 54), add_china=True, regrid_shape=15): """ Draw 850-hPa wind field. :param ax: `matplotlib.axes.Axes`, the `Axes` instance used for plotting. :param uv850: 850-hPa u-component and v-component wind, dictionary: necessary, {'lon': 1D array, 'lat': 1D array, 'udata': 2D array, 'vdata': 2D array} optional, {'clevs': 1D array speed contour levels} :param gh850: optional, {'clevs': 1D array} :param map_extent: [lonmin, lonmax, latmin, latmax], longitude and latitude range. :param add_china: add china map or not. :param regrid_shape: control the wind barbs density. :return: plots dictionary. """ # set data projection datacrs = ccrs.PlateCarree() # plot map background ax.set_extent(map_extent, crs=datacrs) ax.add_feature(cfeature.LAND, facecolor='0.6') ax.coastlines('50m', edgecolor='black', linewidth=0.75, zorder=100) if add_china: add_china_map_2cartopy(ax, name='province', edgecolor='darkcyan', lw=1, zorder=100) # define return plots plots = {} # draw 850hPa wind speed and barbs if uv850 is not None: x, y = np.meshgrid(uv850['lon'], uv850['lat']) u = np.squeeze(uv850['udata']) v = np.squeeze(uv850['vdata']) clevs = uv850.get('clevs') if clevs is None: clevs = np.arange(4, 40, 4) cmaps = guide_cmaps("2") plots['uv850_cf'] = ax.contourf(x, y, np.sqrt(u * u + v * v), clevs, cmap=cmaps, transform=datacrs) plots['uv850_bb'] = ax.barbs(x, y, u * 2.5, v * 2.5, length=7, regrid_shape=regrid_shape, transform=datacrs, sizes=dict(emptybarb=0.05)) # draw 850hPa geopotential height if gh850 is not None: x, y = np.meshgrid(gh850['lon'], gh850['lat']) clevs = gh850.get('clevs') if clevs is None: clevs = np.arange(80, 180, 4) plots['gh850'] = ax.contour(x, y, np.squeeze(gh850['data']), clevs, colors='purple', linewidths=2, transform=datacrs, zorder=30) plt.clabel(plots['gh850'], inline=1, fontsize=16, fmt='%.0f') # add grid lines gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlabels_top = False gl.ylabels_right = False gl.xlabel_style = {'size': 16} gl.ylabel_style = {'size': 16} # return return plots