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, 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_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_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()