Example #1
0
    def contains(self, lon, lat):
        """ Return a boolean array of same shape as lon and lat with points contained in the patch
        """
        lon = np.asarray(lon)
        lat = np.asarray(lat)
        mlon, mlat = self.coords
        assert lon.shape == lat.shape, "lon, lat must have the same shape"
        #lon = rectify_longitude(lon, lon0=self.lon0, sort=False)

        # first fix lon0 to match new data
        lon0 = get_lon0(*lon.flatten())
        if lon0 != self.lon0:
            self = copy(self)
            mlon, self.mask = rectify_longitude_data(mlon, self.mask, lon0)

        if not (np.all(lon == mlon) and np.all(lat == mlat)):
            self = copy(self)

            # interpolate the mask onto the input grid
            maskf = interp(np.asarray(self.mask, dtype=float), mlon, mlat, lon,
                           lat)
            mask = maskf >= 0.5

        else:
            mask = self.mask

        return mask
Example #2
0
    def contains(self, lon, lat):
        """ Return a boolean array of same shape as lon and lat with points contained in the patch
        """
        lon = np.asarray(lon)
        lat = np.asarray(lat)
        mlon, mlat = self.coords
        assert lon.shape == lat.shape, "lon, lat must have the same shape"
        #lon = rectify_longitude(lon, lon0=self.lon0, sort=False)

        # first fix lon0 to match new data
        lon0 = get_lon0(*lon.flatten())
        if lon0 != self.lon0:
            self = copy(self)
            mlon, self.mask = rectify_longitude_data(mlon, self.mask, lon0)

        if not (np.all(lon == mlon) and np.all(lat == mlat)):
            self = copy(self)

            # interpolate the mask onto the input grid
            maskf = interp(np.asarray(self.mask, dtype=float), mlon, mlat, lon, lat)
            mask = maskf >= 0.5

        else:
            mask = self.mask

        return mask
Example #3
0
def interp2(lon, lat, data, lon2, lat2, order=1):
    """ Equivalent to matlab interp2

    order:
    - 0 : nearest neighbout
    - 1 : linear (default)
    """
    from dimarray.compat.basemap import interp
    if np.ndim(lon2) == 1:
        lon2, lat2 = np.meshgrid(lon2, lat2)
    return  interp(data, lon, lat, lon2, lat2, order=order)
Example #4
0
def interp2(lon, lat, data, lon2, lat2, order=1):
    """ Equivalent to matlab interp2

    order:
    - 0 : nearest neighbout
    - 1 : linear (default)
    """
    from dimarray.compat.basemap import interp
    if np.ndim(lon2) == 1:
        lon2, lat2 = np.meshgrid(lon2, lat2)
    return interp(data, lon, lat, lon2, lat2, order=order)
Example #5
0
    def interpolate(self, lon, lat):
        """ interpolate the mask

        lon, lat: 1-D arrays to be passed to meshgrid
        """
        assert lon.ndim == 1 and lat.ndim == 1, "must be 1-D coordinates compatible with meshgrid"
        # first fix lon0 to match new data
        lon0 = get_lon0(*lon.flatten())
        mlon, mlat = self.coords
        mlon, mask = rectify_longitude_data(mlon, self.mask, lon0)

        # make input coords is 2-D
        #if lon.ndim == 1 and meshgrid:
        lon2, lat2 = np.meshgrid(lon, lat)

        maskf = interp(np.asarray(self.mask, dtype=float), mlon, mlat, lon2, lat2)
        mask = maskf >= 0.5
        return Mask(lon, lat, mask, lon0)
Example #6
0
    def interpolate(self, lon, lat):
        """ interpolate the mask

        lon, lat: 1-D arrays to be passed to meshgrid
        """
        assert lon.ndim == 1 and lat.ndim == 1, "must be 1-D coordinates compatible with meshgrid"
        # first fix lon0 to match new data
        lon0 = get_lon0(*lon.flatten())
        mlon, mlat = self.coords
        mlon, mask = rectify_longitude_data(mlon, self.mask, lon0)

        # make input coords is 2-D
        #if lon.ndim == 1 and meshgrid:
        lon2, lat2 = np.meshgrid(lon, lat)

        maskf = interp(np.asarray(self.mask, dtype=float), mlon, mlat, lon2,
                       lat2)
        mask = maskf >= 0.5
        return Mask(lon, lat, mask, lon0)
Example #7
0
def interp2d(dim_array, newaxes, dims=(-2, -1), order=1, clip=False):
    """ bilinear interpolation

    Parameters
    ----------
    dim_array : DimArray instance
    newaxes : sequence of two array-like, or dict.
        axes on which to interpolate
    dims : sequence of two axis names or integer rank, optional
        Indicate dimensions which match `newaxes`.
        By default (-2, -1) (last two dimensions).
    order : int, optional
        order of the interpolation (default 1 for linear)
    clip : bool, optional
        if True, values in newaxes outside the range are clipped to closest
        values

    Returns
    -------
    dim_array_int : DimArray instance
        interpolated array

    Examples
    --------

    >>> from dimarray import DimArray, interp2d
    >>> x = np.array([0, 1, 2])
    >>> y = np.array([0, 10])
    >>> a = DimArray([[0,0,1],[1,0.,0.]], [('y',y),('x',x)])
    >>> a
    dimarray: 6 non-null elements (0 null)
    0 / y (2): 0 to 10
    1 / x (3): 0 to 2
    array([[ 0.,  0.,  1.],
           [ 1.,  0.,  0.]])
    >>> newx = [0.5, 1.5]
    >>> newy = np.linspace(0,10,5)
    >>> ai = interp2d(a, [newy, newx])
    >>> ai
    dimarray: 10 non-null elements (0 null)
    0 / y (5): 0.0 to 10.0
    1 / x (2): 0.5 to 1.5
    array([[ 0.   ,  0.5  ],
           [ 0.125,  0.375],
           [ 0.25 ,  0.25 ],
           [ 0.375,  0.125],
           [ 0.5  ,  0.   ]])

    Use dims keyword argument if new axes order does not match array dimensions
    >>> (ai == interp2d(a, [newx, newy], dims=('x','y'))).all()
    True

    >>> newx = [-1, 1]
    >>> newy = [-5, 0, 10]
    >>> interp2d(a, [newy, newx])
    dimarray: 2 non-null elements (4 null)
    0 / y (3): -5 to 10
    1 / x (2): -1 to 1
    array([[ nan,  nan],
           [ nan,   0.],
           [ nan,   0.]])
    >>> interp2d(a, [newy, newx], clip=True)
    dimarray: 6 non-null elements (0 null)
    0 / y (3): -5 to 10
    1 / x (2): -1 to 1
    array([[ 0.,  0.],
           [ 0.,  0.],
           [ 1.,  0.]])
    """
    # provided as a dictionary
    if isinstance(newaxes, dict):
        dims = newaxes.keys()
        newaxes = newaxes.values()

    if not isinstance(newaxes, list) or isinstance(newaxes, tuple):
        raise TypeError("newaxes must be a sequence of axes to interpolate on")

    if len(newaxes) != 2:
        raise ValueError("must provide two axis values to interpolate on")

    if len(dims) != 2: 
        raise ValueError("must provide two axis names to interpolate on")

    x0 = dim_array.axes[dims[0]]
    y0 = dim_array.axes[dims[1]]

    # new axes
    xi, yi = newaxes
    xi2, yi2 = np.meshgrid(xi, yi) # requires 2-D grid
    xi = Axis(xi, x0.name) # convert to Axis
    yi = Axis(yi, y0.name)


    # transpose the array to shape .., y0, x0 (cartesian convention needed for interp)
    dims_orig = dim_array.dims
    dims_new = [d for d in dim_array.dims if d not in [x0.name, y0.name]] + [y0.name, x0.name]
    dim_array = dim_array.transpose(dims_new) 

    if dim_array.ndim == 2:
        newvalues = interp(dim_array.values, x0.values, y0.values, xi2, yi2, masked=not clip)
        dim_array_int = dim_array._constructor(newvalues, [yi, xi])

    else:
        # first reshape to 3-D, flattening everything except horizontal_coordinates coordinates
        # TODO: optimize by computing and re-using weights?
        dim_array = dim_array.group((x0.name, y0.name), reverse=True, insert=0)  
        newvalues = []
        for k, suba in dim_array.iter(axis=0): # iterate over the first dimension
            newval = interp(suba.values, x0.values, y0.values, xi2, yi2, masked=not clip)
            newvalues.append(newval)

        # stack the arrays together
        newvalues = np.array(newvalues)
        grouped_dim_array = dim_array._constructor(newvalues, [dim_array.axes[0], yi, xi])
        dim_array_int = grouped_dim_array.ungroup(axis=0)

    # reshape back
    # ...replace old axis names by new ones of the projection
    dims_orig = list(dims_orig)
    # ...transpose
    dim_array_int = dim_array_int.transpose(dims_orig)

    # add metadata
    dim_array_int._metadata(dim_array._metadata())

    return dim_array_int
Example #8
0
def transform_vectors(u, v, to_crs, from_crs=None, \
        xt=None, yt=None, masked=np.nan):
    """ Transform vector field array into a new coordinate system and \
            interpolate values onto a new regular grid

    Assume the vector field is represented by an array of shape (2, Ny, Nx)

    Parameters
    ----------
    u, v : GeoArray or other DimArray instances
        x- and y- vector components
    to_crs : str or dict or cartopy.crs.CRS instance
        grid mapping onto which the transformation should be done
        str : PROJ.4 str or cartopy.crs.CRS class name
        dict : CF parameters
    from_crs : idem, optional
        original grid mapping. Can be omitted if the grid_mapping attribute
        already contains the appropriate information, or if the horizontal
        coordinates are longitude and latitude.
    xt, yt : array-like (1-D), optional
        new coordinates to interpolate the array on
        will be deduced as min and max of new coordinates if not provided
    masked : bool or number, optional
        If False, interpolated values outside the range of input grid
        will be clipped to values on boundary of input grid 
        If True, points outside the range of input grid
        are masked (set to NaN)
        If masked is set to a number, then
        points outside the range of xin and yin will be
        set to that number.
        Default is nan.

    Returns
    -------
    transformed : GeoArray
        new 3-D GeoArray transformed and interpolated
    """ 
    if not isinstance(u, DimArray) or not isinstance(v, DimArray):
        raise TypeError("u and v must be DimArray instances")
    if not isinstance(u, GeoArray): 
        u = GeoArray(u) 
    if not isinstance(v, GeoArray): 
        v = GeoArray(v) 

    # consistency check between u and v
    assert u.axes == v.axes , "u and v must have the same axes"
    if from_crs is None and hasattr(u, 'grid_mapping'):
        assert hasattr(v, 'grid_mapping') and u.grid_mapping == v.grid_mapping, 'u and v must have the same grid mapping'

    # get grid mapping instances
    from_crs = _get_crs(from_crs, u)
    to_crs = _get_crs(to_crs)

    # find horizontal coordinates
    x0, y0 = _check_horizontal_coordinates(u)

    # Transform coordinates and prepare regular grid for interpolation
    x0_interp, y0_interp, xt, yt = _inverse_transform_coords(from_crs, to_crs, xt, yt, x0, y0)

    # Transform vector components
    x0_2d, y0_2d = np.meshgrid(x0, y0)

    if masked is True:
        masked = np.nan # use NaN instead of MaskedArray

    _constructor = u._constructor 
    if u.ndim == 2:
        # First transform vector components onto the new coordinate system
        _ut, _vt = to_crs.transform_vectors(from_crs, x0_2d, y0_2d, u.values, v.values) 
        # Then interpolate onto regular grid
        _ui = interp(_ut, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
        ut = _constructor(_ui, [yt, xt])
        _vi = interp(_vt, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
        vt = _constructor(_vi, [yt, xt])

    else:
        # first reshape to 3-D components, flattening everything except horizontal coordinates
        # TODO: optimize by computing and re-using weights?
        obj = stack([u, v], axis='vector_components', keys=['u','v'])
        obj = obj.group(('vector_components', x0.name, y0.name), reverse=True, insert=0) # 
        newvalues = []
        for k, suba in obj.iter(axis=0): # iterate over the first dimension
            # First transform vector components onto the new coordinate system
            _ut, _vt = to_crs.transform_vectors(from_crs, x0_2d, y0_2d, suba.values[0], suba.values[1]) 
            # Then interpolate onto regular grid
            _ui = interp(_ut, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
            _vi = interp(_vt, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
            newvalues.append(np.array([_ui, _vi]))

        # stack the arrays together
        newvalues = np.array(newvalues) # 4-D : grouped, vector_components, y, x
        grouped_obj = _constructor(newvalues, [obj.axes[0], obj.axes[1], yt, xt])
        ut, vt = grouped_obj.ungroup(axis=0).swapaxes('vector_components',0)

    # add metadata
    ut._metadata(u._metadata())
    vt._metadata(v._metadata())

    _add_grid_mapping_metadata(ut, to_crs)
    _add_grid_mapping_metadata(vt, to_crs)

    return ut, vt
Example #9
0
def transform(geo_array, to_crs, from_crs=None, \
        xt=None, yt=None, masked=np.nan):
    """ Transform scalar field array into a new coordinate system and \
            interpolate values onto a new regular grid

    Parameters
    ----------
    geo_array : GeoArray or other DimArray instance
    to_crs : str or dict or cartopy.crs.CRS instance
        grid mapping onto which the transformation should be done
        str : PROJ.4 str or cartopy.crs.CRS class name
        dict : CF parameters
    from_crs : idem, optional
        original grid mapping. Can be omitted if the grid_mapping attribute
        already contains the appropriate information, or if the horizontal
        coordinates are longitude and latitude.
    xt, yt : array-like (1-D), optional
        new coordinates to interpolate the array on
        will be deduced as min and max of new coordinates if not provided
    masked : bool or number, optional
        If False, interpolated values outside the range of input grid
        will be clipped to values on boundary of input grid 
        If True, points outside the range of input grid
        are set to NaN
        If masked is set to a number, then
        points outside the range of xin and yin will be
        set to that number.
        Default is nan.

    Returns
    -------
    transformed : GeoArray
        new GeoArray transformed
        Attempt is made to document the projection with CF-conform metadata

    Examples
    --------
    """ 
    # local import since it's quite heavy
    if not isinstance(geo_array, DimArray):
        raise TypeError("geo_array must be a DimArray instance")
    if not isinstance(geo_array, GeoArray):
        geo_array = GeoArray(geo_array) 

    # find horizontal coordinates
    x0, y0 = _check_horizontal_coordinates(geo_array)

    # transpose the array to shape .., y0, x0 (cartesian convention needed for meshgrid)
    dims_orig = geo_array.dims
    dims_new = [d for d in geo_array.dims if d not in [x0.name, y0.name]] + [y0.name, x0.name]
    geo_array = geo_array.transpose(dims_new) 

    #assert geo_array.dims.index(x0.name) > geo_array.axes[

    # get cartopy.crs.CRS instances
    from_crs = _get_crs(from_crs, geo_array)
    to_crs = _get_crs(to_crs)

    # Transform coordinates and prepare regular grid for interpolation
    x0_interp, y0_interp, xt, yt = _inverse_transform_coords(from_crs, to_crs, xt, yt, x0, y0)

    if masked is True:
        masked = np.nan # use NaN instead of MaskedArray

    if geo_array.ndim == 2:
        #newvalues = interp(geo_array.values, xt_2d, yt_2d, xt_2dr, yt_2dr)
        newvalues = interp(geo_array.values, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
        transformed = geo_array._constructor(newvalues, [yt, xt])

    else:
        # first reshape to 3-D, flattening everything except horizontal_coordinates coordinates
        # TODO: optimize by computing and re-using weights?
        obj = geo_array.group((x0.name, y0.name), reverse=True, insert=0)  
        newvalues = []
        for k, suba in obj.iter(axis=0): # iterate over the first dimension
            #newval = interp(suba.values, xt_2d, yt_2d, xt_2dr, yt_2dr)
            newval = interp(suba.values, x0.values, y0.values, x0_interp, y0_interp, masked=masked)
            newvalues.append(newval)

        # stack the arrays together
        newvalues = np.array(newvalues)
        grouped_obj = geo_array._constructor(newvalues, [obj.axes[0], yt, xt])
        transformed = grouped_obj.ungroup(axis=0)

    # reshape back
    # ...replace old axis names by new ones of the projection
    dims_orig = list(dims_orig)
    dims_orig[dims_orig.index(x0.name)] = xt.name
    dims_orig[dims_orig.index(y0.name)] = yt.name
    # ...transpose
    transformed = transformed.transpose(dims_orig)

    # add metadata
    transformed._metadata(geo_array._metadata())

    _add_grid_mapping_metadata(transformed, to_crs)

    return transformed
Example #10
0
 def interp2d(obj, order=1):
     """ 2-D interpolation function appled recursively on the object
     """
     x0, y0 = obj.axes[x.name].values, obj.axes[y.name].values
     res = interp(obj.values, x0, y0, x1, y1, order=order)
     return obj._constructor(res, newaxes, **obj._metadata)
Example #11
0
 def interp2d(obj, order=1):
     """ 2-D interpolation function appled recursively on the object
     """
     x0, y0 = obj.axes[x.name].values, obj.axes[y.name].values
     res = interp(obj.values, x0, y0, x1, y1, order=order)
     return obj._constructor(res, newaxes, **obj._metadata)