def draw_precipitation_nws(ax,
                           prep,
                           map_extent=(73, 136, 17, 54),
                           gridlines=True):
    """
    Draw NWS-style precipitation map.
    http://jjhelmus.github.io/blog/2013/09/17/plotting-nsw-precipitation-data/

    :param ax: `matplotlib.axes.Axes`, the `Axes` instance used for plotting.
    :param prep: precipitation, dictionary:
                 {'lon': 1D array, 'lat': 1D array, 'data': 2D array}
    :param map_extent: (lonmin, lonmax, latmin, latmax),
                       longitude and latitude range.
    :param gridlines: bool, draw grid lines or not.
    :return: plots dictionary.

    :Example:
    >>> plt.ioff()
    >>> fig = plt.figure(figsize=(8.6, 6.2))
    >>> fig.clf()
    >>> ax = plt.axes((0.1, 0.08, 0.85, 0.92), projection=ccrs.PlateCarree())
    >>> prep = {'lon': lon, 'lat': lat, 'data': rain}
    >>> plots = draw_precipitation_nws(ax, prep, map_extent=[73, 136, 17, 54])
    >>> ax.set_title('24h Accumulated Precipitation', fontsize=18, loc='left')
    >>> cax = fig.add_axes([0.16, 0.08, 0.7, 0.03])
    >>> cb = plt.colorbar(plots['prep'], cax=cax, orientation='horizontal',
    >>>                   ticks=plots['prep'].norm.boundaries)
    >>> cb.set_label('Precipitation (mm)', fontsize=10)
    >>> cb.ax.tick_params(labelsize=10)
    >>> plt.savefig('D:/plot.png')
    """

    # set data projection
    datacrs = ccrs.PlateCarree()

    # plot map background
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=1)
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=1)

    # plots container
    plots = {}

    # draw precipitation map
    x, y = np.meshgrid(prep['lon'], prep['lat'])
    cmap, norm = cm_precipitation_nws()
    plots['prep'] = ax.pcolormesh(x,
                                  y,
                                  np.squeeze(prep['data']),
                                  norm=norm,
                                  cmap=cmap,
                                  transform=datacrs)

    # add grid lines
    if gridlines:
        add_gridlines(ax)

    # return
    return plots
def draw_qpf_nmc(ax, prep, stations=None, map_extent=(107., 123, 28, 43.)):
    """
    Draw filled-contour QPF.

    :param ax: ax: `matplotlib.axes.Axes`, the `Axes` instance.
    :param prep: precipitation, dictionary:
                 necessary, {'lon': 1D array, 'lat': 1D array,
                             'data': 2D array}
                 optional, {'clevs': 1D array}
    :param stations: station locations, dictionary:
                 necessary, {'lon': 1D array, 'lat': 1D array}
    :param map_extent: [lonmin, lonmax, latmin, latmax],
                       longitude and latitude range.
    :return: plots dictionary.
    """

    # set data projection
    datacrs = ccrs.PlateCarree()

    # plot map background
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=1)
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=1)

    # plots container
    plots = {}

    # draw precipitation map
    x, y = np.meshgrid(prep['lon'], prep['lat'])
    if prep.get('clevs') is None:
        clevs = [0.1, 10, 25, 50, 100, 250, 600]
    cmap = plt.get_cmap("YlGnBu")
    norm = mpl.colors.BoundaryNorm(clevs, cmap.N)
    plots['prep'] = ax.contourf(x,
                                y,
                                np.squeeze(prep['data']),
                                clevs,
                                norm=norm,
                                cmap=cmap,
                                transform=datacrs)

    # add station points
    if stations is not None:
        plots['stations'] = ax.scatter(stations['lon'],
                                       stations['lat'],
                                       transform=ccrs.PlateCarree())

    # add grid lines
    add_gridlines(ax)

    # return
    return plots
def show_obfo_rain_24(grid_fo,sta_ob,filename = None):
    fig = plt.figure(figsize=(6,3.6))
    # 平面对比图
    rect1 = [0.01,0.01,0.98,0.98] # 左下宽高
    datacrs = ccrs.PlateCarree()
    ax = plt.axes(rect1,projection=datacrs)
    # 设置地图背景
    map_extent = [grid_fo.slon,grid_fo.elon,grid_fo.slat,grid_fo.elat]
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=0.3) #省界
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=0.3) #河流

    #绘制格点预报场
    x = np.arange(grid_fo.nlon) * grid_fo.dlon + grid_fo.slon
    y = np.arange(grid_fo.nlat) * grid_fo.dlat + grid_fo.slat
    clevs = [0.1, 10, 25, 50, 100, 250, 1000]
    colors_grid = ["#E0EEFA", "#B4D3E9", "#6FB0D7", "#3787C0", "#105BA4", "#07306B","#07306B"]
    plot_grid = ax.contourf(x, y, grid_fo.dat, clevs, colors = colors_grid, transform=datacrs) #填色图

    colorbar_position_grid = fig.add_axes([0.035, 0.94, 0.25, 0.015])  # 位置[左,下,宽,高]
    plt.colorbar(plot_grid,cax = colorbar_position_grid,orientation='horizontal')
    plt.text(0.035, 0.955, "model accumulated precipition(mm)", fontsize=10)
    # 绘制填色站点值
    sta_ob_in = bt.ssf.get_sta_in_grid(sta_ob, grid=grid_fo.grid)
    colors_sta = ['#FFFFFF','#0055FF','#00FFB4','#F4FF00','#FE1B00','#910000','#B800BA']
    dat = sta_ob_in.values[:, 2]
    dat[dat>1000] = 0
    clevs = [0,0.1, 10, 25, 50, 100, 250, 1000]
    cleves_name = ["0","0.1-10","10-25","25-50","50-100","100-250",">=250"]
    for i in range(len(clevs)-1):
        index0 = np.where((dat>=clevs[i])&(dat<clevs[i+1]))
        if (len(index0[0]) > 0):
            x = np.squeeze(sta_ob_in.values[index0, 0])
            y = np.squeeze(sta_ob_in.values[index0, 1])
            if (len(index0) == 1):
                x = np.array([x])
                y = np.array([y])
                if(i >0):
                    ax.scatter(x, y, c=colors_sta[i], transform=ccrs.PlateCarree(), s=3,label=cleves_name[i],linewidths=0.3,edgecolor='k')
                else:
                    ax.scatter(x, y, c=colors_sta[i], transform=ccrs.PlateCarree(), s=1, label=cleves_name[i])
    ax.legend(facecolor ='whitesmoke',title = "observation",loc = "lower left",edgecolor = 'whitesmoke')

    #图片显示或保存
    if(filename is None):
        plt.show()
    else:
        plt.savefig(filename,dpi = 300)
    plt.close()
    return
示例#4
0
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
示例#5
0
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
示例#6
0
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
示例#7
0
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
示例#8
0
def rain_24h_comprehensive_sg(sta_ob, grd_fo, filename=None):
    '''
    #绘制24小时降水实况与预报综合对比检验图,画幅中央为预报实况的对比,左右两侧为各类检验指标
    :param grd_fo: 输入的网格数据,包含一个平面的网格场
    :param sta_ob:  输入的站点数据,包含一个时刻的站点数据列表
    :param filename: 图片输出路径,缺省时会以调试窗口形式弹出
    :return:无返回值
    '''

    grid_fo = nmc_verification.nmc_vf_base.get_grid_of_data(grd_fo)
    #通过经纬度范围设置画幅
    hight = 5.6
    title_hight = 0.3
    legend_hight = 0.6
    left_plots_width = 3
    right_plots_width = 2.3
    width = (
        hight - title_hight - legend_hight
    ) * grid_fo.nlon / grid_fo.nlat + left_plots_width + right_plots_width
    map_width = width - left_plots_width - right_plots_width

    fig = plt.figure(figsize=(width, hight))
    # 设置画幅的布局方式,
    rect1 = [
        left_plots_width / width, 0.12,
        (width - right_plots_width - left_plots_width) / width, 0.84
    ]  # 左下宽高,中央对比图
    ylabelwidth = 0.52 / width
    rect2 = [
        ylabelwidth, 0.08, left_plots_width / width - ylabelwidth - 0.005, 0.40
    ]  # 左下宽高,散点回归图
    ylabelwidth = 0.65 / width
    rect3 = [
        ylabelwidth, 0.60, left_plots_width / width - ylabelwidth - 0.005, 0.18
    ]  # 左下宽高,频谱统计柱状图
    rect4 = [0.01, 0.79, left_plots_width / width - 0.045, 0.15]  # 左下宽高,左侧文字
    rect5 = [(width - right_plots_width) / width + 0.005, -0.035,
             right_plots_width / width - 0.01, 0.90]  # 左下宽高,右侧文字
    width_ob_fo_str = 0.3
    if (map_width < 3.5):
        width_bar = 2.1  #根据中间地图的宽度,来确定预报colorbar的尺寸
        sta_legend_size = 5  #根据中间地图的宽度,来确定观测legend的size
    else:
        sta_legend_size = 7
        width_bar = 2.9

    rect6 = [(left_plots_width + 0.5 * map_width - 0.5 * width_bar +
              0.5 * width_ob_fo_str) / width, 0.04, width_bar / width,
             0.02]  #预报colorbar
    rect7 = [(left_plots_width + 0.5 * map_width - 0.5 * width_bar -
              0.5 * width_ob_fo_str) / width, 0.04, width_ob_fo_str / width,
             0.3]  #观测文字
    #rect8 = [left_plots_width / width, 0.04, width_ob_fo_str / width, 0.3]  # 预报文字

    datacrs = ccrs.PlateCarree()
    ax = plt.axes(rect1, projection=datacrs)
    # 设置地图背景
    map_extent = [grid_fo.slon, grid_fo.elon, grid_fo.slat, grid_fo.elat]
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=0.3)  # 河流

    # 绘制格点预报场
    x = np.arange(grid_fo.nlon) * grid_fo.dlon + grid_fo.slon
    y = np.arange(grid_fo.nlat) * grid_fo.dlat + grid_fo.slat
    clevs = [0.1, 10, 25, 50, 100, 250, 1000]
    colors_grid = [
        "#D0DEEA", "#B4D3E9", "#6FB0D7", "#3787C0", "#105BA4", "#07306B",
        "#07306B"
    ]
    dat = grd_fo.values.squeeze()
    #print(x)
    #print(y)
    #print(dat)
    plot_grid = ax.contourf(x,
                            y,
                            dat,
                            clevs,
                            colors=colors_grid,
                            transform=datacrs)  # 填色图
    time_str = nmc_verification.nmc_vf_base.tool.time_tools.time_to_str(
        grid_fo.gtime[0])
    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[
        6:8] + "日" + time_str[8:10] + "时"
    if type(grid_fo.members[0]) == str:
        model_name = grid_fo.members[0]
    else:
        model_name = str(grid_fo.members[0])

    if map_width < 3:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=7)
    elif map_width < 4:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=10)
    else:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=11)

    colorbar_position_grid = fig.add_axes(rect6)  # 位置[左,下,宽,高]
    cb = plt.colorbar(plot_grid,
                      cax=colorbar_position_grid,
                      orientation='horizontal')
    cb.ax.tick_params(labelsize=8)  # 设置色标刻度字体大小。
    #plt.text(0, 0, "预报(mm)", fontsize=8)

    # 绘制填色站点值
    sta_ob_in = nmc_verification.nmc_vf_base.function.get_from_sta_data.sta_in_grid_xy(
        sta_ob, grid=grid_fo)
    colors_sta = [
        '#FFFFFF', '#0055FF', '#00FFB4', '#F4FF00', '#FE1B00', '#910000',
        '#B800BA'
    ]
    dat = sta_ob_in.values[:, -1]
    dat[dat > 1000] = 0
    clevs = [0, 0.1, 10, 25, 50, 100, 250, 1000]
    cleves_name = [
        "0", "0.1-10", "10-25", "25-50", "50-100", "100-250", ">=250"
    ]
    for i in range(len(clevs) - 1):
        index0 = np.where((dat >= clevs[i]) & (dat < clevs[i + 1]))
        if (len(index0[0]) > 0):
            x = np.squeeze(sta_ob_in["lon"].values[index0])
            y = np.squeeze(sta_ob_in["lat"].values[index0])
            if (len(index0) == 1):
                x = np.array([x])
                y = np.array([y])
                if (i > 0):
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=3,
                               label=cleves_name[i],
                               linewidths=0.3,
                               edgecolor='k')
                else:
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=1,
                               label=cleves_name[i],
                               linewidths=0.1,
                               edgecolor="k")
    ax.legend(facecolor='whitesmoke',
              loc="lower center",
              ncol=4,
              edgecolor='whitesmoke',
              prop={'size': sta_legend_size},
              bbox_to_anchor=(0.5 + 0.5 * width_ob_fo_str / map_width, -0.08))
    ax7 = plt.axes(rect7)
    ax7.axes.set_axis_off()
    plt.text(0, 0.00, "观测\n\n预报", fontsize=7)

    #ax.legend(loc="lower right", ncol=4, facecolor='whitesmoke', title="观测", edgecolor='whitesmoke', fontsize=9,
    #          bbox_to_anchor=(0, -0.32))
    # 散点回归图
    ax2 = plt.axes(rect2)
    sta_fo = nmc_verification.nmc_vf_base.function.gxy_sxy.interpolation_linear(
        grd_fo, sta_ob_in)
    #print(sta_fo)
    data_name = nmc_verification.nmc_vf_base.get_data_names(sta_ob_in)
    ob = sta_ob_in[data_name[0]].values
    data_name = nmc_verification.nmc_vf_base.get_data_names(sta_fo)
    fo = sta_fo[data_name[0]].values
    ax2.plot(ob, fo, '.', color='k')

    # 绘制比例线
    rate = np.sum(fo) / (np.sum(ob) + 1e-30)
    ob_line = np.arange(0, np.max(ob), np.max(ob) / 30)
    fo_rate = ob_line * rate
    ax2.plot(ob_line[0:20], fo_rate[0:20], 'r')

    # 绘制回归线
    X = np.zeros((len(ob), 1))
    X[:, 0] = ob[:]
    clf = LinearRegression().fit(X, fo)
    X = np.zeros((len(ob_line), 1))
    X[:, 0] = ob_line[:]
    fo_rg = clf.predict(X)
    ax2.plot(ob_line, fo_rg, color='b', linestyle='dashed')
    cor = np.corrcoef(ob, fo)
    rg_text1 = "R = " + '%.2f' % (cor[0, 1])
    rg_text2 = "y = " + '%.2f' % (clf.coef_[0]) + "* x + " + '%.2f' % (
        clf.intercept_)

    maxy = max(np.max(ob), np.max(fo)) + 5
    plt.xlim(0, maxy)
    plt.ylim(0, maxy)
    plt.text(0.05 * maxy, 0.9 * maxy, rg_text1, fontsize=10)
    plt.text(0.05 * maxy, 0.8 * maxy, rg_text2, fontsize=10)
    maxy = max(np.max(ob), np.max(fo))
    ax2.set_xlabel("观测", fontsize=9)
    ax2.set_ylabel("预报", fontsize=9)
    ax2.set_title("Obs.vs Pred. Scatter plot", fontsize=12)
    # 设置次刻度间隔
    xmi = 2
    if (np.max(ob) > 100): xmi = 5
    ymi = 2
    if (np.max(fo) > 100): ymi = 5
    xmajorLocator = mpl.ticker.MultipleLocator(10 * xmi)  # 将x主刻度标签设置为次刻度10倍
    ymajorLocator = mpl.ticker.MultipleLocator(10 * ymi)  # 将y主刻度标签设置为次刻度10倍
    ax2.xaxis.set_major_locator(xmajorLocator)
    ax2.yaxis.set_major_locator(ymajorLocator)
    xminorLocator = mpl.ticker.MultipleLocator(xmi)  # 将x轴次刻度标签设置xmi
    yminorLocator = mpl.ticker.MultipleLocator(ymi)  # 将y轴次刻度标签设置ymi
    ax2.xaxis.set_minor_locator(xminorLocator)
    ax2.yaxis.set_minor_locator(yminorLocator)

    # 绘制频率柱状图
    p_ob = np.zeros(6)
    p_fo = np.zeros(6)
    x = np.arange(6) + 1
    for i in range(1, len(clevs) - 1, 1):
        index0 = np.where((ob >= clevs[i]) & (ob < clevs[i + 1]))
        p_ob[i - 1] = len(index0[0])
        index0 = np.where((fo >= clevs[i]) & (fo < clevs[i + 1]))
        p_fo[i - 1] = len(index0[0])

    ax3 = plt.axes(rect3)
    ax3.bar(x - 0.25, p_ob, width=0.2, facecolor="r", label="Obs")
    ax3.bar(x + 0.05, p_fo, width=0.2, facecolor="b", label="Pred")
    ax3.legend(loc="upper right")
    ax3.set_xlabel("precipitation threshold", fontsize=10)
    ax3.set_xticks(x)
    ax3.set_xticklabels(
        ["0.1-10", "10-25", "25-50", "50-100", "100-250", ">=250"], fontsize=9)
    ax3.set_ylabel("point number", fontsize=10)
    ax3.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(100))

    # 绘制降水站点实况预报统计表

    ax4 = plt.axes(rect4)
    ax4.axes.set_axis_off()

    ob_has = ob[ob >= 0.01]
    fo_has = fo[fo >= 0.01]
    text = "降水站点实况和预报 n=" + str(len(ob)) + "\n"
    text += "=============================================\n"
    text += "                         观测           预报\n"
    text += "---------------------------------------------\n"
    text += "有降水站点数(>=0.01)     " + "%4d" % len(
        ob_has) + "           %4d" % len(fo_has) + "\n"
    text += "有降水站点数百分比%    " + "%6.1f" % (len(ob_has) / len(ob)) + "%15.1f" % (
        len(fo_has) / len(fo)) + "\n"
    text += "平均降水量(排除无降水) " + "%6.1f" % (np.mean(ob_has)) + "%15.1f" % (
        np.mean(fo_has)) + "\n"
    text += "最大降水量             " + "%6.1f" % (np.max(ob_has)) + "%15.1f" % (
        np.max(fo_has)) + "\n"
    text += "---------------------------------------------"
    plt.text(0, 0, text, fontsize=9)

    # 绘制统计检验结果

    ax5 = plt.axes(rect5)
    ax5.axes.set_axis_off()

    mae = nmc_verification.nmc_vf_method.continuous.score.mae(ob, fo)
    me = nmc_verification.nmc_vf_method.continuous.score.me(ob, fo)
    mse = nmc_verification.nmc_vf_method.continuous.score.mse(ob, fo)
    rmse = nmc_verification.nmc_vf_method.continuous.score.rmse(ob, fo)
    bias_c = nmc_verification.nmc_vf_method.continuous.score.bias(ob, fo)
    cor = nmc_verification.nmc_vf_method.continuous.score.corr(ob, fo)
    hit, mis, fal, co = nmc_verification.nmc_vf_method.yes_or_no.score.hmfn(
        ob, fo, clevs[1:])
    ts = nmc_verification.nmc_vf_method.yes_or_no.score.ts(ob, fo, clevs[1:])
    ets = nmc_verification.nmc_vf_method.yes_or_no.score.ets(ob, fo, clevs[1:])
    bias = nmc_verification.nmc_vf_method.yes_or_no.score.bias(
        ob, fo, clevs[1:])
    hit_rate = nmc_verification.nmc_vf_method.yes_or_no.score.hit_rate(
        ob, fo, clevs[1:])
    mis_rate = nmc_verification.nmc_vf_method.yes_or_no.score.mis_rate(
        ob, fo, clevs[1:])
    fal_rate = nmc_verification.nmc_vf_method.yes_or_no.score.fal_rate(
        ob, fo, clevs[1:])
    text = str(len(ob)) + "评分站点预报检验统计量\n"
    text += "Mean absolute error:" + "%6.2f" % mae + "\n"
    text += "Mean error:" + "%6.2f" % me + "\n"
    text += "Mean-squared error:" + "%6.2f" % mse + "\n"
    text += "Root mean-squared error:" + "%6.2f" % rmse + "\n"
    text += "Bias:" + "%6.2f" % bias_c + "\n"
    text += "Correctlation coefficiant:" + "%6.2f" % cor + "\n\n\n"
    leves_name = [
        "0.1-10-", "10-25--", "25-50--", "50-100-", "100-250", ">=250-"
    ]
    for i in range(len(leves_name)):
        text += ":" + leves_name[i] + "---------------------------\n"
        text += "正确:" + "%-4d" % hit[i] + " 空报:" + "%-4d" % fal[
            i] + " 漏报:" + "%-4d" % mis[i] + "\n"
        text += "TS:" + "%5.3f" % ts[
            i] + "                  ETS:" + "%5.3f" % ets[i] + "\n"
        text += "Hit rate:" + "%5.3f" % hit_rate[
            i] + "     Miss rate: " + "%5.3f" % mis_rate[i] + "\n"
        text += "False alarm ratio:" + "%5.3f" % fal_rate[
            i] + "  Bias:" + "%5.3f" % bias[i] + "\n\n"
    plt.text(0, 0.00, text, fontsize=9)

    # 图片显示或保存
    if (filename is None):
        plt.show()
        print()
    else:
        plt.savefig(filename, dpi=300)
    plt.close()
    return
def draw_total_precipitation(prep, map_extent=(107., 112, 23.2, 26.5),
                             back_image='terrain-background', back_image_zoom=8, title="降水量实况图",
                             draw_station=True, station_info='cities', station_size=22, 
                             just_contourf=False):
    """
    该程序用于显示多日的累积降水量分布特征, 2020/6/7按业务要求制作.

    Args:
        ax (matplotlib.axes.Axes): the `Axes` instance used for plotting.
        prep (dictionary): precipitation, dictionary: {'lon': 1D array, 'lat': 1D array, 'data': 2D array}
        map_extent (tuple, optional): (lonmin, lonmax, latmin, latmax),. Defaults to (107., 112, 23.2, 26.5).
        back_image (str, opional): the background image name. Default is stamen 'terrain-background', else is
                                      arcgis map server 'World_Physical_Map' (max zoom level is 8)
        back_image_zoom (int, optional): the zoom level for background image. Defaults to 8.
        draw_station (bool, optional): draw station name. Defaults to True.
        station_info (str, optional): station information, 'cities' is 260 city names, or province captial shows.
        station_size (int, optional): station font size. Defaults to 22.
        title (str, optional): title string. Defaults to "降水量实况图".
    
    Example:
        import pandas as pd
        from nmc_met_graphics.plot.precipitation import draw_total_precipitation
        from nmc_met_io.retrieve_micaps_server import get_model_grids

        # read data
        times = pd.date_range(start = pd.to_datetime('2020-06-02 08:00'), end =  pd.to_datetime('2020-06-07 08:00'), freq='1H')
        dataset = get_model_grids("CLDAS/RAIN01_TRI_DATA_SOURCE", times.strftime("%y%m%d%H.000"))
        data = dataset.sum(dim="time")
        data['data'].values[data['data'].values > 2400.0] = np.nan
        prep = {'lon': data['lon'].values, 'lat': data['lat'].values, 'data': data['data'].values}

        # draw the figure
        draw_total_precipitation(prep);
    """

    # set figure size
    fig = plt.figure(figsize=(16, 14.5))

    # set map projection
    datacrs = ccrs.PlateCarree()
    mapcrs = ccrs.LambertConformal(
        central_longitude=np.mean(map_extent[0:1]), central_latitude=np.mean(map_extent[2:3]),
        standard_parallels=(30, 60))
    ax = plt.axes((0.1, 0.08, 0.85, 0.92), projection=mapcrs)
    ax.set_extent(map_extent, crs=datacrs)

    # add map background
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=1)
    add_china_map_2cartopy(ax, name='river', edgecolor='cyan', lw=1)
    if back_image == 'terrain-background':
        stamen_terrain = cimg.Stamen('terrain-background')
        ax.add_image(stamen_terrain, back_image_zoom)
    else:
        image = cimg.GoogleTiles(url="https://server.arcgisonline.com/arcgis/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}.jpg")
        ax.add_image(image, back_image_zoom)

    # set colors and levels
    clevs = [50, 100, 200, 300, 400, 500, 600]
    colors = ['#6ab4f1', '#0001f6', '#f405ee', '#ffa900', '#fc6408', '#e80000', '#9a0001']
    linewidths = [1, 1, 2, 2, 3, 4, 4]
    cmap, norm = mpl.colors.from_levels_and_colors(clevs, colors, extend='max')

    # draw precipitation contour map
    x, y = np.meshgrid(prep['lon'], prep['lat'])
    if just_contourf:
        _ = ax.contourf(
            x, y, np.squeeze(prep['data']), clevs, norm=norm,
            cmap=cmap, transform=datacrs, extend='max', alpha=0.5)
    else:
        _ = ax.contourf(
            x, y, np.squeeze(prep['data']), clevs, norm=norm,
            cmap=cmap, transform=datacrs, extend='max', alpha=0.1)
        con2 = ax.contour(
            x, y, np.squeeze(prep['data']), clevs, norm=norm,
            cmap=cmap, transform=datacrs, linewidths=linewidths)
        # add path effects
        plt.setp(con2.collections, path_effects=[
            path_effects.SimpleLineShadow(), path_effects.Normal()])

    # add title and legend
    font = FontProperties(family='Microsoft YaHei', size=32)
    ax.set_title('降水量实况图(累计降水: 6月02日—6月06日)', loc='center', fontproperties=font)
    font = FontProperties(family='Microsoft YaHei', size=16)
    plt.legend([mpatches.Patch(color=b) for b in colors],[
        '50~100 毫米', '100~200 毫米', '200-300 毫米', '300~400 毫米', '400~500 毫米', '500~600 毫米', '>=600毫米'],
        prop=font)

    # add city information
    if draw_station:
        if station_info == 'cities':
            cities = pd.read_csv(pkg_resources.resource_filename(
                'nmc_met_graphics', "resources/stations/cma_city_station_info.dat"),  delimiter=r"\s+")
        else:
            cities = pd.read_csv(pkg_resources.resource_filename(
                'nmc_met_graphics', "resources/stations/provincial_capital.csv"))
        font = FontProperties(family='SimHei', size=22, weight='bold')
        geodetic_transform = ccrs.Geodetic()._as_mpl_transform(ax)
        for _, row in cities.iterrows():
            text_transform = offset_copy(geodetic_transform, units='dots', x=-5)
            ax.plot(row['lon'], row['lat'], marker='o', color='white', markersize=8,
                    alpha=0.7, transform=datacrs)
            ax.text(row['lon'], row['lat'], row['city_name'], clip_on=True,
                    verticalalignment='center', horizontalalignment='right',
                    transform=text_transform, fontproperties=font, color='white',
                    path_effects=[
                        path_effects.Stroke(linewidth=1, foreground='black'),path_effects.Normal()])
    
    return fig
示例#10
0
def draw_composite_map(date_obj, t850, u200, v200, u500, v500, mslp, gh500,
                       u850, v850, pwat):
    """
    Draw synoptic composite map.

    Args:
        map_subset (int, optional): [description]. Defaults to 1.
        map_region (list, optional): [description]. Defaults to [70, 140, 20, 60].
    """

    #Get lat and lon arrays for this dataset:
    lat = t850.lat.values
    lon = t850.lon.values

    #========================================================================================================
    # Create a Basemap plotting figure and add geography
    #========================================================================================================

    #Create a Plate Carree projection object
    proj_ccrs = ccrs.Miller(central_longitude=0.0)

    #Create figure and axes for main plot and colorbars
    fig = plt.figure(figsize=(18, 12), dpi=125)
    gs = gridspec.GridSpec(12, 36, figure=fig)  #[ytop:ybot, xleft:xright]
    ax = plt.subplot(gs[:, :-1], projection=proj_ccrs)  #main plot
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    ax2 = plt.subplot(gs[:4, -1])  #top plot
    ax2.set_xticklabels([])
    ax2.set_yticklabels([])
    ax3 = plt.subplot(gs[4:8, -1])  #bottom plot
    ax3.set_xticklabels([])
    ax3.set_yticklabels([])
    ax4 = plt.subplot(gs[8:, -1])  #bottom plot
    ax4.set_xticklabels([])
    ax4.set_yticklabels([])

    #Add political boundaries and coastlines
    ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidths=1.2)
    ax.add_feature(cfeature.BORDERS.with_scale('50m'), linewidths=1.2)
    ax.add_feature(cfeature.STATES.with_scale('50m'), linewidths=0.5)

    #Add land/lake/ocean masking
    land_mask = cfeature.NaturalEarthFeature('physical',
                                             'land',
                                             '50m',
                                             edgecolor='face',
                                             facecolor='#e6e6e6')
    sea_mask = cfeature.NaturalEarthFeature('physical',
                                            'ocean',
                                            '50m',
                                            edgecolor='face',
                                            facecolor='#ffffff')
    lake_mask = cfeature.NaturalEarthFeature('physical',
                                             'lakes',
                                             '50m',
                                             edgecolor='face',
                                             facecolor='#ffffff')
    ax.add_feature(sea_mask, zorder=0)
    ax.add_feature(land_mask, zorder=0)
    ax.add_feature(lake_mask, zorder=0)

    #========================================================================================================
    # Fill contours
    #========================================================================================================

    #--------------------------------------------------------------------------------------------------------
    # 850-hPa temperature
    #--------------------------------------------------------------------------------------------------------

    #Specify contour settings
    clevs = np.arange(-40, 40, 1)
    cmap = plt.cm.jet
    extend = "both"

    #Contour fill this variable
    norm = col.BoundaryNorm(clevs, cmap.N)
    cs = ax.contourf(lon,
                     lat,
                     t850,
                     clevs,
                     cmap=cmap,
                     norm=norm,
                     extend=extend,
                     transform=proj_ccrs,
                     alpha=0.1)

    #--------------------------------------------------------------------------------------------------------
    # PWAT
    #--------------------------------------------------------------------------------------------------------

    #Specify contour settings
    clevs = np.arange(20, 71, 0.5)

    #Define a color gradient for PWAT
    pwat_colors = gradient([[(255, 255, 255), 0.0], [(255, 255, 255), 20.0]],
                           [[(205, 255, 205), 20.0], [(0, 255, 0), 34.0]],
                           [[(0, 255, 0), 34.0], [(0, 115, 0), 67.0]])
    cmap = pwat_colors.get_cmap(clevs)
    extend = "max"

    #Contour fill this variable
    norm = col.BoundaryNorm(clevs, cmap.N)
    cs = ax.contourf(lon,
                     lat,
                     pwat,
                     clevs,
                     cmap=cmap,
                     norm=norm,
                     extend=extend,
                     transform=proj_ccrs,
                     alpha=0.9)

    #Add a color bar
    cbar = plt.colorbar(cs,
                        cax=ax2,
                        shrink=0.75,
                        pad=0.01,
                        ticks=[20, 30, 40, 50, 60, 70])

    #--------------------------------------------------------------------------------------------------------
    # 250-hPa wind
    #--------------------------------------------------------------------------------------------------------

    #Get the data for this variable
    wind = calc.wind_speed(u200, v200)

    #Specify contour settings
    clevs = [40, 50, 60, 70, 80, 90, 100, 110]
    cmap = col.ListedColormap([
        '#99E3FB', '#47B6FB', '#0F77F7', '#AC97F5', '#A267F4', '#9126F5',
        '#E118F3', '#E118F3'
    ])
    extend = "max"

    #Contour fill this variable
    norm = col.BoundaryNorm(clevs, cmap.N)
    cs = ax.contourf(lon,
                     lat,
                     wind,
                     clevs,
                     cmap=cmap,
                     norm=norm,
                     extend=extend,
                     transform=proj_ccrs)

    #Add a color bar
    cbar = plt.colorbar(cs, cax=ax3, shrink=0.75, pad=0.01, ticks=clevs)

    #--------------------------------------------------------------------------------------------------------
    # 500-hPa smoothed vorticity
    #--------------------------------------------------------------------------------------------------------

    #Get the data for this variable
    dx, dy = calc.lat_lon_grid_deltas(lon, lat)
    vort = calc.vorticity(u500, v500, dx, dy)
    smooth_vort = smooth(vort, 5.0) * 10**5

    #Specify contour settings
    clevs = np.arange(2, 20, 1)
    cmap = plt.cm.autumn_r
    extend = "max"

    #Contour fill this variable
    norm = col.BoundaryNorm(clevs, cmap.N)
    cs = ax.contourf(lon,
                     lat,
                     smooth_vort,
                     clevs,
                     cmap=cmap,
                     norm=norm,
                     extend=extend,
                     transform=proj_ccrs,
                     alpha=0.3)

    #Add a color bar
    cbar = plt.colorbar(cs, cax=ax4, shrink=0.75, pad=0.01, ticks=clevs[::2])

    #========================================================================================================
    # Contours
    #========================================================================================================

    #--------------------------------------------------------------------------------------------------------
    # MSLP
    #--------------------------------------------------------------------------------------------------------

    #Specify contour settings
    clevs = np.arange(960, 1040 + 4, 4)
    style = 'solid'  #Plot solid lines
    color = 'red'  #Plot lines as gray
    width = 0.8  #Width of contours 0.25

    #Contour this variable
    cs = ax.contour(lon,
                    lat,
                    mslp,
                    clevs,
                    colors=color,
                    linewidths=width,
                    linestyles=style,
                    transform=proj_ccrs,
                    alpha=0.9)

    #Include value labels
    ax.clabel(cs, inline=1, fontsize=9, fmt='%d')

    #--------------------------------------------------------------------------------------------------------
    # Geopotential heights
    #--------------------------------------------------------------------------------------------------------

    #Get the data for this variable
    gh500 = gh500 / 10.0

    #Specify contour settings
    clevs = np.arange(480, 612, 4)
    style = 'solid'  #Plot solid lines
    color = 'black'  #Plot lines as gray
    width = 2.0  #Width of contours

    #Contour this variable
    cs = ax.contour(lon,
                    lat,
                    gh500,
                    clevs,
                    colors=color,
                    linewidths=width,
                    linestyles=style,
                    transform=proj_ccrs)

    #Include value labels
    ax.clabel(cs, inline=1, fontsize=12, fmt='%d')

    #--------------------------------------------------------------------------------------------------------
    # Surface barbs
    #--------------------------------------------------------------------------------------------------------

    #Plot wind barbs
    quivers = ax.quiver(lon,
                        lat,
                        u850.values,
                        v850.values,
                        transform=proj_ccrs,
                        regrid_shape=(38, 30),
                        scale=820,
                        alpha=0.5)

    #--------------------------------------------------------------------------------------------------------
    # Label highs & lows
    #--------------------------------------------------------------------------------------------------------

    #Label highs and lows
    add_mslp_label(ax, proj_ccrs, mslp, lat, lon)

    #========================================================================================================
    # Step 6. Add map boundary, legend, plot title, then save image and close
    #========================================================================================================

    #Add china province boundary
    add_china_map_2cartopy(ax, name='province')

    #Add custom legend
    from matplotlib.lines import Line2D
    custom_lines = [
        Line2D([0], [0], color='#00A123', lw=5),
        Line2D([0], [0], color='#0F77F7', lw=5),
        Line2D([0], [0], color='#FFC000', lw=5),
        Line2D([0], [0], color='k', lw=2),
        Line2D([0], [0], color='k', lw=0.1, marker=r'$\rightarrow$', ms=20),
        Line2D([0], [0], color='r', lw=0.8),
    ]

    ax.legend(custom_lines, [
        'PWAT (mm)', '200-hPa Wind (m/s)', '500-hPa Vorticity',
        '500-hPa Height (dam)', '850-hPa Wind (m/s)', 'MSLP (hPa)'
    ],
              loc=2,
              prop={'size': 12})

    #Format plot title
    title = "Synoptic Composite \nValid: " + dt.datetime.strftime(
        date_obj, '%Y-%m-%d %H%M UTC')
    st = plt.suptitle(title, fontweight='bold', fontsize=16)
    st.set_y(0.92)

    #Return figuration
    return (fig)
示例#11
0
def fig_cldas_temp(indata,
                   figsize=12,
                   map_extent=(100, 125, 25, 45),
                   gridlines=False,
                   outfile=None,
                   title="CLDAS Temperature",
                   time=None):
    """Produce CLDAS temperature map figure.
    
    Arguments:
        indata {dictionary or xarray dataset} -- 
            {'lon': 1D array, 'lat': 1D array, 'data': 2D array}
    
    Keyword Arguments:
        figsize {tuple or int} -- figure size (default: {12})
        map_extent {tuple} -- (lonmin, lonmax, latmin, latmax) (default: {(100, 125, 25, 45)})
        gridlines {bool} -- bool, draw grid lines or not. (default: {False})
        outfile {string} -- save figure to outfile (default: {None})
        title {string} -- figure title.
        time {datetime} -- analysis time.
    """

    # check data type
    if isinstance(indata, xr.core.dataarray.DataArray):
        data = {
            'lon': indata.coords['lon'].values,
            'lat': indata.coords['lat'].values,
            'data': np.squeeze(indata.values)
        }
    else:
        data = indata

    # set data projection
    datacrs = ccrs.PlateCarree()
    plotcrs = ccrs.AlbersEqualArea(
        central_latitude=(map_extent[2] + map_extent[3]) / 2.0,
        central_longitude=(map_extent[0] + map_extent[1]) / 2.0,
        standard_parallels=[30., 60.])

    # set figure
    if isinstance(figsize, int):
        ratio = (map_extent[3] - map_extent[2]) / (map_extent[1] -
                                                   map_extent[0])
        figsize = (figsize, figsize * ratio * 0.8)
    fig = plt.figure(figsize=figsize)
    gs = mpl.gridspec.GridSpec(1,
                               2,
                               width_ratios=[1, .02],
                               bottom=.07,
                               top=.99,
                               hspace=0.01,
                               wspace=0.01)
    ax = plt.subplot(gs[0], projection=plotcrs)

    # plot map background
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=1)
    add_china_map_2cartopy(ax, name='river', edgecolor='darkcyan', lw=1)

    # set color maps
    pos = np.array(
        [-45, -30, -20, -10, -5, 0, 0, 5, 5, 10, 20, 20, 30, 30, 40, 45])
    colormap = cm_temperature_nws(pos)

    # draw CLDAS temperature
    x, y = np.meshgrid(data['lon'], data['lat'])
    pm = ax.pcolormesh(x,
                       y,
                       np.squeeze(data['data']),
                       cmap=colormap,
                       vmin=pos.min(),
                       vmax=pos.max(),
                       transform=datacrs)

    # add title
    plt.title(title, loc='left', fontsize=18)
    if time is not None:
        plt.title(time.strftime("%Y-%m-%dT%H"), loc='right', fontsize=18)

    # add grid lines
    if gridlines:
        add_gridlines(ax)

    # add color bar
    cax = plt.subplot(gs[1])
    cb = plt.colorbar(pm, cax=cax, orientation='vertical', extendrect='True')
    cb.set_label('Temperature', size=12)

    # return
    if outfile is not None:
        fig.savefig(outfile)
        plt.close(fig)
    return None
示例#12
0
def cref_uv850(initial_time, fhour=0, model='ShangHai',
               map_center=(117, 39), map_width=12, draw_wind=False):
    """
    Analysis composite reflectivity and 850hPa wind.
    
    Arguments:
        initial_time {string or datetime}} -- 
            initial time, string or datetime ojbect.
            like '18042008' or datetime(2018, 4, 20, 8).
    
    Keyword Arguments:
        fhour {int} -- forecast hour (default: {0})
        model {str} -- model name (default: {'ShangHai'})
        map_center {tuple} -- map center (default: {(117, 39)})
        map_width {int} -- map width (default: {12})
        draw_wind {bool} -- draw 850hPa wind or not (default: {False})
    
    Raises:
        ValueError -- [description]
    """

    # micaps data directory
    data_dirs = {
        'SHANGHAI': ['SHANGHAI_HR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE',
                     'SHANGHAI_HR/UGRD/850', 'SHANGHAI_HR/VGRD/850'],
        'BEIJING': ['BEIJING_MR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE',
                    'BEIJING_MR/UGRD/850', 'BEIJING_MR/VGRD/850'],
        'GRAPES_MESO': ['GRAPES_MESO_HR/RADAR_COMBINATION_REFLECTIVITY',
                        'GRAPES_MESO_HR/UGRD/850', 'GRAPES_MESO_HR/VGRD/850'],
        'GRAPES_3KM': ['GRAPES_3KM/RADAR_COMBINATION_REFLECTIVITY',
                       'GRAPES_3KM/UGRD/850', 'GRAPES_3KM/VGRD/850']}
    try:
        data_dir = data_dirs[model.strip().upper()]
    except KeyError:
        raise ValueError('Unknown model, choose ShangHai, BeiJing, Grapes_meso of Grapes_3km.')
        
    # get filename
    filename = model_filename(initial_time, fhour)
    
    # retrieve data from micaps server
    cref = get_model_grid(data_dir[0], filename=filename)
    if cref is None:
        return
    init_time = cref.coords['init_time'].values[0]
    if draw_wind:
        u850 = get_model_grid(data_dir[1], filename=filename)
        if u850 is None:
            return
        v850 = get_model_grid(data_dir[2], filename=filename)
        if v850 is None:
            return
    
    # prepare data
    data = np.ma.masked_array(cref.values)
    data[data == 9999] = np.ma.masked
    data[data < 10] = np.ma.masked
    cref_data = {'lon':cref.coords['lon'].values, 
                 'lat':cref.coords['lat'].values, 
                 'data':np.squeeze(data)}
    if draw_wind:
        uv850 = {'lon': u850.coords['lon'].values,
                 'lat': u850.coords['lat'].values,
                 'udata': np.squeeze(u850.values),
                 'vdata': np.squeeze(v850.values)}
    
    # set up map projection
    datacrs = ccrs.PlateCarree()
    plotcrs = ccrs.AlbersEqualArea(
        central_latitude=map_center[1], central_longitude=map_center[0],
        standard_parallels=[30., 60.])
    
    # set up figure
    fig = plt.figure(figsize=(12, 9))
    gs = mpl.gridspec.GridSpec(
        1, 2, width_ratios=[1, .03], 
        bottom=.01, top=.99, hspace=0.01, wspace=0.01)
    ax = plt.subplot(gs[0], projection=plotcrs)
    
    # add model title
    add_model_title(
        'CREF (dBz), 850-hPa Winds', init_time, model=model,
        fhour=fhour, fontsize=18, multilines=True)
    
    # add map background
    map_extent = (
        map_center[0] - map_width/2.0, map_center[0] + map_width/2.0,
        map_center[1] - map_width/3.0, map_center[1] + map_width/3.0)
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(
        ax, name='province', edgecolor='black',
        lw=2, zorder=100)
    
    # draw composite reflectivity
    x, y = np.meshgrid(cref_data['lon'], cref_data['lat'])
    norm, cmap = colortables.get_with_steps('NWSReflectivity', 12, 4)
    pm = ax.pcolormesh(x, y, cref_data['data'], norm=norm, cmap=cmap, transform=datacrs)
    cax = plt.subplot(gs[1])
    cb = plt.colorbar(pm, cax=cax, orientation='vertical', extendrect='True')
    cb.set_label('Composite reflectivity', size=12)

    # draw wind vector
    if draw_wind:
        x, y = np.meshgrid(uv850['lon'], uv850['lat'])
        ax.quiver(x, y, uv850['udata'], uv850['vdata'],
                  transform=datacrs, regrid_shape=25)
    
    # show figure
    gs.tight_layout(fig)
    plt.show()
示例#13
0
def cref_uv850_compare(initial_time, fhour=0, map_center=(117, 39), map_width=12, draw_wind=False):
    """
    Compare mesoscale model's composite reflectivity.
    
    Arguments:
        initial_time {string or datetime}} -- 
            initial time, string or datetime ojbect.
            like '18042008' or datetime(2018, 4, 20, 8).
    
    Keyword Arguments:
        fhour {int} -- forecast hour (default: {0})
        map_center {tuple} -- map center (default: {(117, 39)})
        map_width {int} -- map width (default: {12})
        draw_wind {bool} -- draw 850hPa wind or not (default: {False})
    """

    # micaps data directory
    data_dirs = {'SHANGHAI': ['SHANGHAI_HR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE',
                              'SHANGHAI_HR/UGRD/850', 'SHANGHAI_HR/VGRD/850'],
                 'BEIJING': ['BEIJING_MR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE',
                             'BEIJING_MR/UGRD/850', 'BEIJING_MR/VGRD/850'],
                 'GRAPES_MESO': ['GRAPES_MESO_HR/RADAR_COMBINATION_REFLECTIVITY',
                                 'GRAPES_MESO_HR/UGRD/850', 'GRAPES_MESO_HR/VGRD/850'],
                 'GRAPES_3KM': ['GRAPES_3KM/RADAR_COMBINATION_REFLECTIVITY',
                                'GRAPES_3KM/UGRD/850', 'GRAPES_3KM/VGRD/850']}
    
    # get filename
    filename = model_filename(initial_time, fhour)
    
    # set up map projection
    datacrs = ccrs.PlateCarree()
    plotcrs = ccrs.AlbersEqualArea(
        central_latitude=map_center[1], central_longitude=map_center[0],
        standard_parallels=[30., 60.])
    
    # set up figure
    fig = plt.figure(figsize=(16, 12))
    axes_class = (GeoAxes, dict(map_projection=plotcrs))
    grid = AxesGrid(fig, 111, axes_class=axes_class, nrows_ncols=(2, 2),
                    axes_pad=0.05, cbar_location='right', cbar_mode='single',
                    cbar_pad=0.05, label_mode='')
    
    # loop every data directory
    for index, key in enumerate(data_dirs):
        # get axis and data directory
        ax = grid[index]
        data_dir = data_dirs[key]
        
        # retrieve data from micaps server
        cref = get_model_grid(data_dir[0], filename=filename)
        if cref is None:
            return
        init_time = cref.coords['init_time'].values[0]
        if draw_wind:
            u850 = get_model_grid(data_dir[1], filename=filename)
            if u850 is None:
                return
            v850 = get_model_grid(data_dir[2], filename=filename)
            if v850 is None:
                return
            
        # add title
        if index == 0:
            initial_str, fhour_str, valid_str = get_model_time_stamp(init_time, fhour)
            fig.suptitle('CREF (dBz), 850-hPa Winds    ' + initial_str + '; ' + fhour_str + '; ' + valid_str,
                         x=0.5, y=0.9, fontsize=16)
    
        # prepare data
        data = np.ma.masked_array(cref.values)
        data[data == 9999] = np.ma.masked
        data[data < 10] = np.ma.masked
        cref_data = {'lon':cref.coords['lon'].values, 
                     'lat':cref.coords['lat'].values, 
                     'data':np.squeeze(data)}
        if draw_wind:
            uv850 = {'lon': u850.coords['lon'].values,
                     'lat': u850.coords['lat'].values,
                     'udata': np.squeeze(u850.values),
                     'vdata': np.squeeze(v850.values)}
    
        # add map background
        map_extent = (
            map_center[0] - map_width/2.0, map_center[0] + map_width/2.0,
            map_center[1] - map_width/3.0, map_center[1] + map_width/3.0)
        ax.set_extent(map_extent, crs=datacrs)
        add_china_map_2cartopy(
            ax, name='province', edgecolor='black',
            lw=2, zorder=100)
    
        # draw composite reflectivity
        x, y = np.meshgrid(cref_data['lon'], cref_data['lat'])
        norm, cmap = colortables.get_with_steps('NWSReflectivity', 12, 4)
        pm = ax.pcolormesh(x, y, cref_data['data'], norm=norm, cmap=cmap, transform=datacrs)

        # draw wind vector
        if draw_wind:
            x, y = np.meshgrid(uv850['lon'], uv850['lat'])
            ax.quiver(x, y, uv850['udata'], uv850['vdata'],
                      transform=datacrs, regrid_shape=25)
            
        # add title
        add_titlebox(ax, key)
            
    # add color bar
    cbar = grid.cbar_axes[0].colorbar(pm)
    
    # show figure
    plt.show()
示例#14
0
def temper_comprehensive_gg(grd_ob, grd_fo, filename=None):

    ob_min = np.min(grd_ob.values)
    fo_min = np.min(grd_fo.values)
    ob_max = np.max(grd_ob.values)
    fo_max = np.max(grd_fo.values)

    ob_fo_max = max(ob_max, fo_max)
    ob_fo_min = min(ob_min, fo_min)
    clevs_temp, cmap_temp = nmc_verification.nmc_vf_base.tool.color_tools.get_clev_and_cmap_by_element_name(
        "temp")
    clevs, cmap = nmc_verification.nmc_vf_base.tool.color_tools.get_part_clev_and_cmap(
        clevs_temp, cmap_temp, ob_fo_max, ob_fo_min)

    width = 9  #整个画面的宽度
    width_colorbar = 0.6
    height_title = 0.3
    height_veri_plot = 3

    grid0 = nmc_verification.nmc_vf_base.get_grid_of_data(grd_fo)
    if (grid0.nlon <= grid0.nlat * 0.5):
        #采用3*1布局
        width_map = (width - 2 * width_colorbar) / 3
        height_map = (grid0.nlat / grid0.nlon) * width_map
        height = height_map + height_title + height_veri_plot
        rect1 = [
            width_colorbar / width, height_veri_plot / height,
            width_map / width, height_map / height
        ]  # 实况
        rect2 = [(1 * width_map + width_colorbar) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 预报
        rect3 = [(2 * width_map + width_colorbar + 0.05) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 误差
        ob_fo_colorbar_box = [
            0.02, height_veri_plot / height, 0.015, height_map / height
        ]
        error_colorbar_box = [(3 * width_map + width_colorbar + 0.05) / width,
                              height_veri_plot / height, 0.015,
                              height_map / height]

    else:
        #采用1*2 + 1 布局
        width_map = (width - 2 * width_colorbar) / 1.5
        height_map = (grid0.nlat / grid0.nlon) * width_map
        height = height_map + height_title + height_veri_plot
        rect1 = [(width_colorbar - 0.03) / width,
                 (height_veri_plot + 0.5 * height_map) / height,
                 0.5 * width_map / width, 0.5 * height_map / height]  # 实况
        rect2 = [(width_colorbar - 0.03) / width, height_veri_plot / height,
                 0.5 * width_map / width, 0.5 * height_map / height]  # 预报
        rect3 = [(0.5 * width_map + width_colorbar) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 误差
        ob_fo_colorbar_box = [
            0.02, height_veri_plot / height, 0.01, height_map / height
        ]
        error_colorbar_box = [
            (1.5 * width_map + width_colorbar + 0.05) / width,
            height_veri_plot / height, 0.01, height_map / height
        ]

    rect4 = [0.05, 0.06, 0.26, height_veri_plot / height - 0.1]  # 散点回归图,左下宽高
    rect5 = [0.38, 0.06, 0.28, height_veri_plot / height - 0.1]  # 频率柱状图, 左下宽高
    rect6 = [0.67, 0.01, 0.3, height_veri_plot / height - 0.03]  # 左下宽高
    rect_title = [
        width_colorbar / width, (height_veri_plot + height_map) / height,
        1 - 2 * width_colorbar / width, 0.001
    ]

    fig = plt.figure(figsize=(width, height))
    # 平面对比图1
    datacrs = ccrs.PlateCarree()
    ax1 = plt.axes(rect1, projection=datacrs)
    ax2 = plt.axes(rect2, projection=datacrs)
    ax3 = plt.axes(rect3, projection=datacrs)
    # 设置地图背景

    map_extent = [grid0.slon, grid0.elon, grid0.slat, grid0.elat]
    ax1.set_extent(map_extent, crs=datacrs)
    ax2.set_extent(map_extent, crs=datacrs)
    ax3.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax1, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax1, name='river', edgecolor='blue', lw=0.3)  # 河流
    add_china_map_2cartopy(ax2, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax2, name='river', edgecolor='blue', lw=0.3)  # 河流
    add_china_map_2cartopy(ax3, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax3, name='river', edgecolor='blue', lw=0.3)  # 河流

    # 绘制格点预报场
    x = np.arange(grid0.nlon) * grid0.dlon + grid0.slon
    y = np.arange(grid0.nlat) * grid0.dlat + grid0.slat
    #clevs = [-10,0,15,20,22,24,26,28,30,32,34,35]
    #colors_grid = ["#00AAAA","#009500","#808000", "#BFBF00","#FFFF00","#FFD400","#FFAA00","#FF7F00","#FF0000","#FF002A","#FF0055","#FF0055"]

    plot_grid = ax1.contourf(x,
                             y,
                             grd_ob.values.squeeze(),
                             levels=clevs,
                             cmap=cmap,
                             transform=datacrs)  # 填色图
    ax1.set_title("实况", fontsize=12, loc="left", y=0.0)
    colorbar_position_grid = fig.add_axes(ob_fo_colorbar_box)  # 位置[左,下,宽,高]
    plt.colorbar(plot_grid, cax=colorbar_position_grid, orientation='vertical')
    plt.title("温度(℃)", fontsize=8, verticalalignment='bottom')

    ax2.contourf(x,
                 y,
                 grd_fo.values.squeeze(),
                 levels=clevs,
                 cmap=cmap,
                 transform=datacrs)  # 填色图
    ax2.set_title("预报", fontsize=12, loc="left", y=0.0)

    clevs1 = [-5, -4, -3, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5]
    error = grd_fo.values.squeeze() - grd_ob.values.squeeze()

    plot_grid1 = ax3.contourf(x,
                              y,
                              error,
                              clevs1,
                              cmap="bwr",
                              transform=datacrs)  # 填色图
    colorbar_position_grid1 = fig.add_axes(error_colorbar_box)  # 位置[左,下,宽,高]
    ax3.set_title("预报 - 实况", fontsize=12, loc="left", y=0.0)
    plt.colorbar(plot_grid1,
                 cax=colorbar_position_grid1,
                 orientation='vertical')
    plt.title("误差(℃)", fontsize=8, verticalalignment='bottom')

    time_str = nmc_verification.nmc_vf_base.tool.time_tools.time_to_str(
        grid0.gtime[0])
    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[
        6:8] + "日" + time_str[8:10] + "时"
    if type(grid0.members[0]) == str:
        model_name = grid0.members[0]
    else:
        model_name = str(grid0.members[0])

    title = model_name + " " + dati_str + "起报" + str(
        grid0.dtimes[0]) + "H时效预报和实况对比及误差"
    ax_title = plt.axes(rect_title)
    ax_title.axes.set_axis_off()
    ax_title.set_title(title)

    # 散点回归图
    ax2 = plt.axes(rect4)
    # 保证这两个值的正确性

    ob = grd_ob.values.flatten()
    fo = grd_fo.values.flatten()
    print(len(ob), len(fo))
    ax2.plot(ob, fo, '.', color='k')
    print(np.sum(fo), np.sum(ob))
    # 绘制比例线
    rate = np.sum(fo) / np.sum(ob)
    ob_line = np.arange(0, np.max(ob), np.max(ob) / 30)
    fo_rate = ob_line * rate
    ax2.plot(ob_line[0:20], fo_rate[0:20], 'r')

    # 绘制回归线
    X = np.zeros((len(ob), 1))
    X[:, 0] = ob[:]
    #绘制回归线
    clf = LinearRegression().fit(X, fo)
    X = np.zeros((len(ob_line), 1))
    X[:, 0] = ob_line[:]
    fo_rg = clf.predict(X)
    ax2.plot(ob_line, fo_rg, color='b', linestyle='dashed')
    rg_text1 = "R = " + '%.2f' % (np.corrcoef(ob, fo)[0, 1])
    rg_text2 = "y = " + '%.2f' % (clf.coef_[0]) + "* x + " + '%.2f' % (
        clf.intercept_)
    maxy = max(np.max(ob), np.max(fo)) + 5
    plt.xlim(0, maxy)
    plt.ylim(0, maxy)
    plt.text(0.05 * maxy, 0.9 * maxy, rg_text1, fontsize=10)
    plt.text(0.05 * maxy, 0.8 * maxy, rg_text2, fontsize=10)
    # maxy = max(np.max(ob),np.max(fo))
    ax2.set_xlabel("实况", fontsize=10)
    ax2.set_ylabel("预报", fontsize=10)
    ax2.set_title("散点回归图", fontsize=10)
    # 设置次刻度间隔
    xmi = 1
    if (np.max(ob) > 100): xmi = 2
    ymi = 1
    if (np.max(fo) > 100): ymi = 2
    xmajorLocator = mpl.ticker.MultipleLocator(10 * xmi)  # 将x主刻度标签设置为次刻度10倍
    ymajorLocator = mpl.ticker.MultipleLocator(10 * ymi)  # 将y主刻度标签设置为次刻度10倍
    ax2.xaxis.set_major_locator(xmajorLocator)
    ax2.yaxis.set_major_locator(ymajorLocator)
    xminorLocator = mpl.ticker.MultipleLocator(xmi)  # 将x轴次刻度标签设置xmi
    yminorLocator = mpl.ticker.MultipleLocator(ymi)  # 将y轴次刻度标签设置ymi
    ax2.xaxis.set_minor_locator(xminorLocator)
    ax2.yaxis.set_minor_locator(yminorLocator)

    #折线图
    # 绘制频率柱状图
    p_ob = np.zeros(len(clevs) - 1)
    p_fo = np.zeros(len(clevs) - 1)
    x = clevs[0:-1]
    for i in range(len(clevs) - 1):
        index0 = np.where((ob >= clevs[i]) & (ob < clevs[i + 1]))
        p_ob[i] = len(index0[0])
        index0 = np.where((fo >= clevs[i]) & (fo < clevs[i + 1]))
        p_fo[i] = len(index0[0])

    ax5 = plt.axes(rect5)
    # ax5.plot(p_ob, color='r',label="Obs")
    # ax5.plot(p_fo, color='b',label="Pred")
    ax5.bar(x + 0.5, p_ob, width=0.4, color='r', label="实况")
    ax5.bar(x + 1.1, p_fo, width=0.4, color="b", label="预报")
    ax5.legend(loc="upper right")
    ax5.set_xlabel("等级", fontsize=10)
    ax5.set_ylabel("站点数", fontsize=10)
    ax5.set_title("频率统计图", fontsize=10)
    ax5.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(1000))
    maxy = max(np.max(p_fo), np.max(p_ob)) * 1.4
    ax5.set_ylim(0, maxy)

    #检验效果图
    # 绘制降水站点实况预报统计表
    ax6 = plt.axes(rect6)
    ax6.axes.set_axis_off()
    ob_mean = np.mean(grd_ob.values)
    fo_mean = np.mean(grd_fo.values)

    maee = nmc_verification.nmc_vf_method.continuous.score.mae(ob, fo)
    mee = nmc_verification.nmc_vf_method.continuous.score.me(ob, fo)
    msee = nmc_verification.nmc_vf_method.continuous.score.mse(ob, fo)
    rmsee = nmc_verification.nmc_vf_method.continuous.score.rmse(ob, fo)
    bias_ce = nmc_verification.nmc_vf_method.continuous.score.bias(ob, fo)
    cor = nmc_verification.nmc_vf_method.continuous.score.corr(ob, fo)

    ob_has = ob[ob >= 0.01]
    fo_has = fo[fo >= 0.01]
    text = "格点检验统计量 n=" + str(len(ob)) + "\n"
    text += "==============================================\n"
    text += "                     实况               预报   \n"
    text += "----------------------------------------------\n"
    text += "平均温度         " + "%8.2f" % (ob_mean) + "%20.2f" % (
        fo_mean) + "\n\n"
    text += "温度范围    " + "%8.2f" % (ob_min) + "~%6.2f" % (
        ob_max) + "%12.2f" % (fo_min) + "~%6.2f" % (fo_max) + "\n\n"
    text += "==============================================\n\n"
    text += "Mean absolute error:" + "%6.2f" % maee + "\n\n"
    text += "Mean error:" + "%6.2f" % mee + "\n\n"
    text += "Mean-squared error:" + "%6.2f" % msee + "\n\n"
    text += "Root mean-squared error:" + "%6.2f" % rmsee + "\n\n"
    text += "Bias:" + "%6.2f" % bias_ce + "\n\n"
    text += "Correctlation coefficiant:" + "%6.2f" % cor + "\n"
    plt.text(0, 0, text, fontsize=9)

    # 图片显示或保存
    if (filename is None):
        plt.show()
        print()
    else:
        plt.savefig(filename, dpi=300)
    plt.close()
示例#15
0
def temper_gg(grd_ob, grd_fo, filename=None):

    ob_min = np.min(grd_ob.values)
    fo_min = np.min(grd_fo.values)
    ob_max = np.max(grd_ob.values)
    fo_max = np.max(grd_fo.values)

    ob_fo_max = max(ob_max, fo_max)
    ob_fo_min = min(ob_min, fo_min)
    clevs_temp, cmap_temp = nmc_verification.nmc_vf_base.tool.color_tools.get_clev_and_cmap_by_element_name(
        "temp")
    clevs, cmap = nmc_verification.nmc_vf_base.tool.color_tools.get_part_clev_and_cmap(
        clevs_temp, cmap_temp, ob_fo_max, ob_fo_min)

    width = 9  #整个画面的宽度
    width_colorbar = 0.6
    height_title = 0.3
    height_veri_plot = 0.5

    grid0 = nmc_verification.nmc_vf_base.get_grid_of_data(grd_fo)
    if (grid0.nlon <= grid0.nlat * 0.5):
        #采用3*1布局
        width_map = (width - 2 * width_colorbar) / 3
        height_map = (grid0.nlat / grid0.nlon) * width_map
        height = height_map + height_title + height_veri_plot
        rect1 = [
            width_colorbar / width, height_veri_plot / height,
            width_map / width, height_map / height
        ]  # 实况
        rect2 = [(1 * width_map + width_colorbar) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 预报
        rect3 = [(2 * width_map + width_colorbar + 0.05) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 误差
        ob_fo_colorbar_box = [
            0.02, height_veri_plot / height, 0.015, height_map / height
        ]
        error_colorbar_box = [(3 * width_map + width_colorbar + 0.05) / width,
                              height_veri_plot / height, 0.015,
                              height_map / height]

    else:
        #采用1*2 + 1 布局
        width_map = (width - 2 * width_colorbar) / 1.5
        height_map = (grid0.nlat / grid0.nlon) * width_map
        height = height_map + height_title + height_veri_plot
        rect1 = [(width_colorbar - 0.03) / width,
                 (height_veri_plot + 0.5 * height_map) / height,
                 0.5 * width_map / width, 0.5 * height_map / height]  # 实况
        rect2 = [(width_colorbar - 0.03) / width, height_veri_plot / height,
                 0.5 * width_map / width, 0.5 * height_map / height]  # 预报
        rect3 = [(0.5 * width_map + width_colorbar) / width,
                 height_veri_plot / height, width_map / width,
                 height_map / height]  # 误差
        ob_fo_colorbar_box = [
            0.02, height_veri_plot / height, 0.01, height_map / height
        ]
        error_colorbar_box = [
            (1.5 * width_map + width_colorbar + 0.05) / width,
            height_veri_plot / height, 0.01, height_map / height
        ]

    rect4 = [0.05, 0.06, 0.26, height_veri_plot / height - 0.1]  # 散点回归图,左下宽高
    rect5 = [0.38, 0.06, 0.28, height_veri_plot / height - 0.1]  # 频率柱状图, 左下宽高
    rect6 = [0.67, 0.01, 0.3, height_veri_plot / height - 0.03]  # 左下宽高
    rect_title = [
        width_colorbar / width, (height_veri_plot + height_map) / height,
        1 - 2 * width_colorbar / width, 0.001
    ]

    fig = plt.figure(figsize=(width, height))
    # 平面对比图1
    datacrs = ccrs.PlateCarree()
    ax1 = plt.axes(rect1, projection=datacrs)
    ax2 = plt.axes(rect2, projection=datacrs)
    ax3 = plt.axes(rect3, projection=datacrs)
    # 设置地图背景

    map_extent = [grid0.slon, grid0.elon, grid0.slat, grid0.elat]
    ax1.set_extent(map_extent, crs=datacrs)
    ax2.set_extent(map_extent, crs=datacrs)
    ax3.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax1, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax1, name='river', edgecolor='blue', lw=0.3)  # 河流
    add_china_map_2cartopy(ax2, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax2, name='river', edgecolor='blue', lw=0.3)  # 河流
    add_china_map_2cartopy(ax3, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax3, name='river', edgecolor='blue', lw=0.3)  # 河流

    # 绘制格点预报场
    x = np.arange(grid0.nlon) * grid0.dlon + grid0.slon
    y = np.arange(grid0.nlat) * grid0.dlat + grid0.slat
    #clevs = [-10,0,15,20,22,24,26,28,30,32,34,35]
    #colors_grid = ["#00AAAA","#009500","#808000", "#BFBF00","#FFFF00","#FFD400","#FFAA00","#FF7F00","#FF0000","#FF002A","#FF0055","#FF0055"]

    plot_grid = ax1.contourf(x,
                             y,
                             grd_ob.values.squeeze(),
                             levels=clevs,
                             cmap=cmap,
                             transform=datacrs)  # 填色图
    ax1.set_title("实况", fontsize=12, loc="left", y=0.0)
    colorbar_position_grid = fig.add_axes(ob_fo_colorbar_box)  # 位置[左,下,宽,高]
    plt.colorbar(plot_grid, cax=colorbar_position_grid, orientation='vertical')
    plt.title("温度(℃)", fontsize=8, verticalalignment='bottom')

    ax2.contourf(x,
                 y,
                 grd_fo.values.squeeze(),
                 levels=clevs,
                 cmap=cmap,
                 transform=datacrs)  # 填色图
    ax2.set_title("预报", fontsize=12, loc="left", y=0.0)

    clevs1 = [-5, -4, -3, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5]
    error = grd_fo.values.squeeze() - grd_ob.values.squeeze()

    plot_grid1 = ax3.contourf(x,
                              y,
                              error,
                              clevs1,
                              cmap="bwr",
                              transform=datacrs)  # 填色图
    colorbar_position_grid1 = fig.add_axes(error_colorbar_box)  # 位置[左,下,宽,高]
    ax3.set_title("预报 - 实况", fontsize=12, loc="left", y=0.0)
    plt.colorbar(plot_grid1,
                 cax=colorbar_position_grid1,
                 orientation='vertical')
    plt.title("误差(℃)", fontsize=8, verticalalignment='bottom')

    time_str = nmc_verification.nmc_vf_base.tool.time_tools.time_to_str(
        grid0.gtime[0])
    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[
        6:8] + "日" + time_str[8:10] + "时"
    if type(grid0.members[0]) == str:
        model_name = grid0.members[0]
    else:
        model_name = str(grid0.members[0])

    title = model_name + " " + dati_str + "起报" + str(
        grid0.dtimes[0]) + "H时效预报和实况对比及误差"
    ax_title = plt.axes(rect_title)
    ax_title.axes.set_axis_off()
    ax_title.set_title(title)

    # 图片显示或保存
    if (filename is None):
        plt.show()
        print()
    else:
        plt.savefig(filename, dpi=300)
    plt.close()
示例#16
0
def pcolormesh_2d_grid(grd, title=None, filename=None, clevs=None, cmap=None):
    x = grd['lon'].values
    y = grd['lat'].values
    rlon = x[-1] - x[0]
    rlat = y[-1] - y[0]
    height = 5
    width = height * rlon / rlat + 1
    fig = plt.figure(figsize=(width, height))
    datacrs = ccrs.PlateCarree()
    ax = plt.axes(projection=datacrs)
    map_extent = [x[0], x[-1], y[0], y[-1]]
    ax.set_extent(map_extent)

    if title is not None:
        plt.title(title)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=0.3)  #省界
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=0.3)  #河流

    if clevs is None:
        vmax = np.max(grd.values)
        vmin = np.min(grd.values)
        if vmax - vmin < 1e-10:
            vmax = vmin + 1.1
        dif = (vmax - vmin) / 10.0
        inte = math.pow(10, math.floor(math.log10(dif)))
        #用基本间隔,将最大最小值除于间隔后小数点部分去除,最后把间隔也整数化
        r = dif / inte
        if r < 3 and r >= 1.5:
            inte = inte * 2
        elif r < 4.5 and r >= 3:
            inte = inte * 4
        elif r < 5.5 and r >= 4.5:
            inte = inte * 5
        elif r < 7 and r >= 5.5:
            inte = inte * 6
        elif r >= 7:
            inte = inte * 8
        vmin = inte * ((int)(vmin / inte))
        vmax = inte * ((int)(vmax / inte) + 1)
        clevs = np.arange(vmin, vmax, inte)
    if cmap is None:
        cmap = plt.get_cmap("rainbow")
    norm = BoundaryNorm(clevs, ncolors=cmap.N, clip=True)
    im = ax.pcolormesh(x,
                       y,
                       np.squeeze(grd.values),
                       cmap=cmap,
                       norm=norm,
                       transform=datacrs)
    left_low = (width - 1) / width
    colorbar_position = fig.add_axes([left_low, 0.11, 0.03,
                                      0.77])  # 位置[左,下,宽,高]
    plt.colorbar(im, cax=colorbar_position)

    vmax = x[-1]
    vmin = x[0]
    r = rlon
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * ((int)(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)
    xticks = np.arange(vmin, vmax, inte)
    xticks_label = []
    for x in range(len(xticks)):
        xticks_label.append(str(xticks[x]))
    xticks_label[-1] += "°E"
    ax.set_xticks(xticks)
    ax.set_xticklabels(xticks_label)

    vmax = y[-1]
    vmin = y[0]
    r = rlat
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * ((int)(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)
    yticks = np.arange(vmin, vmax, inte)
    yticks_label = []
    for y in range(len(yticks)):
        yticks_label.append(str(yticks[y]))
    yticks_label[-1] += "°N"
    ax.set_yticks(yticks)
    ax.set_yticklabels(yticks_label)

    if (filename is None):
        plt.show()
    else:
        file1, extension = os.path.splitext(filename)
        extension = extension[1:]
        plt.savefig(filename, format=extension)
    plt.close()
示例#17
0
def qpf_24h(initial_time,
            fhour=0,
            model='ECMWF',
            map_center=(117, 39),
            map_width=12):
    """
    Draw 24h accumulated QPF.

    Arguments:
        initial_time {string or datetime object} -- model initital time,
            like '18042008' or datetime(2018, 4, 20, 8).

    Keyword Arguments:
        fhour {int} -- model initial time (default: {0})
        model {str} -- model name (default: {'ECMWF'})
    """

    # micaps data directory
    data_dirs = {'ECMWF': ['ECMWF_HR/RAIN24']}
    try:
        data_dir = data_dirs[model.strip().upper()]
    except KeyError:
        raise ValueError('Unknown model, choose ECMWF, GRAPES or NCEP.')

    # get file name
    filename = model_filename(initial_time, fhour)

    # retrieve data from micaps server
    rain24 = get_model_grid(data_dir[0], filename=filename)
    if rain24 is None:
        print('Can not retrieve {} from Micaps server.'.format(filename))
        return
    init_time = rain24.coords['init_time'].values[0]
    rain24 = {
        'lon': rain24.coords['lon'].values,
        'lat': rain24.coords['lat'].values,
        'data': np.squeeze(rain24.values)
    }

    # set up map projection
    datacrs = ccrs.PlateCarree()
    plotcrs = ccrs.AlbersEqualArea(central_latitude=map_center[1],
                                   central_longitude=map_center[0],
                                   standard_parallels=[30., 60.])

    # set up figure
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_axes([0, 0, 1, 1], projection=plotcrs)

    # add model title
    add_model_title('24h accumulated QPF',
                    init_time,
                    model=model,
                    fhour=fhour,
                    fontsize=18,
                    multilines=True,
                    atime=24)

    # add map background
    map_extent = (map_center[0] - map_width / 2.0,
                  map_center[0] + map_width / 2.0,
                  map_center[1] - map_width / 2.0,
                  map_center[1] + map_width / 2.0)
    ax.set_extent(map_extent, crs=datacrs)
    land_50m = cfeature.NaturalEarthFeature('physical',
                                            'land',
                                            '50m',
                                            edgecolor='face',
                                            facecolor=cfeature.COLORS['land'])
    ax.add_feature(land_50m)
    add_china_map_2cartopy(ax,
                           name='province',
                           edgecolor='darkcyan',
                           lw=1,
                           zorder=100)

    # draw QPF
    clevs = [0.1, 10, 25, 50, 100, 250]
    colors = ["#88F492", "#00A929", "#2AB8FF", "#1202FC", "#FF04F4", "#850C3E"]
    cmap, norm = mpl.colors.from_levels_and_colors(clevs, colors, extend='max')
    ax.pcolormesh(rain24['lon'],
                  rain24['lat'],
                  rain24['data'],
                  norm=norm,
                  cmap=cmap,
                  transform=datacrs,
                  zorder=2)

    # add custom legend
    legend_elements = [
        Patch(facecolor=colors[0], label='0.1~10mm'),
        Patch(facecolor=colors[1], label='10~25mm'),
        Patch(facecolor=colors[2], label='25~50mm'),
        Patch(facecolor=colors[3], label='50~100mm'),
        Patch(facecolor=colors[4], label='100~250mm'),
        Patch(facecolor=colors[5], label='>250mm')
    ]
    ax.legend(handles=legend_elements, loc='lower right', fontsize=16)

    # add logo
    add_logo(fig, alpha=0.7)

    # show figure
    ax.set_adjustable('datalim')
    plt.show()
def draw_veri_rain_24(grid_fo, sta_ob, filename=None):
    fig = plt.figure(figsize=(10, 7))
    # 平面对比图
    rect1 = [0.00, 0.42, 0.7, 0.55]  # 左下宽高
    datacrs = ccrs.PlateCarree()
    ax = plt.axes(rect1, projection=datacrs)
    # 设置地图背景
    map_extent = [grid_fo.slon, grid_fo.elon, grid_fo.slat, grid_fo.elat]
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=0.3)  # 河流

    # 绘制格点预报场
    x = np.arange(grid_fo.nlon) * grid_fo.dlon + grid_fo.slon
    y = np.arange(grid_fo.nlat) * grid_fo.dlat + grid_fo.slat
    clevs = [0.1, 10, 25, 50, 100, 250, 1000]
    colors_grid = [
        "#E0EEFA", "#B4D3E9", "#6FB0D7", "#3787C0", "#105BA4", "#07306B",
        "#07306B"
    ]
    plot_grid = ax.contourf(x,
                            y,
                            grid_fo.dat,
                            clevs,
                            colors=colors_grid,
                            transform=datacrs)  # 填色图

    colorbar_position_grid = fig.add_axes([0.035, 0.94, 0.25,
                                           0.015])  # 位置[左,下,宽,高]
    plt.colorbar(plot_grid,
                 cax=colorbar_position_grid,
                 orientation='horizontal')
    plt.text(0.035, 0.955, "model accumulated precipition(mm)", fontsize=10)
    # 绘制填色站点值
    sta_ob_in = function.get_from_sta_data.sta_in_grid_xy(sta_ob,
                                                          grid=grid_fo.grid)
    colors_sta = [
        '#FFFFFF', '#0055FF', '#00FFB4', '#F4FF00', '#FE1B00', '#910000',
        '#B800BA'
    ]
    dat = sta_ob_in.values[:, 2]
    dat[dat > 1000] = 0
    clevs = [0, 0.1, 10, 25, 50, 100, 250, 1000]
    cleves_name = [
        "0", "0.1-10", "10-25", "25-50", "50-100", "100-250", ">=250"
    ]
    for i in range(len(clevs) - 1):
        index0 = np.where((dat >= clevs[i]) & (dat < clevs[i + 1]))
        if (len(index0[0]) > 0):
            x = np.squeeze(sta_ob_in.values[index0, 0])
            y = np.squeeze(sta_ob_in.values[index0, 1])
            if (len(index0) == 1):
                x = np.array([x])
                y = np.array([y])
                if (i > 0):
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=3,
                               label=cleves_name[i],
                               linewidths=0.3,
                               edgecolor='k')
                else:
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=1,
                               label=cleves_name[i])
    ax.legend(facecolor='whitesmoke',
              title="observation",
              loc="lower left",
              edgecolor='whitesmoke')

    # 散点回归图
    rect2 = [0.07, 0.07, 0.21, 0.30]  # 左下宽高
    ax2 = plt.axes(rect2)
    sta_fo = function.gxy_sxy.interpolation_linear(grid_fo, sta_ob_in)

    ob = sta_ob_in.values[:, 2]
    fo = sta_fo.values[:, 2]
    ax2.plot(ob, fo, '.', color='k')

    # 绘制比例线
    rate = np.sum(fo) / np.sum(ob)
    ob_line = np.arange(0, np.max(ob), np.max(ob) / 30)
    fo_rate = ob_line * rate
    ax2.plot(ob_line[0:20], fo_rate[0:20], 'r')

    # 绘制回归线
    X = np.zeros((len(ob), 1))
    X[:, 0] = ob[:]
    clf = LinearRegression().fit(X, fo)
    X = np.zeros((len(ob_line), 1))
    X[:, 0] = ob_line[:]
    fo_rg = clf.predict(X)
    ax2.plot(ob_line, fo_rg, color='b', linestyle='dashed')
    rg_text1 = "R = " + '%.2f' % (np.corrcoef(ob, fo)[0, 1])
    rg_text2 = "y = " + '%.2f' % (clf.coef_[0]) + "* x + " + '%.2f' % (
        clf.intercept_)

    maxy = max(np.max(ob), np.max(fo)) + 5
    plt.xlim(0, maxy)
    plt.ylim(0, maxy)
    plt.text(0.05 * maxy, 0.9 * maxy, rg_text1, fontsize=10)
    plt.text(0.05 * maxy, 0.8 * maxy, rg_text2, fontsize=10)
    maxy = max(np.max(ob), np.max(fo))
    ax2.set_xlabel("observation", fontsize=12)
    ax2.set_ylabel("precipitation", fontsize=12)
    ax2.set_title("Obs.vs Pred. Scatter plot", fontsize=12)
    # 设置次刻度间隔
    xmi = 1
    if (np.max(ob) > 100): xmi = 2
    ymi = 1
    if (np.max(fo) > 100): ymi = 2
    xmajorLocator = mpl.ticker.MultipleLocator(10 * xmi)  # 将x主刻度标签设置为次刻度10倍
    ymajorLocator = mpl.ticker.MultipleLocator(10 * ymi)  # 将y主刻度标签设置为次刻度10倍
    ax2.xaxis.set_major_locator(xmajorLocator)
    ax2.yaxis.set_major_locator(ymajorLocator)
    xminorLocator = mpl.ticker.MultipleLocator(xmi)  # 将x轴次刻度标签设置xmi
    yminorLocator = mpl.ticker.MultipleLocator(ymi)  # 将y轴次刻度标签设置ymi
    ax2.xaxis.set_minor_locator(xminorLocator)
    ax2.yaxis.set_minor_locator(yminorLocator)

    # 绘制频率柱状图
    p_ob = np.zeros(6)
    p_fo = np.zeros(6)
    x = np.arange(6) + 1
    for i in range(1, len(clevs) - 1, 1):
        index0 = np.where((ob >= clevs[i]) & (ob < clevs[i + 1]))
        p_ob[i - 1] = len(index0[0])
        index0 = np.where((fo >= clevs[i]) & (fo < clevs[i + 1]))
        p_fo[i - 1] = len(index0[0])
    rect3 = [0.35, 0.07, 0.325, 0.17]  # 左下宽高
    ax3 = plt.axes(rect3)
    ax3.bar(x - 0.25, p_ob, width=0.2, facecolor="r", label="Obs")
    ax3.bar(x + 0.05, p_fo, width=0.2, facecolor="b", label="Pred")
    ax3.legend(loc="upper right")
    ax3.set_xlabel("precipitation threshold", fontsize=10)
    ax3.set_xticks(x)
    ax3.set_xticklabels(
        ["0.1-10", "10-25", "25-50", "50-100", "100-250", ">=250"], fontsize=9)
    ax3.set_ylabel("point number", fontsize=10)
    ax3.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(100))

    # 绘制降水站点实况预报统计表
    rect4 = [0.325, 0.255, 0.4, 0.10]  # 左下宽高
    ax4 = plt.axes(rect4)
    ax4.axes.set_axis_off()

    ob_has = ob[ob >= 0.01]
    fo_has = fo[fo >= 0.01]
    text = "制降水站点实况预报 n=" + str(len(ob)) + "\n"
    text += "=======================================================\n"
    text += "                         observation      Predication\n"
    text += "-------------------------------------------------------\n"
    text += "有降水站点数(>=0.01)        " + "%4d" % len(
        ob_has) + "                %4d" % len(fo_has) + "\n"
    text += "有降水站点数百分比%     " + "%8.2f" % (
        len(ob_has) / len(ob)) + "%20.2f" % (len(fo_has) / len(fo)) + "\n"
    text += "平均降水量(排除无降水)  " + "%8.2f" % (np.mean(ob_has)) + "%20.2f" % (
        np.mean(fo_has)) + "\n"
    text += "最大降水量              " + "%8.2f" % (np.max(ob_has)) + "%20.2f" % (
        np.max(fo_has))
    plt.text(0, 0, text, fontsize=9)

    # 绘制统计检验结果
    rect5 = [0.705, 0.01, 0.28, 0.97]  # 左下宽高
    ax5 = plt.axes(rect5)
    ax5.axes.set_axis_off()

    mae = continuous.score.mae(ob, fo)
    me = continuous.score.me(ob, fo)
    mse = continuous.score.mse(ob, fo)
    rmse = continuous.score.rmse(ob, fo)
    bias_c = continuous.score.bias(ob, fo)
    cor = continuous.score.corr(ob, fo)
    hit, mis, fal, co = yes_or_no.score.hmfn(ob, fo, clevs[1:])
    ts = yes_or_no.score.ts(ob, fo, clevs[1:])
    ets = yes_or_no.score.ets(ob, fo, clevs[1:])
    bias = yes_or_no.score.bias(ob, fo, clevs[1:])
    hit_rate = yes_or_no.score.hit_rate(ob, fo, clevs[1:])
    mis_rate = yes_or_no.score.mis_rate(ob, fo, clevs[1:])
    fal_rate = yes_or_no.score.fal_rate(ob, fo, clevs[1:])
    text = str(len(ob)) + "评分站点预报检验统计量\n"
    text += "Mean absolute error:" + "%6.2f" % mae + "\n"
    text += "Mean error:" + "%6.2f" % me + "\n"
    text += "Mean-squared error:" + "%6.2f" % mse + "\n"
    text += "Root mean-squared error:" + "%6.2f" % rmse + "\n"
    text += "Bias:" + "%6.2f" % bias_c + "\n"
    text += "Correctlation coefficiant:" + "%6.2f" % cor + "\n\n\n"
    leves_name = [
        "0.1-10-", "10-25--", "25-50--", "50-100-", "100-250", ">=250-"
    ]
    for i in range(len(leves_name)):
        text += ":" + leves_name[i] + "----------------------------\n"
        text += "正确:" + "%-4d" % hit[i] + " 空报:" + "%-4d" % fal[
            i] + " 漏报:" + "%-4d" % mis[i] + "\n"
        text += "TS:" + "%5.3f" % ts[
            i] + "                  ETS:" + "%5.3f" % ets[i] + "\n"
        text += "Hit rate:" + "%5.3f" % hit_rate[
            i] + "     Miss rate: " + "%5.3f" % mis_rate[i] + "\n"
        text += "False alarm ratio:" + "%5.3f" % fal_rate[
            i] + "  Bias:" + "%5.3f" % bias[i] + "\n\n"
    plt.text(0, 0.00, text, fontsize=11)

    # 图片显示或保存
    if (filename is None):
        plt.show()
    else:
        plt.savefig(filename, dpi=300)
    plt.close()
    return
示例#19
0
def rain_24h_sg(sta_ob, grd_fo, filename=None):
    '''
    #绘制24小时降水实况与预报对比图
    :param grd_fo: 输入的网格数据,包含一个平面的网格场
    :param sta_ob:  输入的站点数据,包含一个时刻的站点数据列表
    :param filename: 图片输出路径,缺省时会以调试窗口形式弹出
    :return: 无返回值
    '''
    grid_fo = nmc_verification.nmc_vf_base.get_grid_of_data(grd_fo)
    # 通过经纬度范围设置画幅
    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
    ) * grid_fo.nlon / grid_fo.nlat + left_plots_width + right_plots_width
    map_width = width - left_plots_width - right_plots_width

    fig = plt.figure(figsize=(width, hight))
    # 设置画幅的布局方式,
    rect1 = [
        left_plots_width / width, 0.12,
        (width - right_plots_width - left_plots_width) / width, 0.84
    ]  # 左下宽高,中央对比图
    ylabelwidth = 0.52 / width
    rect2 = [
        ylabelwidth, 0.08, left_plots_width / width - ylabelwidth - 0.005, 0.40
    ]  # 左下宽高,散点回归图
    ylabelwidth = 0.65 / width
    rect3 = [
        ylabelwidth, 0.60, left_plots_width / width - ylabelwidth - 0.005, 0.18
    ]  # 左下宽高,频谱统计柱状图
    rect4 = [0.01, 0.79, left_plots_width / width - 0.045, 0.15]  # 左下宽高,左侧文字
    rect5 = [(width - right_plots_width) / width + 0.005, -0.035,
             right_plots_width / width - 0.01, 0.90]  # 左下宽高,右侧文字
    width_ob_fo_str = 0.3
    if (map_width < 3.5):
        width_bar = 2.1  # 根据中间地图的宽度,来确定预报colorbar的尺寸
        sta_legend_size = 5  # 根据中间地图的宽度,来确定观测legend的size
    else:
        sta_legend_size = 7
        width_bar = 2.9

    rect6 = [(left_plots_width + 0.5 * map_width - 0.5 * width_bar +
              0.5 * width_ob_fo_str) / width, 0.04, width_bar / width,
             0.02]  # 预报colorbar
    rect7 = [(left_plots_width + 0.5 * map_width - 0.5 * width_bar -
              0.5 * width_ob_fo_str) / width, 0.04, width_ob_fo_str / width,
             0.3]  # 观测文字

    datacrs = ccrs.PlateCarree()
    ax = plt.axes(rect1, projection=datacrs)
    # 设置地图背景
    map_extent = [grid_fo.slon, grid_fo.elon, grid_fo.slat, grid_fo.elat]
    ax.set_extent(map_extent, crs=datacrs)
    add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=0.3)  # 省界
    add_china_map_2cartopy(ax, name='river', edgecolor='blue', lw=0.3)  # 河流

    # 绘制格点预报场
    x = np.arange(grid_fo.nlon) * grid_fo.dlon + grid_fo.slon
    y = np.arange(grid_fo.nlat) * grid_fo.dlat + grid_fo.slat
    clevs = [0.1, 10, 25, 50, 100, 250, 1000]
    colors_grid = [
        "#D0DEEA", "#B4D3E9", "#6FB0D7", "#3787C0", "#105BA4", "#07306B",
        "#07306B"
    ]
    dat = grd_fo.values.squeeze()
    # print(x)
    # print(y)
    # print(dat)
    plot_grid = ax.contourf(x,
                            y,
                            dat,
                            clevs,
                            colors=colors_grid,
                            transform=datacrs)  # 填色图
    time_str = nmc_verification.nmc_vf_base.tool.time_tools.time_to_str(
        grid_fo.gtime[0])
    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[
        6:8] + "日" + time_str[8:10] + "时"
    if type(grid_fo.members[0]) == str:
        model_name = grid_fo.members[0]
    else:
        model_name = str(grid_fo.members[0])

    if map_width < 3:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=7)
    elif map_width < 4:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=10)
    else:
        title = model_name + " " + dati_str + "起报" + str(
            grid_fo.dtimes[0]) + "H时效预报和观测"
        ax.set_title(title, fontsize=11)

    colorbar_position_grid = fig.add_axes(rect6)  # 位置[左,下,宽,高]
    cb = plt.colorbar(plot_grid,
                      cax=colorbar_position_grid,
                      orientation='horizontal')
    cb.ax.tick_params(labelsize=8)  # 设置色标刻度字体大小。
    # plt.text(0, 0, "预报(mm)", fontsize=8)

    # 绘制填色站点值
    sta_ob_in = nmc_verification.nmc_vf_base.function.get_from_sta_data.sta_in_grid_xy(
        sta_ob, grid=grid_fo)
    colors_sta = [
        '#FFFFFF', '#0055FF', '#00FFB4', '#F4FF00', '#FE1B00', '#910000',
        '#B800BA'
    ]
    dat = sta_ob_in.values[:, -1]
    dat[dat > 1000] = 0
    clevs = [0, 0.1, 10, 25, 50, 100, 250, 1000]
    cleves_name = [
        "0", "0.1-10", "10-25", "25-50", "50-100", "100-250", ">=250"
    ]
    for i in range(len(clevs) - 1):
        index0 = np.where((dat >= clevs[i]) & (dat < clevs[i + 1]))
        if (len(index0[0]) > 0):
            x = np.squeeze(sta_ob_in["lon"].values[index0])
            y = np.squeeze(sta_ob_in["lat"].values[index0])
            if (len(index0) == 1):
                x = np.array([x])
                y = np.array([y])
                if (i > 0):
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=3,
                               label=cleves_name[i],
                               linewidths=0.3,
                               edgecolor='k')
                else:
                    ax.scatter(x,
                               y,
                               c=colors_sta[i],
                               transform=ccrs.PlateCarree(),
                               s=1,
                               label=cleves_name[i],
                               linewidths=0.1,
                               edgecolor="k")
    ax.legend(facecolor='whitesmoke',
              loc="lower center",
              ncol=4,
              edgecolor='whitesmoke',
              prop={'size': sta_legend_size},
              bbox_to_anchor=(0.5 + 0.5 * width_ob_fo_str / map_width, -0.08))
    ax7 = plt.axes(rect7)
    ax7.axes.set_axis_off()
    plt.text(0, 0.00, "观测\n\n预报", fontsize=7)

    # 图片显示或保存
    if (filename is None):
        plt.show()
        print()
    else:
        plt.savefig(filename, dpi=300)
    plt.close()
    return