Example #1
0
    def __init__(self, raster, geo_grid: GeoGrid = None, no_data_value=None, crs=None):
        """ RasterMap constructor

        :param raster: raster file or numpy array
        :param geo_grid: GeoGrid instance
        :param no_data_value: data to be regarded as "no_data"
        :param crs: projection used for the raster

        :Example:
        >>>
        """
        check_type(raster, (str, np.ndarray))

        if type(raster) == np.ndarray:
            raster_file = None
            try:
                test_fit = geo_grid.data_fits(raster)
                crs = pyproj.CRS(crs)
                # crs = proj4_from(crs)
                if not test_fit:
                    raise RasterMapError("Input geo grid does not fit raster")
            except AttributeError:
                raise RasterMapError("Geo grid argument has not been set")
            except (ValueError, TypeError):
                raise RasterMapError("Invalid projection: crs='{}'".format(crs))
        else:
            raster_file = raster
            try:
                geo_grid = GeoGrid.from_raster_file(raster)
                crs = crs_from_raster(raster)
                raster = raster_to_array(raster)
            except RuntimeError:
                raise RasterMapError("Invalid/unknown file '%s'" % raster_file)

        # Set attributes
        self._raster_file = raster_file
        self._geo_grid = geo_grid
        self._raster_array = np.array(raster, dtype='float64')  # Ensure compatibility with NaNs
        self._crs = crs
        self._res = self._geo_grid.res
        self._x_origin = self._geo_grid.geo_transform[0]
        self._y_origin = self._geo_grid.geo_transform[3]
        self._x_size = self._geo_grid.num_x
        self._y_size = self._geo_grid.num_y
        self._shape = self._raster_array.shape
        self._no_data_value = no_data_value

        if no_data_value is not None:
            self._raster_array[self._raster_array == no_data_value] = np.nan  # Use attribute (raster_array) rather than
            # instance (self == ...) to avoid 'recursion' error with decorator above

        # Available filters
        self._filters = {"majority_filter": self._majority_filter, "sieve": self._gdal_sieve}
Example #2
0
 def _apply_operator(self, other, operator_function, operator_str):
     if isinstance(other, RasterMap):
         if self.geo_grid == other.geo_grid:
             return self.raster_array.__getattribute__(operator_function)(other.raster_array)
         else:
             raise RasterMapError("Raster maps are not defined on the same geo grid")
     else:
         try:
             return self.raster_array.__getattribute__(operator_function)(other)
         except TypeError:
             raise RasterMapError("Unsupported operand type(s) for {}: '{}' and '{}'".format(operator_str,
                                                                                             type(self).__name__,
                                                                                             type(other).__name__))
         except ValueError:
             raise RasterMapError("No match for operand {} between '{}' and '{}'".format(operator_str,
                                                                                         type(self).__name__,
                                                                                         type(other).__name__))
         except Exception as e:
             raise RuntimeError("Unexpected error when applying {} between '{}' and '{}': {}"
                                .format(operator_str, type(self).__name__, type(other).__name__, e))
Example #3
0
    def __setitem__(self, key, value):

        if type(key) == type(self):
            self.raster_array.__setitem__(key.raster_array, value)
        else:
            try:
                self.raster_array.__setitem__(key, value)
            except IndexError:
                raise RasterMapError("Invalid indexing")
            except Exception as e:
                raise RuntimeError("Unknown error while setting data in raster map: {}".format(e))

        return self
Example #4
0
    def __getitem__(self, key):

        if key.__class__ == type(self):
            key = key.raster_array

        if key.__class__ == slice:
            key = (key, key)

        if key.__class__ == tuple:
            if key[0].__class__ == int and key[1].__class__ == int:
                return self.raster_array.__getitem__(key)
            else:
                try:
                    return self.__class__(self.raster_array.__getitem__(key), self.geo_grid.__getitem__(key),
                                          no_data_value=self.no_data_value, crs=self.crs)
                except IndexError:
                    raise RasterMapError("Invalid indexing")
                except Exception as e:
                    raise RuntimeError("Unknown error while getting data in raster map: {}".format(e))
        elif key.__class__ == np.ndarray:
            return self.raster_array.__getitem__(key)
        else:
            raise RasterMapError("Invalid indexing")
Example #5
0
    def to_crs(self, crs):
        """ Reproject raster onto new CRS

        :param crs:
        :return:
        """
        try:
            if self.crs != crs:
                srs = srs_from(crs)
                return self._gdal_warp(srs)
            else:
                return self.copy()
        except ValueError:
            raise RasterMapError("Invalid CRS '%s'" % crs)
Example #6
0
 def _apply_comparison(self, other, operator_function, operator_str):
     valid_values = np.full(self.raster_array.shape, False)
     if isinstance(other, RasterMap):
         other = other.raster_array
     try:
         valid_values[(~np.isnan(self.raster_array)) & (~np.isnan(other))] = True
         valid_values[valid_values] = self.raster_array[valid_values].__getattribute__(operator_function)(
             other[valid_values])
         return valid_values
     except (TypeError, IndexError):
         valid_values[~np.isnan(self.raster_array)] = True
         valid_values[valid_values] = self.raster_array[valid_values].__getattribute__(operator_function)(other)
         return valid_values
     except Exception as e:
         raise RasterMapError("Comparison for '{}' has failed ({})".format(operator_str, e))
Example #7
0
    def to_file(self, raster_file, data_type=None):
        """ Save raster to file

        :param raster_file:
        :param data_type: data type
        :return:
        """
        if data_type is None:
            dtype = self._numpy_to_gdal_type[self.data_type]
        else:
            try:
                dtype = self._numpy_to_gdal_type[data_type]
            except KeyError:
                raise RasterMapError("Invalid data type '%s'" % data_type)

        out = array_to_raster(raster_file, self.raster_array_without_nans,
                              self.geo_grid, self.crs, datatype=dtype,
                              no_data_value=self.no_data_value)

        return out
Example #8
0
    def get_raster_at(self, layer=None, ll_point=None, ur_point=None):
        """ Extract sub-raster in current raster map

        Extract new raster from current raster map
        by giving either a geo lines_ or a new geo-square
        defined by lower-left point (ll_point) and upper
        right point (ur_point) such as for geo grids.
        :param layer: GeoLayer instance
        :param ll_point: tuple of 2 values (lat, lon)
        :param ur_point: tuple of 2 values (lat, lon)
        :return: RasterMap
        """
        if layer is not None:
            check_proj(layer.crs, self.crs)
            ll_point = (layer.bounds[1], layer.bounds[0])  # Warning: (lat, lon) in that order !
            ur_point = (layer.bounds[3], layer.bounds[2])

        try:
            ll_point_r, ll_point_c = self._geo_grid.latlon_to_2d_index(ll_point[0], ll_point[1])
            ur_point_r, ur_point_c = self._geo_grid.latlon_to_2d_index(ur_point[0], ur_point[1])
            return self.raster_array[ur_point_r:ll_point_r + 1, ll_point_c:ur_point_c + 1], \
                self.geo_grid[ur_point_r:ll_point_r + 1, ll_point_c:ur_point_c + 1]
        except GeoGridError:
            raise RasterMapError("Lower left or/and upper right points have not been rightly defined")
Example #9
0
    def disaggregate(self, factor: int = 1, method: str = 'nearest', no_limit=False):
        """ Disaggregate raster cells

        :param factor: scale factor for disaggregation (number of cells)
        :param method: 'linear' or 'nearest' (default = 'nearest')
        :param no_limit: no limit for disaggregation (default=False)
        :return:
        """
        from scipy.interpolate import RegularGridInterpolator

        upper_limit = np.inf if no_limit else 10**8 / (self.geo_grid.num_x * self.geo_grid.num_y)
        if 1 < factor <= upper_limit:
            new_geo_grid = self.geo_grid.to_res(self.res/factor)
            try:
                interpolator = RegularGridInterpolator((self.geo_grid.lats, self.geo_grid.lons),
                                                       self.raster_array[::-1, :], bounds_error=False,
                                                       method=method)
            except ValueError:
                raise RasterMapError("Method should be 'linear' or 'nearest' but is {}".format(method))

            return interpolator((new_geo_grid.latitude, new_geo_grid.longitude)), new_geo_grid
        else:
            warnings.warn("Invalid factor, factor = 1, or exceeded limit (set no_limit=True). Return copy of object")
            return self.copy()