Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #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
Example #5
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
Example #6
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
Example #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
Example #8
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