def plt_tsk(nc, model, figname):
    """
    Create a pcolor surface map of surface skin temperature
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    """
    tsk = nc['TSK']
    color_label = 'TSK (\N{DEGREE SIGN}C)'
    title = 'Surface Skin Temperature (\N{DEGREE SIGN}C)'

    plot_types = ['full_grid',
                  'bight']  # plot the full grid and just NY Bight area
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            tsk_sub, ax_lims, xticks, yticks = cf.subset_grid(tsk, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            tsk_sub, ax_lims, xticks, yticks = cf.subset_grid(tsk, 'bight')

        fig, ax, lat, lon = cf.set_map(tsk_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # convert degrees K to degrees C
        tsk_sub_c = tsk_sub.values - 273.15

        # add contour lines
        contour_list = np.linspace(0, 30, 7)
        pf.add_contours(ax, lon, lat, tsk_sub_c, contour_list)

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        vlims = [0, 32]
        cmap = cmo.cm.thermal
        levels = MaxNLocator(nbins=16).tick_values(
            vlims[0], vlims[1])  # levels every 2 degrees C
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = title
        kwargs['clab'] = color_label
        # kwargs['var_lims'] = vlims
        kwargs['norm_clevs'] = norm
        kwargs['extend'] = 'both'
        kwargs['cmap'] = cmap
        pf.plot_pcolormesh(fig, ax, lon, lat, tsk_sub_c, **kwargs)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        plt.savefig(figname, dpi=200)
        plt.close()
def plt_radar(nc, model, figname, lease_areas=None):
    """
    Create filled contour surface maps of radar reflectivity
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    """
    lease_areas = lease_areas or None

    # MDBZ = max radar reflectivity
    radar = nc['MDBZ']

    plot_types = ['full_grid', 'bight']  # plot the full grid and just NY Bight area
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            radar_sub, ax_lims, xticks, yticks = cf.subset_grid(radar, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]), new_fname)
            radar_sub, ax_lims, xticks, yticks = cf.subset_grid(radar, 'bight')

        fig, ax, lat, lon = cf.set_map(radar_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start, model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        title = 'Radar Composite Reflectivity ({})'.format(radar.units)

        vmin = 0
        vmax = 72
        levels = np.linspace(vmin, vmax, 145)
        ticklevs = np.linspace(vmin, 70, 15)

        # If the array is all zeros, turn the zeros to nans. Otherwise the plot will be all teal instead of white.
        if np.nanmax(radar_sub) == 0.0:
            radar_sub.values[radar_sub == 0] = np.nan

        kwargs = dict()
        kwargs['ttl'] = title
        kwargs['cmap'] = 'pyart_NWSRef'
        kwargs['clab'] = title
        kwargs['var_lims'] = [vmin, vmax]
        kwargs['cbar_ticks'] = ticklevs.tolist()

        pf.plot_contourf(fig, ax, lon, lat, radar_sub, levels, **kwargs)

        plt.savefig(figname, dpi=200)
        plt.close()
Exemple #3
0
def plt_radar(nc, subset_domain, figname):
    """
    Create filled contour surface maps of radar reflectivity
    :param nc: netcdf file
    :param subset_domain: the plotting limit domain, e.g. 3km, 9km, bight (NY Bight), full_grid, mab, nj, snj
    :param figname: full file path to save directory and save filename
    """
    radar = nc['Reflectivity']

    radar_sub, ax_lims, xticks, yticks = cf.subset_grid_wct(radar, subset_domain)

    fig, ax, lat, lon = cf.set_map(radar_sub)

    # initialize keyword arguments for map features
    kwargs = dict()
    kwargs['xticks'] = xticks
    kwargs['yticks'] = yticks

    cf.add_map_features(ax, ax_lims, **kwargs)

    title = 'Radar Reflectivity ({})'.format(radar_sub.units)

    kwargs = dict()
    kwargs['ttl'] = title
    kwargs['cmap'] = 'pyart_NWSRef'
    kwargs['clab'] = title
    kwargs['var_lims'] = [0, 72]

    # If the array is all zeros, turn the zeros to nans. Otherwise the plot will be all teal instead of white.
    if np.nanmax(radar_sub) == 0.0:
        radar_sub.values[radar_sub == 0] = np.nan

    pf.plot_pcolormesh(fig, ax, lon, lat, np.squeeze(radar_sub.values), **kwargs)

    plt.savefig(figname, dpi=200)
    plt.close()
def plt_rain(nc, model, figname, raintype, lease_areas=None, ncprev=None):
    """
    Create filled contour surface maps of hourly and accumulated rain
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    :param raintype: plot type to make, e.g. 'acc' (accumulated) or 'hourly'
    :param lease_areas: optional, dictionary containing lat/lon coordinates for wind energy lease area polygon
    :param ncprev: optional, netcdf file from the previous model hour to calculate hourly rainfall
    """
    lease_areas = lease_areas or None
    ncprev = ncprev or None

    # RAINNC = total accumulated rainfall
    rn = nc['RAINNC']
    plot_types = ['full_grid', 'bight']

    if raintype == 'acc':
        new_fname = 'acc{}'.format(figname.split('/')[-1])
        figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                  new_fname)
        color_label = 'Total Accumulated Precipitation (in)'
        title = color_label
        slp = None  # don't plot sea level pressure for accumulated rain maps
    elif raintype == 'hourly':
        color_label = 'Hourly Precipitation (in)'
        title = '{}, Sea Level Pressure (mb)'.format(color_label)
        slp = nc['SLP']
        # calculate hourly rainfall for every model hour by subtracting the rainfall for the previous hour from
        # the rainfall for the current hour
        if ncprev:
            preciprev = ncprev['RAINNC']
            rn = np.subtract(np.squeeze(rn), np.squeeze(preciprev))
        else:
            rn = rn

    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            if isinstance(slp, xr.DataArray):
                slp_sub, _, _, _ = cf.subset_grid(slp, model)
            rn_sub, ax_lims, xticks, yticks = cf.subset_grid(rn, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            if isinstance(slp, xr.DataArray):
                slp_sub, _, _, _ = cf.subset_grid(slp, 'bight')
            rn_sub, ax_lims, xticks, yticks = cf.subset_grid(rn, 'bight')

        fig, ax, lat, lon = cf.set_map(rn_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        # convert mm to inches
        rn_sub = rn_sub * 0.0394

        # modified NWS colormap, from http://jjhelmus.github.io/blog/2013/09/17/plotting-nsw-precipitation-data/
        nws_precip_colors = [
            "#fdfdfd",  # 0.01 - 0.10 inches
            "#019ff4",  # 0.10 - 0.25 inches
            "#0300f4",  # 0.25 - 0.50 inches
            "#02fd02",  # 0.50 - 0.75 inches
            "#01c501",  # 0.75 - 1.00 inches
            "#008e00",  # 1.00 - 1.50 inches
            "#fdf802",  # 1.50 - 2.00 inches
            "#e5bc00",  # 2.00 - 2.50 inches
            "#fd9500",  # 2.50 - 3.00 inches
            "#fd0000",  # 3.00 - 4.00 inches
            "#d40000",  # 4.00 - 5.00 inches
            "#bc0000",  # 5.00 - 6.00 inches
            "#f800fd",  # 6.00 - 8.00 inches
            "#9854c6",  # 8.00 - 10.00 inches
            "#4B0082"  # 10.00+
        ]
        precip_colormap = mpl.colors.ListedColormap(nws_precip_colors)

        # specify colorbar level demarcations
        levels = [
            0.01, 0.1, 0.25, 0.50, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0,
            6.0, 8.0, 10., 12.
        ]

        kwargs = dict()
        kwargs['ttl'] = title
        kwargs['cmap'] = precip_colormap
        kwargs['clab'] = color_label
        kwargs['normalize'] = 'yes'
        kwargs['extend'] = 'max'

        # plot data
        pf.plot_contourf(fig, ax, lon, lat, rn_sub, levels, **kwargs)

        # add slp as contours if provided
        if isinstance(slp, xr.DataArray):
            contour_list = [
                940, 944, 948, 952, 956, 960, 964, 968, 972, 976, 980, 984,
                988, 992, 996, 1000, 1004, 1008, 1012, 1016, 1020, 1024, 1028,
                1032, 1036, 1040
            ]
            pf.add_contours(ax, lon, lat, slp_sub, contour_list)

        plt.savefig(figname, dpi=200)
        plt.close()
Exemple #5
0
def plt_2m_temp(nc, model, figname, lease_areas=None):
    """
    Create a pcolor surface map of air temperature at 2m with contours
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    """
    lease_areas = lease_areas or None

    t2 = nc['T2']
    color_label = 'Air Temperature (\N{DEGREE SIGN}F)'

    plot_types = ['full_grid',
                  'bight']  # plot the full grid and just NY Bight area
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            t2_sub, ax_lims, xticks, yticks = cf.subset_grid(t2, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            t2_sub, ax_lims, xticks, yticks = cf.subset_grid(t2, 'bight')

        fig, ax, lat, lon = cf.set_map(t2_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        # convert K to F
        d = np.squeeze(t2_sub.values) * 9 / 5 - 459.67

        # add contour lines
        contour_list = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
        pf.add_contours(ax, lon, lat, d, contour_list)

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        vlims = [-20, 110]
        cmap = plt.get_cmap('jet')
        # levels = MaxNLocator(nbins=30).tick_values(vlims[0], vlims[1])  # levels every 5 degrees F
        levels = MaxNLocator(nbins=65).tick_values(
            vlims[0], vlims[1])  # levels every 2 degrees F
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = '2m {}'.format(color_label)
        kwargs['clab'] = color_label
        # kwargs['var_lims'] = vlims
        kwargs['norm_clevs'] = norm
        kwargs['extend'] = 'both'
        pf.plot_pcolormesh(fig, ax, lon, lat, d, **kwargs)

        # # contourf: smooths the resolution of the model data, plots are less pixelated
        # kwargs = dict()
        # kwargs['ttl'] = '2m {}'.format(color_label)
        # kwargs['clab'] = color_label
        # kwargs['var_lims'] = [-20, 110]
        # kwargs['cbar_ticks'] = np.linspace(-20, 100, 7)
        #
        # levels = np.arange(-20, 110.5, .5)
        # pf.plot_contourf(fig, ax, lon, lat, d, levels, **kwargs)

        plt.savefig(figname, dpi=200)
        plt.close()
def plt_power(nc, model, ht, figname, lease_areas=None):
    """
    Create pseudocolor surface maps of estimated wind power at 160m.
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param ht: wind speed height to plot, e.g. 160m
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    """
    power_curve = '/home/lgarzio/rucool/bpu/wrf/wrf_lw15mw_power_15001max.csv'  # on server, max is set to 15001
    pc = pd.read_csv(power_curve)
    turbine = power_curve.split('/')[-1].split('_')[1].split('lw')[-1].upper()
    lease_areas = lease_areas or None

    if ht == '10m':
        u = nc['U10']
        v = nc['V10']
    else:
        u = nc.sel(height=int(ht[0:-1]))['U']
        v = nc.sel(height=int(ht[0:-1]))['V']

    color_label = f'Estimated {turbine} Wind Power (kW)'

    plot_types = ['full_grid', 'bight']
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            u_sub, _, _, _ = cf.subset_grid(u, model)
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            u_sub, _, _, _ = cf.subset_grid(u, 'bight')
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, 'bight')

        fig, ax, lat, lon = cf.set_map(u_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        # calculate wind speed from u and v
        speed = cf.wind_uv_to_spd(u_sub, v_sub)

        # calculate wind power
        power = xr.DataArray(np.interp(speed, pc['Wind Speed'], pc['Power']),
                             coords=speed.coords)

        # add contours
        contour_list = [15000]
        pf.add_contours(ax, lon, lat, power, contour_list)

        # set color map
        cmap = plt.get_cmap('OrRd')
        levels = list(np.arange(0, 15001, 1000))

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = '{} {}'.format(ht, color_label)
        kwargs['cmap'] = cmap
        kwargs['clab'] = color_label
        kwargs['norm_clevs'] = norm
        kwargs['extend'] = 'neither'
        pf.plot_pcolormesh(fig, ax, lon, lat, power, **kwargs)

        # add power values of 15000 as another layer
        power_copy = power.copy()
        custom_color = ["#67000d"]  # dark red
        custom_colormap = ListedColormap(custom_color)
        mask = np.logical_and(power_copy.values < 15001,
                              power_copy.values < 15001)
        power_copy.values[mask] = np.nan
        ax.pcolormesh(lon,
                      lat,
                      power_copy,
                      cmap=custom_colormap,
                      transform=ccrs.PlateCarree())

        plt.savefig(figname, dpi=200)
        plt.close()
Exemple #7
0
def plt_solar(nc, model, figname, lease_areas=None):
    """
    Create pcolor surface maps of total, diffuse, and direct shortwave flux with contours
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    """
    lease_areas = lease_areas or None

    varname = figname.split('/')[-1].split('_')[0]

    if varname == 'swdown':
        solar = nc['SWDOWN']
        title = r'Total Shortwave Flux (W $\rm m^{-2}$)'
    elif varname == 'diffuse':
        solar = nc['SWDOWN'] * nc['DIFFUSE_FRAC']
        title = r'Diffuse Shortwave Flux (W $\rm m^{-2}$)'
    elif varname == 'direct':
        solar = nc['SWDOWN'] * (1 - nc['DIFFUSE_FRAC'])
        title = r'Direct Shortwave Flux (W $\rm m^{-2}$)'

    plot_types = ['full_grid',
                  'bight']  # plot the full grid and just NY Bight area
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            solar_sub, ax_lims, xticks, yticks = cf.subset_grid(solar, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            solar_sub, ax_lims, xticks, yticks = cf.subset_grid(solar, 'bight')

        fig, ax, lat, lon = cf.set_map(solar_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks

        # for diffuse shortwave flux, make state and coastline edgecolor gray, and make wind energy lease area magenta
        # for total and direct, change the state and coastline edgecolor to gray, and make wind energy lease area
        # magenta if solar radiation is beneath a certain threshold
        mingray = 100  # minimum average value for making the state/coastlines gray
        if varname == 'diffuse':
            kwargs['ecolor'] = '#525252'
            cf.add_map_features(ax, ax_lims, **kwargs)
            lease_area_color = 'magenta'
        else:
            if np.nanmean(solar_sub) < mingray:
                kwargs['ecolor'] = '#525252'
                cf.add_map_features(ax, ax_lims, **kwargs)
                lease_area_color = 'magenta'
            else:
                cf.add_map_features(ax, ax_lims, **kwargs)
                lease_area_color = '#252525'  # #252525 is very close to black

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, lease_area_color)

        color_label = r'Surface Downwelling Shortwave Flux (W $\rm m^{-2}$)'  # \rm removes the italics
        contour_list = np.linspace(200, 1000, 5)

        # add contour lines
        pf.add_contours(ax, lon, lat, solar_sub, contour_list)

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        vlims = [0, 1200]
        cmap = plt.get_cmap(plt.cm.CMRmap)
        #levels = MaxNLocator(nbins=14).tick_values(vlims[0], vlims[1])  # every 100 W m-2
        levels = MaxNLocator(nbins=25).tick_values(vlims[0],
                                                   vlims[1])  # every 50 W m-2
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = title
        kwargs['cmap'] = cmap
        kwargs['clab'] = color_label
        # kwargs['var_lims'] = vlims
        kwargs['norm_clevs'] = norm
        pf.plot_pcolormesh(fig, ax, lon, lat, solar_sub, **kwargs)

        plt.savefig(figname, dpi=200)
        plt.close()
Exemple #8
0
def plt_snow(nc, model, figname, snowtype, lease_areas=None, ncprev=None):
    """
    Create filled contour surface maps of hourly and accumulated snowfall
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param figname: full file path to save directory and save filename
    :param snowtype: plot type to make, e.g. 'acc' (accumulated) or 'hourly'
    :param lease_areas: optional, dictionary containing lat/lon coordinates for wind energy lease area polygon
    :param ncprev: optional, netcdf file from the previous model hour to calculate hourly snowfall
    """
    lease_areas = lease_areas or None
    ncprev = ncprev or None

    # SNOWNC = water equivalent of total accumulated snowfall
    snow = nc['SNOWNC']
    plot_types = ['full_grid', 'bight']

    if snowtype == 'acc':
        new_fname = 'acc{}'.format(figname.split('/')[-1])
        figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                  new_fname)
        color_label = 'Total Accumulated Snow 10:1 (in)'

        # specify colorbar level demarcations and contour levels
        levels = [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20]
        contour_list = [0, 2, 4, 6, 10, 20]

    elif snowtype == 'hourly':
        color_label = 'Hourly Snowfall 10:1 (in)'
        # calculate hourly snowfall for every model hour by subtracting the snowfall for the previous hour from
        # the snowfall for the current hour
        if ncprev is not None:
            snowprev = ncprev['SNOWNC']
            snow = np.subtract(np.squeeze(snow), np.squeeze(snowprev))
        else:
            snow = snow

            # specify colorbar level demarcations and contour levels
        levels = [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5]
        contour_list = [0, 1, 2, 3, 4, 5]

    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            snow_sub, ax_lims, xticks, yticks = cf.subset_grid(snow, model)
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            snow_sub, ax_lims, xticks, yticks = cf.subset_grid(snow, 'bight')

        fig, ax, lat, lon = cf.set_map(snow_sub)

        # convert mm to in then multiply by 10 since the output is water equivalent
        snow_in = snow_sub * 0.0393701 * 10

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        snow_colors = [
            "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c",
            "#9e9ac8", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"
        ]
        snow_colormap = mpl.colors.ListedColormap(snow_colors)

        # make 0 white instead of blue without showing up on the colorbar
        snow_colormap.set_under('white')
        levels[0] = 1e-10

        kwargs = dict()
        kwargs['ttl'] = color_label
        kwargs['cmap'] = snow_colormap
        kwargs['clab'] = color_label
        kwargs['normalize'] = 'yes'
        kwargs['cbar_ticks'] = levels
        kwargs['extend'] = 'max'

        # plot data
        pf.plot_contourf(fig, ax, lon, lat, snow_in, levels, **kwargs)

        # add contours
        pf.add_contours(ax, lon, lat, snow_in, contour_list)

        plt.savefig(figname, dpi=200)
        plt.close()
def plt_windsp(nc, model, ht, figname, lease_areas=None):
    """
    Create pseudocolor surface maps of wind speed with quivers indicating wind direction.
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param ht: wind speed height to plot, e.g. 10m, 80m, 160m
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    """
    lease_areas = lease_areas or None

    if ht == '10m':
        u = nc['U10']
        v = nc['V10']
    else:
        u = nc.sel(height=int(ht[0:-1]))['U']
        v = nc.sel(height=int(ht[0:-1]))['V']

    color_label = 'Wind Speed (knots)'

    # define the subsetting for the quivers on the map based on model and height
    quiver_subset = dict(_3km=dict(_10m=11, _80m=12, _160m=13),
                         _9km=dict(_10m=4, _80m=5, _160m=6),
                         bight_3km=dict(_10m=6, _80m=6, _160m=7),
                         bight_9km=dict(_10m=2, _80m=2, _160m=3))

    plot_types = ['full_grid', 'bight']
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            u_sub, _, _, _ = cf.subset_grid(u, model)
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, model)
            qs = quiver_subset['_{}'.format(model)]['_{}'.format(ht)]
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            u_sub, _, _, _ = cf.subset_grid(u, 'bight')
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, 'bight')
            qs = quiver_subset['bight_{}'.format(model)]['_{}'.format(ht)]

        fig, ax, lat, lon = cf.set_map(u_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        # convert wind speeds from m/s to knots
        u_sub = np.squeeze(u_sub.values) * 1.94384
        v_sub = np.squeeze(v_sub.values) * 1.94384

        # standardize the vectors so they only represent direction
        u_sub_standardize = u_sub / cf.wind_uv_to_spd(u_sub, v_sub)
        v_sub_standardize = v_sub / cf.wind_uv_to_spd(u_sub, v_sub)

        # calculate wind speed from u and v
        speed = cf.wind_uv_to_spd(u_sub, v_sub)

        # mask vectors if wind speed is < 2
        mask = speed < 2
        u_sub_standardize[mask] = np.nan
        v_sub_standardize[mask] = np.nan

        # add contours
        contour_list = [5, 10, 15, 20]
        pf.add_contours(ax, lon, lat, speed, contour_list)

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        cmap = plt.get_cmap('turbo')
        vlims = [0, 20]
        levels = MaxNLocator(nbins=20).tick_values(vlims[0],
                                                   vlims[1])  # every 2 knots
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = 'Wind Speed ({}) Wind Ops'.format(ht)
        kwargs['cmap'] = cmap
        kwargs['clab'] = color_label
        kwargs['norm_clevs'] = norm
        kwargs['extend'] = 'neither'
        pf.plot_pcolormesh(fig, ax, lon, lat, speed, **kwargs)

        ax.quiver(lon[::qs, ::qs],
                  lat[::qs, ::qs],
                  u_sub_standardize[::qs, ::qs],
                  v_sub_standardize[::qs, ::qs],
                  scale=50,
                  width=.002,
                  headlength=4,
                  transform=ccrs.PlateCarree())

        plt.savefig(figname, dpi=200)
        plt.close()
def plt_windsp(nc,
               model,
               ht,
               figname,
               lease_areas=None,
               summary=None,
               add_text=None):
    """
    Create pseudocolor surface maps of wind speed with quivers indicating wind direction.
    :param nc: netcdf file
    :param model: the model version that is being plotted, e.g. 3km or 9km
    :param ht: wind speed height in mb to plot, e.g. 925
    :param figname: full file path to save directory and save filename
    :param lease_areas: optional dictionary containing lat/lon coordinates for wind energy lease area polygon
    :param summary: optional dictionary containing locations of specific locations for seabreeze classification,
    and a list to append windspeeds at specific locations for summary output
    :param add_text: optional, add windspeed/direction values at specific locations to the figure
    """
    lease_areas = lease_areas or None
    summary = summary or None
    add_text = add_text or None

    u = nc.sel(pressure=ht)['UP']
    v = nc.sel(pressure=ht)['VP']

    color_label = 'Wind Speed (m/s)'
    quiver_subset = dict(_3km=dict(_925=12),
                         _9km=dict(_925=4),
                         bight_3km=dict(_925=6),
                         bight_9km=dict(_925=2))

    plot_types = ['full_grid', 'bight']
    for pt in plot_types:
        if pt == 'full_grid':  # subset the entire grid
            u_sub, _, _, _ = cf.subset_grid(u, model)
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, model)
            qs = quiver_subset['_{}'.format(model)]['_{}'.format(ht)]
        else:  # subset just NY Bight
            new_fname = 'bight_{}'.format(figname.split('/')[-1])
            figname = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]),
                                      new_fname)
            u_sub, _, _, _ = cf.subset_grid(u, 'bight')
            v_sub, ax_lims, xticks, yticks = cf.subset_grid(v, 'bight')
            qs = quiver_subset['bight_{}'.format(model)]['_{}'.format(ht)]

        fig, ax, lat, lon = cf.set_map(u_sub)

        # add text to the bottom of the plot
        cf.add_text(ax, nc.SIMULATION_START_DATE, nc.time_coverage_start,
                    model)

        # initialize keyword arguments for map features
        kwargs = dict()
        kwargs['xticks'] = xticks
        kwargs['yticks'] = yticks
        cf.add_map_features(ax, ax_lims, **kwargs)

        if lease_areas:
            pf.add_lease_area_polygon(ax, lease_areas, 'magenta')

        # convert wind speeds from m/s to knots
        # u_sub = xr.DataArray(np.squeeze(u_sub.values) * 1.94384, coords=u_sub.coords)
        # v_sub = xr.DataArray(np.squeeze(v_sub.values) * 1.94384, coords=v_sub.coords)

        # standardize the vectors so they only represent direction
        u_sub_standardize = u_sub / cf.wind_uv_to_spd(u_sub, v_sub)
        v_sub_standardize = v_sub / cf.wind_uv_to_spd(u_sub, v_sub)

        # calculate wind speed and direction from u and v
        speed = cf.wind_uv_to_spd(u_sub, v_sub)
        direction = cf.wind_uv_to_dir(u_sub, v_sub)

        # write a summary for wind speeds/directions at specified locations for seabreeze classification
        # add the windspeeds/directions to the map
        map_values = dict()
        if summary:
            tmstr = pd.to_datetime(
                nc.Time.values[0]).strftime('%Y-%m-%dT%H:%M')
            for key, coords in summary['locations'].items():
                # find the closest model grid point to the location
                a = abs(speed.XLAT - coords['lat']) + abs(speed.XLONG -
                                                          coords['lon'])
                i, j = np.unravel_index(a.argmin(), a.shape)
                sp = speed[i, j]
                d = direction[i, j]
                coords.update(ws=np.round(float(sp.values), 2))
                coords.update(direction=np.round(float(d.values), 2))
                map_values[key] = coords
                if pt == 'full_grid':
                    wrf_lat = np.round(float(sp.XLAT.values), 4)
                    wrf_lon = np.round(float(sp.XLONG.values), 4)
                    summary['rows'].append([
                        tmstr, key, coords['lat'], coords['lon'], ht, wrf_lat,
                        wrf_lon,
                        np.round(float(sp.values), 4),
                        np.round(float(d.values), 4)
                    ])

        # mask vectors if wind speed is < 1 m/s
        mask = speed.values < 1
        u_sub_standardize.values[mask] = np.nan
        v_sub_standardize.values[mask] = np.nan

        # add contours
        #contour_list = [10, 22, 34, 48, 64]
        contour_list = [5, 11, 17, 25, 32]
        pf.add_contours(ax, lon, lat, speed, contour_list)

        # plot data
        # pcolormesh: coarser resolution, shows the actual resolution of the model data
        cmap = plt.get_cmap('BuPu')
        # vlims = [0, 40]
        # levels = MaxNLocator(nbins=20).tick_values(vlims[0], vlims[1])  # every 2 knots
        vlims = [0, 25]
        levels = MaxNLocator(nbins=25).tick_values(vlims[0],
                                                   vlims[1])  # every 1 m/s
        norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

        kwargs = dict()
        kwargs['ttl'] = '{}mb {}'.format(ht, color_label)
        kwargs['cmap'] = cmap
        kwargs['clab'] = color_label
        #kwargs['var_lims'] = vlims
        kwargs['norm_clevs'] = norm
        kwargs['extend'] = 'max'
        pf.plot_pcolormesh(fig, ax, lon, lat, speed, **kwargs)

        # # contourf: smooths the resolution of the model data, plots are less pixelated
        # kwargs = dict()
        # kwargs['ttl'] = '{} {}'.format(ht, color_label)
        # kwargs['cmap'] = cmap
        # kwargs['clab'] = color_label
        # kwargs['var_lims'] = [0, 40]
        # kwargs['cbar_ticks'] = np.linspace(0, 40, 9)
        #
        # levels = np.arange(0, 40.1, .1)
        # pf.plot_contourf(fig, ax, lon, lat, speed, levels, **kwargs)

        # subset the quivers and add as a layer
        # ax.quiver(lon[::qs, ::qs], lat[::qs, ::qs], u_sub[::qs, ::qs], v_sub[::qs, ::qs], scale=1000,
        #           width=.002, headlength=4, transform=ccrs.PlateCarree())

        ax.quiver(lon[::qs, ::qs],
                  lat[::qs, ::qs],
                  u_sub_standardize.values[::qs, ::qs],
                  v_sub_standardize.values[::qs, ::qs],
                  scale=50,
                  width=.002,
                  headlength=4,
                  transform=ccrs.PlateCarree())

        # add the seabreeze classification locations to the map
        if summary:
            if pt == 'full_grid':
                offset = 1.75
            else:
                offset = .85
            for key, values in map_values.items():
                ax.scatter(values['lon'],
                           values['lat'],
                           c='magenta',
                           s=40,
                           zorder=15,
                           transform=ccrs.PlateCarree())
                if add_text:
                    ax.text(values['lon'] - offset,
                            values['lat'],
                            '{} {}'.format(values['ws'], values['direction']),
                            transform=ccrs.PlateCarree(),
                            bbox=dict(facecolor='lightgray', alpha=1),
                            fontsize=8,
                            zorder=15)

        plt.savefig(figname, dpi=200)
        plt.close()