示例#1
0
 def normalize(self, fcst):
     if 'time' in fcst.dims:
         if not fcst.dims['time'] == 1:
             raise ValueError("Expected a single time for VelocityField")
         fcst = fcst.isel(time=0)
     fcst = self.variable.normalize(fcst)
     units.convert_units(fcst[self.variable.speed_name],
                         self.speed_units)
     units.convert_units(fcst[self.variable.direction_name],
                         'radians')
     return fcst
示例#2
0
文件: tinylib.py 项目: ms8r/slocum
def check_beaufort(obj):

    if conv.UWND in obj:
        units.convert_units(obj[conv.UWND], _units[conv.WIND_SPEED])
        # we need both UWND and VWND to do anything with wind
        assert conv.VWND in obj
        units.convert_units(obj[conv.VWND], _units[conv.WIND_SPEED])
        # double check
        assert obj[conv.UWND].attrs[conv.UNITS] == _units[conv.WIND_SPEED]
        assert obj[conv.VWND].attrs[conv.UNITS] == _units[conv.WIND_SPEED]

    if conv.ENS_SPREAD_WS in obj:
        units.convert_units(obj[conv.ENS_SPREAD_WS],
                _units[conv.ENS_SPREAD_WS])
        # double check
        assert (obj[conv.ENS_SPREAD_WS].attrs[conv.UNITS] ==
                _units[conv.ENS_SPREAD_WS])

    # make sure latitudes are in degrees and are on the correct scale
    assert 'degrees' in obj[conv.LAT].attrs[conv.UNITS]
    assert np.min(np.asarray(obj[conv.LAT].values)) >= -90
    assert np.max(np.asarray(obj[conv.LAT].values)) <= 90
    # make sure longitudes are in degrees and are on the correct scale
    assert 'degrees' in obj[conv.LON].attrs[conv.UNITS]
    obj[conv.LON].values[:] = np.mod(obj[conv.LON].values + 180., 360) - 180.
    assert obj[conv.UWND].shape == obj[conv.VWND].shape

    if conv.PRECIP in obj:
        units.convert_units(obj[conv.PRECIP], _units[conv.PRECIP])
示例#3
0
文件: spot.py 项目: akleeman/slocum
    def normalize(self, fcsts):
        fcsts = ensure_single_location(fcsts)
        fcsts = self.variable.normalize(fcsts)

        # add a realization dimension if it doesn't exist.  This
        # allows us to support both ensemble and non-ensemble
        # forecasts with the same code.
        if not 'realization' in fcsts:
            def add_ensemble(vn):
                fcsts[vn] = (xray.concat([fcsts[vn]], 'realization')
                             .transpose('time', 'realization'))
            add_ensemble(self.variable.speed_name)
            add_ensemble(self.variable.direction_name)

        units.convert_units(fcsts[self.variable.speed_name],
                            self.speed_units)
        units.convert_units(fcsts[self.variable.direction_name],
                            'radians')
        return fcsts
示例#4
0
    def __init__(self, fcst, velocity_variable,
                 speed_units='knots', ax=None, fig=None,
                  **kwdargs):
        self.variable = velocity_variable
        self.speed_units = speed_units
        # set the default colormap if needed
        kwdargs['cmap'] = kwdargs.get('cmap', velocity_cmap)

        # convert the bins to knots
        bins = xray.Variable('bins',
                             velocity_variable.speed_bins.copy(),
                             {'units': velocity_variable.units})
        _, self.bins, _ = units.convert_units(bins, speed_units)

        default_norm = plt.cm.colors.BoundaryNorm(self.bins, self.bins.size)
        kwdargs['norm'] = kwdargs.get('norm', default_norm)

        self.variable = velocity_variable
        self.ax, self.fig = utils.axis_figure(ax, fig)

        # add the color bar
        self.cax = self.fig.add_axes([0.92, 0.05, 0.03, 0.9])
        cbar = mpl.colorbar.ColorbarBase(self.cax,
                                         cmap=kwdargs['cmap'],
                                         norm=kwdargs['norm'])
        cbar.set_label("Knots")

        fcst = self.normalize(fcst)
        # use the longitude grid to define the radius of the circles
        sorted_lats = np.sort(fcst['latitude'].values)
        resol = np.median(angles.angle_diff(sorted_lats[1:],
                                            sorted_lats[:-1]))

        # create the map
        self.m = utils.get_basemap(fcst, ax=self.ax,
                                   lon_pad=0.75 * resol,
                                   lat_pad = 0.75 * resol)
        def create_circle(one_loc):
            # determine the circle center
            x, y = self.m(one_loc['longitude'].values,
                          one_loc['latitude'].values)
            speeds = one_lonlat[self.variable.speed_name].values
            dirs = one_lonlat[self.variable.direction_name].values
            orientation = self.variable.direction_orientation
            return DirectionCircle(x, y,
                                   speeds=np.atleast_1d(speeds),
                                   directions=np.atleast_1d(dirs),
                                   orientation=orientation,
                                   radius=0.4 * resol,
                                   ax=self.ax, **kwdargs)

        self.circles = [[create_circle(one_lonlat)
                         for lo, one_lonlat in one_lat.groupby('longitude')]
                        for la, one_lat in fcst.groupby('latitude')]
        self.set_title(fcst)
示例#5
0
文件: spot.py 项目: akleeman/slocum
    def __init__(self, fcsts, velocity_variable, speed_units='knot',
                 max_speed=None, ax=None, fig=None):
        self.variable = velocity_variable
        self.speed_units = speed_units
        self.ax, self.fig = utils.axis_figure(ax, fig)
        self.ax.set_ylabel("Speed (%s)" % speed_units)

        # convert the bins to knots
        bins = xray.Variable('bins',
                             velocity_variable.speed_bins.copy(),
                             {'units': velocity_variable.units})
        _, self.bins, _ = units.convert_units(bins, speed_units)
        # convert the data to knots and radians
        fcsts = self.normalize(fcsts)

        # determine the upper bound on speed so we can place
        # the direction circles.
        all_speeds =fcsts[self.variable.speed_name].values
        max_speed = max_speed or np.max(all_speeds)
        max_bin = np.sum(self.bins <= max_speed) + 2
        self.max_bin = np.minimum(max_bin, self.bins.size)
        self.plot(fcsts)
示例#6
0
文件: enslib.py 项目: ms8r/slocum
def plot_gridded_ensemble(gfsx, contour_units=None, max_level=None,
        barb_units='knot', cols=2, save_path=None, save_fmt='svg'):
    """
    Plots the average windspeed deviation of ensemble forecast members over
    the published GSF forecast for each grid point and forecast time.
    The result is (for each forecast time) a color filled contour plot
    indicating the ensemble deviation superimposed over the usual wind barbs
    with the published GFS forecast vectors.

    Parameters:
    -----------
    fcst_gfsx: xray.Dataset
        Dataset with the GFS forecast for windspeed (uwnd and vwnd) and
        ensemble forecast deviation (other forecast variables will be ignored
        if present).
    contour_units: str
        The units in which to plot the ensemble spread indicator (heatmap). If
        specified, the data sets current unit must be convertible into the
        desired unit by slocum.lib.units. If not specified the exsiting units in
        the data set will be used.
    max_level: float
        Heatmap/contour plot maximum level. Minimum level is assumed to be 0.
        Values greater tha max_level will be mapped onto the max_level color.
        If not specified, the maximum value found in the data set will be used
        as the upper end of the color bar.
    barb_units: str
        Units in which to plot the GFS wind speed/direction forecast data (wind
        bars). If specified, the data sets current unit must be convertible
        into the desired unit by slocum.lib.units.
    cols: int
        Number of columns for subplot layout.
    save_path: str
        If specified the plot will be saved into this directory with file
        name ``ens_<bounding box>_<t0>.svg`` where *bounding box* is
        specified as *ll_lat, ll_lon - ur_lat, ur_lon*.  If not specified or
        ``None`` the plot will be displayed interactively.
    save_fmt: str
        Format under which to save the image (only relevant if *save_path* is
        specified). Can be any image file extension that plt.savefig() will
        recognize as a valid format.
    """
    # adjust units as requested:
    for v in (conv.UWND, conv.VWND):
        units.convert_units(gfsx[v], barb_units)
    if contour_units:
        units.convert_units(gfsx[conv.ENS_SPREAD_WS], contour_units)
    if not max_level:
        max_level = gfsx[conv.ENS_SPREAD_WS].max()

    if isinstance(gfsx, np.datetime64): # True is gfsx has not been packed
        f_times = gfsx[conv.TIME].values
    else:                               # time variable has int offsets
        f_times = xray.conventions.decode_cf_datetime(
                gfsx['time'], gfsx['time'].attrs['units'])

    lats = gfsx[conv.LAT].values
    lons = gfsx[conv.LON].values

    # Basemap.transform_vector requires lats and lons each to be in ascending
    # order:
    lat_inds = range(len(lats))
    lon_inds = range(len(lons))
    if NautAngle(lats[0]).is_north_of(NautAngle(lats[-1])):
        lat_inds.reverse()
        lats = lats[lat_inds]
    if NautAngle(lons[0]).is_east_of(NautAngle(lons[-1])):
        lon_inds.reverse()
        lons = lons[lon_inds]

    # determine layout:
    fig_width_inches = 10
    plot_aspect_ratio = (abs(lons[-1] - lons[0]) /
                         float(abs(lats[-1] - lats[0])))
    rows = int(np.ceil(gfsx.dimensions[conv.TIME] / float(cols)))
    fig_height_inches = (fig_width_inches / (float(cols) * plot_aspect_ratio)
                         * rows + 2)
    fig = plt.figure(figsize=(fig_width_inches, fig_height_inches))
    fig.suptitle("GFS wind forecast in %s and "
                 "ensemble wind speed deviation" % barb_units,
                 fontsize=12)
    grid = AxesGrid(fig, [0.01, 0.01, 0.95, 0.93],
                    nrows_ncols=(rows, cols),
                    axes_pad=0.8,
                    cbar_mode='single',
                    cbar_pad=0.0,
                    cbar_size=0.2,
                    cbar_location='bottom',
                    share_all=True,)

    # size for lat/lon labels, timestamp:
    label_fontsize = 'medium' if cols <= 2 else 'small'
    # format string for colorbar labels:
    decimals = max(0, int(2 - np.floor(np.log10(max_level))))
    cb_label_fmt = '%.' + '%d' % decimals + 'f'

    # heatmap color scaling and levels
    spread_levels = np.linspace(0., max_level, 50)

    m = Basemap(projection='merc', llcrnrlon=lons[0], llcrnrlat=lats[0],
            urcrnrlon=lons[-1], urcrnrlat=lats[-1], resolution='l')

    for t_step, t in enumerate(f_times):

        ax = grid[t_step]
        m.drawcoastlines(ax=ax)
        m.drawparallels(lats,labels=[1,0,0,0], ax=ax,
                fontsize=label_fontsize)
        m.drawmeridians(lons,labels=[0,0,0,1], ax=ax,
                fontsize=label_fontsize, rotation='vertical')

        # ensemble spread heatmap:
        x, y = m(*np.meshgrid(lons, lats))
        data = gfsx[conv.ENS_SPREAD_WS]
        data = data.indexed(**{conv.TIME: t_step})
        data = data.indexed(**{conv.LAT: lat_inds})
        data = data.indexed(**{conv.LON: lon_inds}).values
        cs = m.contourf(x, y, data, spread_levels, ax=ax, extend='max',
                cmap=cm.jet)

        # wind barbs:
        u = gfsx[conv.UWND].indexed(**{conv.TIME: t_step})
        u = u.indexed(**{conv.LAT: lat_inds})
        u = u.indexed(**{conv.LON: lon_inds}).values
        v = gfsx[conv.VWND].indexed(**{conv.TIME: t_step})
        v = v.indexed(**{conv.LAT: lat_inds})
        v = v.indexed(**{conv.LON: lon_inds}).values
        # transform from spherical to map projection coordinates (rotation
        # and interpolation).
        nxv = len(lons)
        nyv = len(lats)
        barb_length = 8 - cols
        barb_width = 1.2 - (cols / 10.)
        udat, vdat, xv, yv = m.transform_vector(
                u, v, lons, lats, nxv, nyv, returnxy=True)
        # plot barbs.
        m.barbs(xv, yv, udat, vdat, ax=ax, length=barb_length, barbcolor='w',
                flagcolor='r', linewidth=barb_width)

        ax.set_title(t.astype('M8[h]').item().strftime('%Y-%m-%dT%H:%MZ'),
                fontsize=label_fontsize)

    cbar = fig.colorbar(cs, cax=grid.cbar_axes[0], orientation='horizontal',
            format=cb_label_fmt)
    attr = gfsx[conv.ENS_SPREAD_WS].attrs
    cb_label = attr.get('long_name',
            'Average (normalized) wind speed delta (ens - gfs)')
    s = ["%s = %s" % (k, attr[k]) for k in attr if k != 'long_name']
    if s:
        cb_label = "%s (%s)" % (cb_label, ', '.join(s))
    cbar.set_label(cb_label)

    if save_path:
        t0_str = f_times[0].astype('M8[h]').item().strftime('%Y%m%dT%H%MZ')
        file_name = "ens_%s%s-%s%s_%s.%s" % (
                NautAngle(lats[0]).named_str(conv.LAT),
                NautAngle(lons[0]).named_str(conv.LON),
                NautAngle(lats[-1]).named_str(conv.LAT),
                NautAngle(lons[-1]).named_str(conv.LON),
                t0_str, save_fmt)
        plt.savefig(os.path.join(save_path, file_name), bbox_inches='tight')
    else:
        plt.show()

    plt.close()