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()
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()
def plt_cloudfrac(nc, model, figname, lease_areas=None): """ Create a pcolor surface map of cloud cover :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 var = nc['cloudfrac'] color_label = 'Cloud Cover (%)' splitter = figname.split('/')[-1].split('_') # calculate maximum cloud fraction among each level = Total Cloud Fraction max_cloudfrac = np.max(np.squeeze(var), axis=0) # plot_types = ['full_grid', 'bight'] plot_types = ['full_grid'] for pt in plot_types: if pt == 'full_grid': # create a new file path new_fname = '{}_{}'.format(splitter[0], '_'.join(splitter[1:len(splitter)])) save_fig = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]), new_fname) # subset the entire grid max_cloudfrac_sub, ax_lims, xticks, yticks = cf.subset_grid( max_cloudfrac, model) else: # create a new file path new_fname = 'bight_{}_{}'.format( splitter[0], '_'.join(splitter[1:len(splitter)])) save_fig = '/{}/{}'.format(os.path.join(*figname.split('/')[0:-1]), new_fname) # subset just NY Bight max_cloudfrac_sub, ax_lims, xticks, yticks = cf.subset_grid( max_cloudfrac, 'bight') fig, axs, lat, lon = set_map_panel(max_cloudfrac_sub) fig.suptitle(color_label, fontsize=17, y=.94) d = max_cloudfrac_sub.values * 100 vlims = [0, 100] # plot Total Cloud Fraction in the bottom right panel ax4 = axs[1, 1] # add text to the bottom of the plot targs = dict() targs['add_y'] = .08 cf.add_text(ax4, nc.SIMULATION_START_DATE, nc.time_coverage_start, model, **targs) kwargs = dict() kwargs['panel_title'] = 'Total Cloud Fraction' kwargs['cmap'] = 'gray' kwargs['var_lims'] = vlims kwargs['clab'] = color_label pf.plot_pcolormesh_panel(fig, ax4, lon, lat, d, **kwargs) kwargs = dict() kwargs['ecolor'] = 'red' kwargs['xticks'] = xticks kwargs['yticks'] = yticks kwargs['left_labs'] = 'remove' cf.add_map_features(ax4, ax_lims, **kwargs) if lease_areas: pf.add_lease_area_polygon(ax4, lease_areas, 'magenta') # plot each level ax1 = axs[0, 0] ax2 = axs[0, 1] ax3 = axs[1, 0] axes_ind = [ax1, ax2, ax3] for i, level in enumerate(var['low_mid_high'].values): ds = var.sel(low_mid_high=level) if pt == 'full_grid': # subset the entire grid ds_sub, ax_lims, xticks, yticks = cf.subset_grid(ds, model) else: # subset just NY Bight ds_sub, ax_lims, xticks, yticks = cf.subset_grid(ds, 'bight') d = ds_sub.values * 100 # keyword arguments for plotting function pcargs = dict() pcargs['cmap'] = 'gray' pcargs['var_lims'] = vlims # keyword arguments for add_map_features mapargs = dict() mapargs['ecolor'] = 'red' mapargs['xticks'] = xticks mapargs['yticks'] = yticks if level == 300: pcargs['panel_title'] = 'Low Level ({} m)'.format(level) mapargs['bottom_labs'] = 'remove' elif level == 2000: pcargs['panel_title'] = 'Mid Level ({} m)'.format(level) pcargs['clab'] = color_label mapargs['bottom_labs'] = 'remove' mapargs['left_labs'] = 'remove' elif level == 6000: pcargs['panel_title'] = 'High Level ({} m)'.format(level) pf.plot_pcolormesh_panel(fig, axes_ind[i], lon, lat, d, **pcargs) cf.add_map_features(axes_ind[i], ax_lims, **mapargs) if lease_areas: pf.add_lease_area_polygon(axes_ind[i], lease_areas, 'magenta') plt.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9, wspace=0.02, hspace=0.01) plt.savefig(save_fig, dpi=200) plt.close()
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()
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()
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()