def map_add_currents(ax, currents, coarsen=None, scale=None, headwidth=None, headlength=None, headaxislength=None): """ Add currents to map :param dsd: dataset :param sub: amount to downsample by :return: """ scale = scale or 90 headwidth = headwidth or 2.75 headlength = headlength or 2.75 headaxislength = headaxislength or 2.5 coarsen = coarsen or 2 try: qds = currents.coarsen(lon=coarsen, boundary='pad').mean().coarsen( lat=coarsen, boundary='pad').mean() mesh = True except ValueError: qds = currents.coarsen(X=coarsen, boundary='pad').mean().coarsen( Y=coarsen, boundary='pad').mean() mesh = False angle, speed = uv2spdir(qds['u'], qds['v']) # convert u/v to angle and speed u, v = spdir2uv( # convert angle and speed back to u/v, normalizing the arrow sizes np.ones_like(speed), angle, deg=True) qargs = {} qargs['scale'] = scale qargs['headwidth'] = headwidth qargs['headlength'] = headlength qargs['headaxislength'] = headaxislength qargs['transform'] = ccrs.PlateCarree() if mesh: lons, lats = np.meshgrid(qds['lon'], qds['lat']) q = ax.quiver(lons, lats, u, v, **qargs) else: q = ax.quiver(qds.lon.squeeze().data, qds.lat.squeeze().data, u.squeeze(), v.squeeze(), **qargs) return q
def plot_model_region_comparison_quiver(rtofs, gofs, region, time, bathy=None, argo=None, gliders=None, currents=None, transform=None, save_dir=None, dpi=None, t0=None, ticks=True, colorbar=True): """ :param ds: model 1 :param ds2: :param region: :param t1: :param bathy: :param argo: :param gliders: :param transform: :param save_dir: :param dpi: :param t0: :return: """ bathy = bathy or None transform = transform or dict(map=ccrs.Mercator(), data=ccrs.PlateCarree()) save_dir = save_dir or os.getcwd() dpi = dpi or 150 region_name = region[0] limits = region[1] extent = limits['lonlat'] region_file_str = ('_').join(region_name.lower().split(' ')) save_dir_region = os.path.join(save_dir, 'regions', region_file_str) # eez = '/Users/mikesmith/Documents/github/rucool/Daily_glider_models_comparisons/World_EEZ_v11_20191118/eez_boundaries_v11.shp' # shape_feature = cfeature.ShapelyFeature(Reader(eez).geometries(), ccrs.PlateCarree(), edgecolor='red', facecolor='none') for k, v in limits.items(): if k == 'currents': var_str = 'currents'.title() save_dir_var = os.path.join(save_dir_region, k) for item in v: depth = item['depth'] rds = rtofs.sel(depth=depth) gds = gofs.sel(depth=depth) save_dir_depth = os.path.join(save_dir_var, f'{depth}m') sname = f'{k}-model-comparison-{time.strftime("%Y-%m-%dT%H%M%SZ")}' save_dir_final = os.path.join(save_dir_depth, time.strftime('%Y/%m')) os.makedirs(save_dir_final, exist_ok=True) save_file = os.path.join(save_dir_final, sname) save_file = save_file + '.png' vargs = {} vargs['transform'] = transform['data'] vargs['cmap'] = cmocean.cm.speed # vargs['cmap'] = 'viridis' vargs['ticks'] = ticks # Initiate transect plot fig = plt.figure(figsize=(16, 10), constrained_layout=True) grid = plt.GridSpec(12, 20, hspace=0.2, wspace=0.2, figure=fig) ax1 = plt.subplot(grid[0:9, 0:8], projection=transform['map']) ax2 = plt.subplot(grid[0:9, 10:18], projection=transform['map']) ax3 = plt.subplot(grid[9:11, :]) fig.tight_layout() fig.subplots_adjust(top=0.9) first_line = f'Region:{region_name.title()}, Variable:{var_str}, Depth: {depth}m' second_line = f'\nTime: {str(time)} UTC\nGlider/Argo Search Window: {str(t0)} to {str(time)}' # Add RTOFS SUBPLOT angle, speed = uv2spdir( rds.u, rds.v) # convert u/v to angle and speed rds['speed'] = (('Y', 'X'), speed) vargs['vmin'] = 0 vargs['vmax'] = 1 vargs['levels'] = np.arange(0, 1.1, .1) ax1, h1 = region_subplot(fig, ax1, extent, rds['speed'], 'RTOFS', argo, gliders, bathy, **vargs) cwargs = copy.deepcopy(item) cwargs.pop('bool') try: cwargs.pop('depth') except KeyError: pass cwargs['scale'] = 30 cwargs['headwidth'] = 5 cwargs['headlength'] = 5 cwargs['headaxislength'] = 4.5 map_add_currents(ax1, rds, **cwargs) # ax1.add_feature(shape_feature, zorder=1) ax1.set_xlabel('Longitude', fontsize=14) ax1.set_ylabel('Latitude', fontsize=14) if colorbar: axins = inset_axes( ax1, # here using axis of the lowest plot width="2.5%", # width = 5% of parent_bbox width height="100%", # height : 340% good for a (4x4) Grid loc='lower left', bbox_to_anchor=(1.05, 0., 1, 1), bbox_transform=ax1.transAxes, borderpad=0) cb = fig.colorbar(h1, cax=axins) # cb.ax.tick_params(labelsize=12) # cb.set_label(f'{rtofs_sub[k].name.title()} ({rtofs_sub[k].units})', fontsize=13) # Add GOFS SUBPLOT angle, speed = uv2spdir( gds.u, gds.v) # convert u/v to angle and speed gds['speed'] = (('lat', 'lon'), speed) vargs['vmin'] = 0 vargs['vmax'] = 1 vargs['levels'] = np.arange(0, 1.1, .1) ax2, h2 = region_subplot(fig, ax2, extent, gds['speed'], 'GOFS', argo, gliders, bathy, **vargs) cwargs = copy.deepcopy(item) cwargs.pop('bool') try: cwargs.pop('depth') except KeyError: pass # scale=None, headwidth=None, headlength=None, headaxislength=None cwargs['scale'] = 30 cwargs['headwidth'] = 5 cwargs['headlength'] = 5 cwargs['headaxislength'] = 4.5 map_add_currents(ax2, gds, **cwargs) # ax2.add_feature(shape_feature, zorder=1) ax2.set_xlabel('Longitude', fontsize=14) # ax2.set_ylabel('Latitude', fontsize=14) if colorbar: axins = inset_axes( ax2, # here using axis of the lowest plot width="2.5%", # width = 5% of parent_bbox width height="100%", # height : 340% good for a (4x4) Grid loc='lower left', bbox_to_anchor=(1.05, 0., 1, 1), bbox_transform=ax2.transAxes, borderpad=0) cb = fig.colorbar(h2, cax=axins) cb.ax.tick_params(labelsize=12) cb.set_label(f'Speed (m/s)', fontsize=13) h, l = ax2.get_legend_handles_labels( ) # get labels and handles from ax1 if l: ax3.legend(h, l, ncol=6, loc='center', fontsize=10) ax3.set_axis_off() # if l: # plt.legend(h, l, ncol=6, loc='center', fontsize=10) plt.suptitle(r"$\bf{" + first_line + "}$" + second_line, fontsize=13) # plt.tight_layout() plt.savefig(save_file, dpi=dpi, bbox_inches='tight', pad_inches=0.1) # plt.show() plt.close()
facecolor='none') fig = plt.figure() tds = ds.squeeze() u = tds['u'].data v = tds['v'].data lon = tds.coords['lon'].data lat = tds.coords['lat'].data # time = tds.coords['time'].data u = ma.masked_invalid(u) v = ma.masked_invalid(v) angle, speed = uv2spdir(u, v) us, vs = spdir2uv(np.ones_like(speed), angle, deg=True) lons, lats = np.meshgrid(lon, lat) speed_clipped = np.clip(speed[::sub, ::sub], velocity_min, velocity_max).squeeze() fig, ax = plt.subplots(figsize=(11, 8), subplot_kw=dict(projection=ccrs.PlateCarree())) # Plot title plt.title('{}\n{}'.format(title_str, str(ds.time.values[0]))) # plot arrows over pcolor h = ax.quiver(lons[::sub, ::sub],
def surface_map_glider_track(ds, region, bathy=None, argo=None, gliders=None, transform=None, model=None, save_dir=None, dpi=None, custom_transect=None, current_glider_loc=None): """ Written by Mike Smith Modified by Lori Garzio """ bathy = bathy or None transform = transform or ccrs.PlateCarree() argo = argo or False gliders = gliders or False save_dir = save_dir or os.getcwd() model = model or 'rtofs' dpi = dpi or 150 custom_transect = custom_transect or None current_glider_loc = current_glider_loc or None limits = region[1] extent = limits['lonlat'] save_dir_maps = os.path.join(save_dir, 'surface_maps', region[1]["code"]) os.makedirs(save_dir_maps, exist_ok=True) glider_name = gliders.deployment_name.split('-')[0] glidert0 = np.nanmin(gliders.time.values) glidert1 = np.nanmax(gliders.time.values) glidert0_str = pd.to_datetime(glidert0).strftime('%Y-%m-%dT%H:%M') glidert1_str = pd.to_datetime(glidert1).strftime('%Y-%m-%dT%H:%M') if model in ['gofs', 'cmems']: t1 = pd.to_datetime(ds.time.data) elif model == 'rtofs': t1 = pd.to_datetime(ds.time.data[0]) else: return 'Incorrect model type. Please enter "gofs", "rtofs" or "cmems"' for k, v in limits.items(): if k in ['lonlat', 'code', 'currents']: continue if k == 'salinity': var_str = 'Sea Surface Salinity' elif k == 'temperature': var_str = 'Sea Surface Temperature' for item in v: depth = item['depth'] if depth > 0: # only plot sea surface continue try: dsd = ds.sel(depth=depth) except KeyError: dsd = ds.sel(depth=slice(0, 1)) if len(dsd.depth) > 1: raise ValueError('More than one depth between 0-1m') title = f'{glider_name} track: {glidert0_str} to {glidert1_str}\n' \ f'{model.upper()} {var_str} at {str(t1)} UTC' sname = f'{glider_name}_{region[1]["code"]}_{model}_{k}_{t1.strftime("%Y-%m-%dT%H%M%SZ")}' save_file = os.path.join(save_dir_maps, sname) vargs = {} vargs['vmin'] = item['limits'][0] vargs['vmax'] = item['limits'][1] vargs['transform'] = transform vargs['cmap'] = sp.cmaps(ds[k].name) vargs['extend'] = 'both' if k == 'sea_surface_height': vargs['levels'] = np.arange(vargs['vmin'], vargs['vmax'], item['limits'][2]) limits['currents'] = True else: vargs['levels'] = np.arange(vargs['vmin'], vargs['vmax'], item['limits'][2]) try: vargs.pop('vmin'), vargs.pop('vmax') except KeyError: pass fig, ax = plt.subplots( figsize=(11, 8), subplot_kw=dict(projection=ccrs.Mercator()) ) h = plt.contourf(dsd['lon'], dsd['lat'], dsd[k].squeeze(), **vargs) if k == 'sea_surface_height': sub = 6 qds = dsd.coarsen(lon=sub, boundary='pad').mean().coarsen(lat=sub, boundary='pad').mean() angle, speed = uv2spdir(qds['u'], qds['v']) # convert u/v to angle and speed u, v = spdir2uv( # convert angle and speed back to u/v, normalizing the arrow sizes np.ones_like(speed), angle, deg=True ) qargs = {} # qargs['norm'] = Normalize(vmin=velocity_min, vmax=velocity_max, clip=True) qargs['scale'] = 90 # qargs['headwidth'] = 2.5 # qargs['headlength'] = 4 # qargs['headaxislength'] = 4 qargs['headwidth'] = 2.75 qargs['headlength'] = 2.75 qargs['headaxislength'] = 2.5 qargs['transform'] = ccrs.PlateCarree() # qargs['pivot'] = 'mid' # qargs['units'] = 'inches' # sub = 3 lons, lats = np.meshgrid(qds['lon'], qds['lat']) q = plt.quiver(lons, lats, u, v, **qargs) if bathy: levels = np.arange(-100, 0, 50) bath_lat = bathy.variables['lat'][:] bath_lon = bathy.variables['lon'][:] bath_elev = bathy.variables['elevation'][:] CS = plt.contour(bath_lon, bath_lat, bath_elev, levels, linewidths=.75, alpha=.5, colors='k', transform=ccrs.PlateCarree()) ax.clabel(CS, [-100], inline=True, fontsize=7, fmt=sp.fmt) # plt.contourf(bath_lon, bath_lat, bath_elev, np.arange(-9000,9100,100), cmap=cmocean.cm.topo, transform=ccrs.PlateCarree()) sp.map_add_features(ax, extent) sp.map_add_ticks(ax, extent) if argo: atimes = [] for i in argo: ax.plot(i.lon, i.lat, marker='o', markersize=7, color='w', markeredgecolor='black', label=i.name, transform=ccrs.PlateCarree()) atimes.append(pd.to_datetime(i.time)) title = '{}\n Argo floats (circles): {} to {} '.format(title, pd.to_datetime(np.min(atimes)).strftime('%Y-%m-%dT%H:%M'), pd.to_datetime(np.max(atimes)).strftime('%Y-%m-%dT%H:%M')) #ax.legend(loc='upper right', fontsize=6) # plot full glider track ax.plot(gliders.longitude.values, gliders.latitude.values, color='white', linewidth=1.5, label='Glider Track', transform=ccrs.PlateCarree()) ax.legend(loc='upper left') if current_glider_loc: ax.plot(gliders.longitude.values[-1], gliders.latitude.values[-1], color='white', marker='^', markeredgecolor='black', markersize=8.5, transform=ccrs.PlateCarree()) if custom_transect: ax.plot(custom_transect['lon'], custom_transect['lat'], color='magenta', linewidth=1.5, label='Model Comparison', transform=ccrs.PlateCarree()) ax.legend(loc='upper left') # Plot title plt.title(title) # Set colorbar height equal to plot height divider = make_axes_locatable(ax) cax = divider.new_horizontal(size='5%', pad=0.05, axes_class=plt.Axes) fig.add_axes(cax) # generate colorbar cbar = plt.colorbar(h, cax=cax) cbar.set_label(ds[k].units) plt.savefig(save_file, dpi=dpi, bbox_inches='tight', pad_inches=0.1) plt.close()
def plot_radials(dataset, *, plot_type='velocity', output_file=None, extent=None, lon_ticks=None, lat_ticks=None, scale=True, sub=2, cbar_step=10, velocity_min=None, velocity_max=None, markers=None, prim_filter=False, title='HF Radar'): """ param dataset: a file-path to an xarray compatible object or an xarray Dataset object """ try: ds = xr.open_dataset(dataset) closing = ds.close except AttributeError: if isinstance(dataset, xr.Dataset): ds = dataset closing = int # dummy func to close nothing else: raise tds = ds.squeeze() if prim_filter: if 'PRIM' in list(tds.keys()): tds = tds.where(tds.PRIM == 1).squeeze() title = title + ' - QC' else: logging.warning('PRIM flag not found. Bypassing quality control filters') time = ds.time.values[0] lon = tds.coords['lon'].data lat = tds.coords['lat'].data u = tds['u'].data v = tds['v'].data u = ma.masked_invalid(u) v = ma.masked_invalid(v) if scale: angle, speed = uv2spdir(u, v) # convert u/v to angle and speed u, v = spdir2uv( # convert angle and speed back to u/v, normalizing the arrow sizes np.ones_like(speed), angle, deg=True ) velocity_min = velocity_min or -40 velocity_max = velocity_max or 40 kwargs = dict(extent=extent, lon_ticks=lon_ticks, lat_ticks=lat_ticks, output_file=output_file, sub=sub, markers=markers, title=title, meshgrid=False, scale=120, headwidth=2.5, headlength=4, headaxislength=4) if 'velocity' in plot_type: """ Velocity displays the direction and magnitude of the radials """ kwargs['colorbar'] = True kwargs['cmap'] = cmocean.cm.balance # Define arrow colors. Limited by velocity_min and velocity_max kwargs['color_clipped'] = np.clip( tds.velocity.data[::sub], velocity_min, velocity_max ).squeeze() kwargs['offset'] = Normalize(vmin=velocity_min, vmax=velocity_max, clip=True) kwargs['ticks'] = np.append(np.arange(velocity_min, velocity_max, cbar_step), velocity_max) elif 'motion' in plot_type: """ Motion displays the direction (towards or away) from radar """ kwargs['colorbar'] = False kwargs['cmap'] = 'bwr' velocity = tds.velocity velocity_temp = velocity.where(velocity > 0, other=-1) # Going away from radar kwargs['color_clipped'] = velocity_temp.where(velocity < 0, other=1).data # Going towards radar kwargs['offset'] = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=1) elif 'qc_pass_fail' in plot_type: kwargs['colorbar'] = False kwargs['cmap'] = colors.ListedColormap(['limegreen', 'red']) if prim_filter: tds = ds.squeeze() kwargs['color_clipped'] = tds.PRIM.where(tds.PRIM != 1, other=-1).data # PRIM == 1 where vectors pass qc kwargs['offset'] = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=1) closing() plot_common(time, lon, lat, u, v, **kwargs)
def plot_totals(dataset, *, output_file=None, extent=None, scale=True, sub=2, cbar_step=20, velocity_min=None, velocity_max=None, markers=None, title='HF Radar'): """ param dataset: a file-path to an xarray compatible object or an xarray Dataset object """ try: ds = xr.open_dataset(dataset) closing = ds.close except AttributeError: if isinstance(dataset, xr.Dataset): ds = dataset closing = int # dummy func to close nothing else: raise tds = ds.squeeze() u = tds['u'].data v = tds['v'].data lon = tds.coords['lon'].data lat = tds.coords['lat'].data try: time = str(ds.time.values[0]) except IndexError: time = ds.time.values closing() if scale: angle, speed = uv2spdir(u, v) # convert u/v to angle and speed u, v = spdir2uv( # convert angle and speed back to u/v, normalizing the arrow sizes np.ones_like(speed), angle, deg=True ) velocity_min = velocity_min or np.int32(np.nanmin(speed)) or 0 velocity_max = velocity_max or np.int32(np.nanmax(speed)) or 15 kwargs = dict(output_file=output_file, sub=sub, markers=markers, title=title, meshgrid=True, scale=60, headwidth=3, headlength=5, headaxislength=4.5) kwargs['color_clipped'] = np.clip( speed[::sub], velocity_min, velocity_max ).squeeze() kwargs['offset'] = Normalize(vmin=velocity_min, vmax=velocity_max, clip=True) kwargs['ticks'] = np.append(np.arange(velocity_min, velocity_max, cbar_step), velocity_max) kwargs['extent'] = extent plt = plot_common( time, lon, lat, u, v, **kwargs ) if output_file is None: return plt
def plot_common(time, lon, lat, u, v, *, output_file=None, meshgrid=True, sub=2, velocity_min=None, velocity_max=None, markers=None, title='HF Radar'): """ param markers: a list of 3-tuple/lists containng [lon, lat, marker kwargs] as should be passed into ax.plot() eg. [ [-74.6, 38.5, dict(marker='o', markersize=8, color='r')], [-70.1, 35.2, dict(marker='o', markersize=8, color='b')] ] """ markers = markers or [] fig = plt.figure() u = ma.masked_invalid(u) v = ma.masked_invalid(v) angle, speed = uv2spdir(u, v) us, vs = spdir2uv(np.ones_like(speed), angle, deg=True) if meshgrid is True: lons, lats = np.meshgrid(lon, lat) else: lons, lats = lon, lat velocity_min = velocity_min or 0 velocity_max = velocity_max or np.nanmax(speed) or 15 speed_clipped = np.clip(speed[::sub, ::sub], velocity_min, velocity_max).squeeze() fig, ax = plt.subplots(figsize=(11, 8), subplot_kw=dict(projection=ccrs.PlateCarree())) # Plot title plt.title('{}\n{}'.format(title, time)) # plot arrows over pcolor h = ax.quiver(lons[::sub, ::sub], lats[::sub, ::sub], us[::sub, ::sub], vs[::sub, ::sub], speed_clipped, cmap='jet', scale=60) divider = make_axes_locatable(ax) cax = divider.new_horizontal(size='5%', pad=0.05, axes_class=plt.Axes) fig.add_axes(cax) # generate colorbar ticks = np.linspace(velocity_min, velocity_max, 5) cb = plt.colorbar(h, cax=cax, ticks=ticks) cb.ax.set_yticklabels([f'{s:.2f}' for s in ticks]) cb.set_label('cm/s') for m in markers: ax.plot(m[0], m[1], **m[2]) # Gridlines and grid labels gl = ax.gridlines(draw_labels=True, linewidth=1, color='black', alpha=0.5, linestyle='--') gl.xlabels_top = gl.ylabels_right = False gl.xlabel_style = {'size': 10, 'color': 'gray'} gl.ylabel_style = {'size': 10, 'color': 'gray'} gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER # Axes properties and features ax.set_extent([lon.min() - 1, lon.max() + 1, lat.min() - 1, lat.max() + 1]) ax.add_feature(LAND, zorder=0, edgecolor='black') ax.add_feature(cfeature.LAKES) ax.add_feature(cfeature.BORDERS) ax.add_feature(state_lines, edgecolor='black') fig_size = plt.rcParams["figure.figsize"] fig_size[0] = 12 fig_size[1] = 8.5 plt.rcParams["figure.figsize"] = fig_size if output_file is not None: create_dir(str(Path(output_file).parent)) resoluton = 150 # plot resolution in DPI plt.savefig(output_file, dpi=resoluton) plt.close('all') else: return plt
def plot_ruv(radial_file, save_path=None, fname=None, speed_display='color', redblue=True, plotflag=None, scale=50, vlims=(-100, 100)): """ Main function to plot radial files. Args: radial_file (str or Path): Path to radial file or a Radial object save_path (str or Path): Path to save figures fname (str): Output file name. If not specified, the radial object filename is used, Defaults to None speed_display (str, optional): 'color' or 'arrowlength' to specify whether current speed is depicted by color or arrow length, Defaults to color redblue (bool, optional): If True, colorbar scheme is redblue, Defaults to True plotflag (str, optional): QARTOD QC test code, fail and suspect flags for that test will be highlighted, Defaults to None scale (int, optional): Scaling factor for drawing the vectors, Default = 50 vlims (tuple, optional): Velocity limits for the colorbar, Default = (-100,100) """ if not isinstance(radial_file, Radial): r = Radial(radial_file) else: r = radial_file if not r.is_valid(): return if r._iscorrupt: return if fname == None: fname = r.file_name[0:-4] # Adjust some standard plotting settings to make them the size of a sheet of paper fig_size = plt.rcParams["figure.figsize"] fig_size[0] = 12 fig_size[1] = 8 plt.rcParams["figure.figsize"] = fig_size # Set colors of the land. edgecolor = 'black' landcolor = 'tan' LAND = cfeature.NaturalEarthFeature('physical', 'land', '10m', edgecolor='face', facecolor='tan') state_lines = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='50m', facecolor='none') bf = 0.3 #degrees extent = [ r.data.LOND.min() - bf, r.data.LOND.max() + bf, r.data.LATD.min() - bf, r.data.LATD.max() + bf ] # Split out everything into seperate variables in order to pass them easier to the plotting functions time = r.time lon = r.data.LOND.to_numpy() lat = r.data.LATD.to_numpy() u = r.data.VELU.to_numpy() v = r.data.VELV.to_numpy() velocity = r.data.VELO.to_numpy() sitename = r.metadata['Site'][0:4] ptype = r.metadata['PatternType'] # Mask nans just in case there are any u = ma.masked_invalid(u) v = ma.masked_invalid(v) # convert U and V component velocities to angle and speed angle, speed = uv2spdir(u, v) # convert angle and speed right back back to U and V component velocities, # Passing speed as an array of 1's allows for the normalizing of the arrow sizes # if we pass the correct u, v = spdir2uv(np.ones_like(speed), angle, deg=True) # Get the receiver location receiver_location = [float(x) for x in r.metadata['Origin'].split(' ')] receiver_location.reverse() # Intialize an empty subplot using cartopy fig, ax = plt.subplots(figsize=(11, 8), subplot_kw=dict(projection=ccrs.Mercator())) #plt.quiver(lon, lat, u, v, transform=ccrs.PlateCarree()) plt.plot(receiver_location[0], receiver_location[1], 'o', markersize=10, markeredgecolor='black', color='red', transform=ccrs.PlateCarree()) map_features(ax, extent, LAND, edgecolor, landcolor, state_lines) # The next lines specify the arrow shapes. You can customize this to your preference, usually by trial and error. # scale = 50 headwidth = 2.5 headlength = 4 headaxislength = 4 sub = 1 # if user requested speed displayed as arrow length if speed_display == 'arrowlength': scale_units = 'width' width = 0.005 if not plotflag == None: fail = r.data[plotflag] == 4 suspect = r.data[plotflag] == 3 noteval = r.data[plotflag] == 2 away = r.data.VELO > 0 plt.quiver(lon, lat, u, v, transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='lightpink') plt.quiver(lon[away], lat[away], u[away], v[away], transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='lightblue') #plt.quiver(lon, lat, u, v, transform=ccrs.PlateCarree(), scale=scale, color='white') plt.quiver(lon[fail], lat[fail], u[fail], v[fail], transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='red') plt.quiver(lon[suspect], lat[suspect], u[suspect], v[suspect], transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='gold') plt.quiver(lon[noteval], lat[noteval], u[noteval], v[noteval], transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='gray') plt.title( f'{sitename} {ptype} {plotflag}\nFail(red) Suspect(yellow) Not Evaluated(grey)\n{time}' ) plt.savefig(save_path + '/' + fname + '_' + plotflag) plt.close('all') elif redblue: away = r.data.VELO > 0 plt.quiver(lon, lat, u, v, transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='red') plt.quiver(lon[away], lat[away], u[away], v[away], transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='blue') plt.title(f'{sitename} {ptype}\n{time}') plt.savefig(save_path + '/' + fname + '_rb') plt.close('all') else: plt.quiver(lon, lat, u, v, transform=ccrs.PlateCarree(), scale=scale, scale_units=scale_units, width=width, color='wheat') plt.title(f'{sitename} {ptype}\n{time}') plt.savefig(save_path + '/' + fname) plt.close('all') # if user requested speed displayed as color else: if not plotflag == None: test = r.data[plotflag] velocity[np.where(test >= 0)] = 1 velocity[np.where(test == 4)] = -1 color_clipped = np.clip(r.data.VELO[::sub], -1, 1).squeeze() offset = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=1) cmap = colors.ListedColormap(['red', 'wheat']) plt.title(f'{sitename} {ptype} {plotflag} Fail\n{time}') qargs = dict(cmap=cmap, scale=scale, headwidth=headwidth, headlength=headlength, headaxislength=headaxislength) qargs['transform'] = ccrs.PlateCarree() qargs['norm'] = offset # plot arrows over pcolor h = ax.quiver(lon[::sub], lat[::sub], u[::sub], v[::sub], color_clipped, **qargs) plt.savefig(save_path + '/' + fname + '_' + plotflag + '_fail') plt.close('all') elif redblue: cmap = 'bwr' # velocity_temp = velocity.where(velocity > 0, other=-1) # Going away from radar velocity[np.where(velocity < 0)] = -1 velocity[np.where(velocity >= 0)] = 1 # We will create temporary variable of velocities that sets any velocity less than 0 to 1 # color_clipped = velocity_temp.where(velocity < 0, other=1) # Going towards radar # Define arrow colors. Limited by velocity_min and velocity_max color_clipped = np.clip(r.data.VELO[::sub], -1, 1).squeeze() offset = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=1) plt.title(f'{sitename} {ptype}\n{time}') qargs = dict(cmap=cmap, scale=scale, headwidth=headwidth, headlength=headlength, headaxislength=headaxislength) qargs['transform'] = ccrs.PlateCarree() qargs['norm'] = offset # plot arrows over pcolor h = ax.quiver(lon[::sub], lat[::sub], u[::sub], v[::sub], color_clipped, **qargs) # map_features(ax, extent, LAND, edgecolor, landcolor, state_lines) plt.savefig(save_path + '/' + fname + '_rb') plt.close('all') else: plt.title(f'{sitename} {ptype}\n{time}') cmap = cmocean.cm.balance # Colorbar options velocity_min = vlims[ 0] # The minimum speed that should be displayed on the colorbar velocity_max = vlims[ 1] # The maximum speed that should be displayed on the colorbar cbar_step = 10 # The step between each colorbar tick offset = Normalize(vmin=velocity_min, vmax=velocity_max, clip=True) # Define arrow colors. Limited by velocity_min and velocity_max color_clipped = np.clip(r.data.VELO[::sub], velocity_min, velocity_max).squeeze() ticks = np.append(np.arange(velocity_min, velocity_max, cbar_step), velocity_max) qargs = dict(cmap=cmap, scale=scale, headwidth=headwidth, headlength=headlength, headaxislength=headaxislength) qargs['transform'] = ccrs.PlateCarree() qargs['norm'] = offset # plot arrows over pcolor h = ax.quiver(lon[::sub], lat[::sub], u[::sub], v[::sub], color_clipped, **qargs) # map_features(ax, extent, LAND, edgecolor, landcolor, state_lines) # generate colorbar divider = make_axes_locatable(ax) cax = divider.new_horizontal(size='5%', pad=0.05, axes_class=plt.Axes) fig.add_axes(cax) cb = plt.colorbar(h, cax=cax, ticks=ticks) cb.ax.set_yticklabels([f'{s:d}' for s in ticks]) cb.set_label('cm/s') plt.savefig(save_path + '/' + fname) plt.close('all')