Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
    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],
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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')