Esempio n. 1
0
class TestVector:
    glacier_outlines = gu.Vector(GLACIER_OUTLINES_URL)

    def test_init(self):

        vector = gu.Vector(GLACIER_OUTLINES_URL)

        assert isinstance(vector, gu.Vector)

    def test_copy(self):

        vector2 = self.glacier_outlines.copy()

        assert vector2 is not self.glacier_outlines

        vector2.ds = vector2.ds.query("NAME == 'Ayerbreen'")

        assert vector2.ds.shape[0] < self.glacier_outlines.ds.shape[0]

    def test_query(self):

        vector2 = self.glacier_outlines.query("NAME == 'Ayerbreen'")

        assert vector2 is not self.glacier_outlines

        assert vector2.ds.shape[0] < self.glacier_outlines.ds.shape[0]
Esempio n. 2
0
    def test_merge_bounds(self) -> None:
        """
        Check that merge_bounds and bounds2poly work as expected for all kinds of bounds objects.
        """
        img1 = gu.Raster(gu.datasets.get_path("landsat_B4"))
        img2 = gu.Raster(gu.datasets.get_path("landsat_B4_crop"))

        # Check union (default) - with Raster objects
        out_bounds = pt.merge_bounds((img1, img2))
        assert out_bounds[0] == min(img1.bounds.left, img2.bounds.left)
        assert out_bounds[1] == min(img1.bounds.bottom, img2.bounds.bottom)
        assert out_bounds[2] == max(img1.bounds.right, img2.bounds.right)
        assert out_bounds[3] == max(img1.bounds.top, img2.bounds.top)

        # Check intersection - with Raster objects
        out_bounds = pt.merge_bounds((img1, img2),
                                     merging_algorithm="intersection")
        assert out_bounds[0] == max(img1.bounds.left, img2.bounds.left)
        assert out_bounds[1] == max(img1.bounds.bottom, img2.bounds.bottom)
        assert out_bounds[2] == min(img1.bounds.right, img2.bounds.right)
        assert out_bounds[3] == min(img1.bounds.top, img2.bounds.top)

        # Check that the results is the same with rio.BoundingBoxes
        out_bounds2 = pt.merge_bounds((img1.bounds, img2.bounds),
                                      merging_algorithm="intersection")
        assert out_bounds2 == out_bounds

        # Check that the results is the same with a list
        out_bounds2 = pt.merge_bounds((list(img1.bounds), list(img2.bounds)),
                                      merging_algorithm="intersection")
        assert out_bounds2 == out_bounds

        # Check with gpd.GeoDataFrame
        outlines = gu.Vector(gu.datasets.get_path("glacier_outlines"))
        outlines = gu.Vector(outlines.ds.to_crs(
            img1.crs))  # reproject to img1's CRS
        out_bounds = pt.merge_bounds((img1, outlines.ds))

        assert out_bounds[0] == min(img1.bounds.left,
                                    outlines.ds.total_bounds[0])
        assert out_bounds[1] == min(img1.bounds.bottom,
                                    outlines.ds.total_bounds[1])
        assert out_bounds[2] == max(img1.bounds.right,
                                    outlines.ds.total_bounds[2])
        assert out_bounds[3] == max(img1.bounds.top,
                                    outlines.ds.total_bounds[3])
Esempio n. 3
0
    def test_crop(self) -> None:

        r = gr.Raster(datasets.get_path("landsat_B4"))
        r2 = gr.Raster(datasets.get_path("landsat_B4_crop"))

        # Read a vector and extract only the largest outline within the extent of r
        outlines = gu.Vector(datasets.get_path("glacier_outlines"))
        outlines.ds = outlines.ds.to_crs(r.crs)
        outlines.crop2raster(r)
        outlines = outlines.query(
            f"index == {np.argmax(outlines.ds.geometry.area)}")

        # Crop the raster to the outline and validate that it got smaller
        r_outline_cropped = r.crop(outlines, inplace=False)
        assert r.data.size > r_outline_cropped.data.size  # type: ignore

        b = r.bounds
        b2 = r2.bounds

        b_minmax = (max(b[0], b2[0]), max(b[1],
                                          b2[1]), min(b[2],
                                                      b2[2]), min(b[3], b2[3]))

        r_init = r.copy()

        # Cropping overwrites the current Raster object
        r.crop(r2)
        b_crop = tuple(r.bounds)

        if DO_PLOT:
            fig1, ax1 = plt.subplots()
            r_init.show(ax=ax1, title="Raster 1")

            fig2, ax2 = plt.subplots()
            r2.show(ax=ax2, title="Raster 2")

            fig3, ax3 = plt.subplots()
            r.show(ax=ax3, title="Raster 1 cropped to Raster 2")
            plt.show()

        assert b_minmax == b_crop
Esempio n. 4
0
class TestVector:
    glacier_outlines = gu.Vector(GLACIER_OUTLINES_URL)

    def test_init(self) -> None:

        vector = gu.Vector(GLACIER_OUTLINES_URL)

        assert isinstance(vector, gu.Vector)

    def test_copy(self) -> None:

        vector2 = self.glacier_outlines.copy()

        assert vector2 is not self.glacier_outlines

        vector2.ds = vector2.ds.query("NAME == 'Ayerbreen'")

        assert vector2.ds.shape[0] < self.glacier_outlines.ds.shape[0]

    def test_query(self) -> None:

        vector2 = self.glacier_outlines.query("NAME == 'Ayerbreen'")

        assert vector2 is not self.glacier_outlines

        assert vector2.ds.shape[0] < self.glacier_outlines.ds.shape[0]

    def test_bounds(self) -> None:

        bounds = self.glacier_outlines.bounds

        assert bounds.left < bounds.right
        assert bounds.bottom < bounds.top

        assert bounds.left == self.glacier_outlines.ds.total_bounds[0]
        assert bounds.bottom == self.glacier_outlines.ds.total_bounds[1]
        assert bounds.right == self.glacier_outlines.ds.total_bounds[2]
        assert bounds.top == self.glacier_outlines.ds.total_bounds[3]
"""Plot an example of spatial interpolation of randomly generated errors."""
import geoutils as gu
import matplotlib.pyplot as plt
import numpy as np

import xdem

dem_2009 = xdem.DEM(xdem.examples.get_path("longyearbyen_ref_dem"))
dem_1990 = xdem.DEM(xdem.examples.get_path("longyearbyen_tba_dem"))
outlines_1990 = gu.Vector(
    xdem.examples.get_path("longyearbyen_glacier_outlines"))

ddem = xdem.dDEM(dem_2009 - dem_1990,
                 start_time=np.datetime64("1990-08-01"),
                 end_time=np.datetime64("2009-08-01"))
# The example DEMs are void-free, so let's make some random voids.
ddem.data.mask = np.zeros_like(ddem.data, dtype=bool)  # Reset the mask
# Introduce 50000 nans randomly throughout the dDEM.
ddem.data.mask.ravel()[np.random.choice(ddem.data.size, 50000,
                                        replace=False)] = True

ddem.interpolate(method="linear")

ylim = (300, 100)
xlim = (800, 1050)

plt.figure(figsize=(8, 5))
plt.subplot(121)
plt.imshow(ddem.data.squeeze(), cmap="coolwarm_r", vmin=-50, vmax=50)
plt.ylim(ylim)
plt.xlim(xlim)
Esempio n. 6
0
def test_read_paths_vector(test_dataset: str) -> None:
    assert isinstance(gu.Vector(datasets.get_path(test_dataset)), gu.Vector)
Esempio n. 7
0
    def test_init(self):

        timestamps = [
            datetime.datetime(1990, 8, 1),
            datetime.datetime(2009, 8, 1),
            datetime.datetime(2060, 8, 1)
        ]

        scott_1990 = gu.Vector(self.outlines_1990.ds.loc[
            self.outlines_1990.ds["NAME"] == "Scott Turnerbreen"])
        scott_2010 = gu.Vector(self.outlines_2010.ds.loc[
            self.outlines_2010.ds["NAME"] == "Scott Turnerbreen"])

        # Make sure the glacier was bigger in 1990, since this is assumed later.
        assert scott_1990.ds.area.sum() > scott_2010.ds.area.sum()

        mask_2010 = scott_2010.create_mask(self.dem_2009).reshape(
            self.dem_2009.data.shape)

        dem_2060 = self.dem_2009.copy()
        dem_2060.data[mask_2010] -= 30

        dems = xdem.DEMCollection(
            [self.dem_1990, self.dem_2009, dem_2060],
            timestamps=timestamps,
            outlines=dict(
                zip(timestamps[:2], [self.outlines_1990, self.outlines_2010])),
            reference_dem=1)

        # Check that the first raster is the oldest one and
        assert dems.dems[0].data.max() == self.dem_1990.data.max()
        assert dems.reference_dem.data.max() == self.dem_2009.data.max()

        dems.subtract_dems(resampling_method="nearest")

        assert np.mean(dems.ddems[0].data) < 0

        scott_filter = "NAME == 'Scott Turnerbreen'"

        dh_series = dems.get_dh_series(outlines_filter=scott_filter)

        # The 1990-2009 area should be the union of those years. The 2009-2060 area should just be the 2010 area.
        assert dh_series.iloc[0]["area"] > dh_series.iloc[-1]["area"]

        cumulative_dh = dems.get_cumulative_series(
            kind="dh", outlines_filter=scott_filter)
        cumulative_dv = dems.get_cumulative_series(
            kind="dv", outlines_filter=scott_filter)

        # Simple check that the cumulative_dh is overall negative.
        assert cumulative_dh.iloc[0] > cumulative_dh.iloc[-1]

        # Simple check that the dV number is of a greater magnitude than the dH number.
        assert abs(cumulative_dv.iloc[-1]) > abs(cumulative_dh.iloc[-1])

        # Generate 10000 NaN values randomly in one of the dDEMs
        dems.ddems[0].data[
            np.random.randint(0, dems.ddems[0].data.shape[0], 100),
            np.random.randint(0, dems.ddems[0].data.shape[1], 100)] = np.nan
        # Check that the cumulative_dh function warns for NaNs
        with warnings.catch_warnings():
            warnings.simplefilter("error")
            try:
                dems.get_cumulative_series(nans_ok=False)
            except UserWarning as exception:
                if "NaNs found in dDEM" not in str(exception):
                    raise exception
Esempio n. 8
0
class TestDEMCollection:
    dem_2009 = xdem.DEM(xdem.examples.get_path("longyearbyen_ref_dem"))
    dem_1990 = xdem.DEM(xdem.examples.get_path("longyearbyen_tba_dem"))
    outlines_1990 = gu.Vector(
        xdem.examples.get_path("longyearbyen_glacier_outlines"))
    outlines_2010 = gu.Vector(
        xdem.examples.get_path("longyearbyen_glacier_outlines_2010"))

    def test_init(self):

        timestamps = [
            datetime.datetime(1990, 8, 1),
            datetime.datetime(2009, 8, 1),
            datetime.datetime(2060, 8, 1)
        ]

        scott_1990 = gu.Vector(self.outlines_1990.ds.loc[
            self.outlines_1990.ds["NAME"] == "Scott Turnerbreen"])
        scott_2010 = gu.Vector(self.outlines_2010.ds.loc[
            self.outlines_2010.ds["NAME"] == "Scott Turnerbreen"])

        # Make sure the glacier was bigger in 1990, since this is assumed later.
        assert scott_1990.ds.area.sum() > scott_2010.ds.area.sum()

        mask_2010 = scott_2010.create_mask(self.dem_2009).reshape(
            self.dem_2009.data.shape)

        dem_2060 = self.dem_2009.copy()
        dem_2060.data[mask_2010] -= 30

        dems = xdem.DEMCollection(
            [self.dem_1990, self.dem_2009, dem_2060],
            timestamps=timestamps,
            outlines=dict(
                zip(timestamps[:2], [self.outlines_1990, self.outlines_2010])),
            reference_dem=1)

        # Check that the first raster is the oldest one and
        assert dems.dems[0].data.max() == self.dem_1990.data.max()
        assert dems.reference_dem.data.max() == self.dem_2009.data.max()

        dems.subtract_dems(resampling_method="nearest")

        assert np.mean(dems.ddems[0].data) < 0

        scott_filter = "NAME == 'Scott Turnerbreen'"

        dh_series = dems.get_dh_series(outlines_filter=scott_filter)

        # The 1990-2009 area should be the union of those years. The 2009-2060 area should just be the 2010 area.
        assert dh_series.iloc[0]["area"] > dh_series.iloc[-1]["area"]

        cumulative_dh = dems.get_cumulative_series(
            kind="dh", outlines_filter=scott_filter)
        cumulative_dv = dems.get_cumulative_series(
            kind="dv", outlines_filter=scott_filter)

        # Simple check that the cumulative_dh is overall negative.
        assert cumulative_dh.iloc[0] > cumulative_dh.iloc[-1]

        # Simple check that the dV number is of a greater magnitude than the dH number.
        assert abs(cumulative_dv.iloc[-1]) > abs(cumulative_dh.iloc[-1])

        # Generate 10000 NaN values randomly in one of the dDEMs
        dems.ddems[0].data[
            np.random.randint(0, dems.ddems[0].data.shape[0], 100),
            np.random.randint(0, dems.ddems[0].data.shape[1], 100)] = np.nan
        # Check that the cumulative_dh function warns for NaNs
        with warnings.catch_warnings():
            warnings.simplefilter("error")
            try:
                dems.get_cumulative_series(nans_ok=False)
            except UserWarning as exception:
                if "NaNs found in dDEM" not in str(exception):
                    raise exception

        # print(cumulative_dh)

        #raise NotImplementedError

    def test_dem_datetimes(self):
        """Try to create the DEMCollection without the timestamps argument (instead relying on datetime attributes)."""
        self.dem_1990.datetime = datetime.datetime(1990, 8, 1)
        self.dem_2009.datetime = datetime.datetime(2009, 8, 1)

        dems = xdem.DEMCollection([self.dem_1990, self.dem_2009])

        assert len(dems.timestamps) > 0

    def test_ddem_interpolation(self):
        """Test that dDEM interpolation works as it should."""
        # All warnings should raise errors from now on
        warnings.simplefilter("error")

        # Create a DEMCollection object
        dems = xdem.DEMCollection([self.dem_2009, self.dem_1990],
                                  timestamps=[
                                      datetime.datetime(year, 8, 1)
                                      for year in (2009, 1990)
                                  ])

        # Create dDEMs
        dems.subtract_dems(resampling_method="nearest")

        # The example data does not have NaNs, so filled_data should exist.
        assert dems.ddems[0].filled_data is not None

        # Try to set the filled_data property with an invalid size.
        try:
            dems.ddems[0].filled_data = np.zeros(3)
        except AssertionError as exception:
            if "differs from the data shape" not in str(exception):
                raise exception

        # Generate 10000 NaN values randomly in one of the dDEMs
        dems.ddems[0].data[
            np.random.randint(0, dems.ddems[0].data.shape[0], 100),
            np.random.randint(0, dems.ddems[0].data.shape[1], 100)] = np.nan

        # Make sure that filled_data is not available anymore, since the data now has nans
        assert dems.ddems[0].filled_data is None

        # Interpolate the nans
        dems.ddems[0].interpolate(method="linear")

        # Make sure that the filled_data is available again
        assert dems.ddems[0].filled_data is not None
Esempio n. 9
0
class TestdDEM:
    dem_2009 = xdem.DEM(xdem.examples.get_path("longyearbyen_ref_dem"))
    dem_1990 = xdem.DEM(xdem.examples.get_path("longyearbyen_tba_dem"))
    outlines_1990 = gu.Vector(xdem.examples.get_path("longyearbyen_glacier_outlines"))

    ddem = xdem.dDEM(
        dem_2009 - dem_1990,
        start_time=np.datetime64("1990-08-01"),
        end_time=np.datetime64("2009-08-01")
    )

    def test_init(self):
        """Test that the dDEM object was instantiated correctly."""
        assert isinstance(self.ddem, xdem.dDEM)
        assert isinstance(self.ddem.data, np.ma.masked_array)

    def test_copy(self):
        """Test that copying works as it should."""
        ddem2 = self.ddem.copy()

        assert isinstance(ddem2, xdem.dDEM)

        ddem2.data += 1

        assert self.ddem != ddem2

    def test_filled_data(self):
        """Test that the filled_data property points to the right data."""
        ddem2 = self.ddem.copy()

        assert not np.any(np.isnan(ddem2.data)) or np.all(~ddem2.data.mask)
        assert ddem2.filled_data is not None

        assert np.count_nonzero(np.isnan(ddem2.data)) == 0
        ddem2.data.ravel()[0] = np.nan

        assert np.count_nonzero(np.isnan(ddem2.data)) == 1

        assert ddem2.filled_data is None

        ddem2.interpolate(method="linear")

        assert ddem2.fill_method is not None

    def test_regional_hypso(self):
        """Test the regional hypsometric approach."""
        ddem = self.ddem.copy()
        ddem.data.mask = np.zeros_like(ddem.data, dtype=bool)
        ddem.data.mask.ravel()[np.random.choice(ddem.data.size, 50000, replace=False)] = True
        assert np.count_nonzero(ddem.data.mask) > 0

        assert ddem.filled_data is None

        ddem.interpolate(
            method="regional_hypsometric",
            reference_elevation=self.dem_2009,
            mask=self.outlines_1990
        )

        assert ddem._filled_data is not None
        assert type(ddem.filled_data) == np.ndarray

        assert ddem.filled_data.shape == ddem.data.shape

        assert np.abs(np.nanmean(self.ddem.data - ddem.filled_data)) < 1

    def test_local_hypso(self):
        """Test the local hypsometric approach."""
        ddem = self.ddem.copy()
        scott_1990 = self.outlines_1990.query("NAME == 'Scott Turnerbreen'")
        ddem.data.mask = np.zeros_like(ddem.data, dtype=bool)
        ddem.data.mask.ravel()[np.random.choice(ddem.data.size, 50000, replace=False)] = True
        assert np.count_nonzero(ddem.data.mask) > 0

        assert ddem.filled_data is None

        ddem.interpolate(
            method="local_hypsometric",
            reference_elevation=self.dem_2009.data,
            mask=self.outlines_1990
        )
        assert np.abs(np.mean(self.ddem.data - ddem.filled_data)) < 1
Esempio n. 10
0
and quality of stereo-correlation (Equation 1, Extended Data Fig. 3a).
"""
# sphinx_gallery_thumbnail_number = 4
import matplotlib.pyplot as plt
import numpy as np
import xdem
import geoutils as gu

# %%
# We start by estimating the non-stationarities and deriving a terrain-dependent measurement error as a function of both
# slope and maximum curvature, as shown in the  :ref:`sphx_glr_auto_examples_plot_nonstationary_error.py` example.

# Load the data
ref_dem = xdem.DEM(xdem.examples.get_path("longyearbyen_ref_dem"))
dh = xdem.DEM(xdem.examples.get_path("longyearbyen_ddem"))
glacier_outlines = gu.Vector(xdem.examples.get_path("longyearbyen_glacier_outlines"))
mask_glacier = glacier_outlines.create_mask(dh)

# Compute the slope and maximum curvature
slope, planc, profc = \
    xdem.terrain.get_terrain_attribute(dem=ref_dem.data,
                                       attribute=['slope', 'planform_curvature', 'profile_curvature'],
                                       resolution=ref_dem.res)

# Remove values on unstable terrain
dh_arr = dh.data[~mask_glacier]
slope_arr = slope[~mask_glacier]
planc_arr = planc[~mask_glacier]
profc_arr = profc[~mask_glacier]
maxc_arr = np.maximum(np.abs(planc_arr),np.abs(profc_arr))
Esempio n. 11
0
    def interpolate(self,
                    method: str = "linear",
                    reference_elevation: Optional[Union[np.ndarray,
                                                        np.ma.masked_array,
                                                        xdem.DEM]] = None,
                    mask: Optional[Union[np.ndarray, xdem.DEM,
                                         gu.Vector]] = None):
        """
        Interpolate the dDEM using the given method.

        :param method: The method to use for interpolation.
        :param reference_elevation: Reference DEM. Only required for hypsometric approaches.
        """
        if reference_elevation is not None:
            try:
                reference_elevation = reference_elevation.reproject(
                    self, silent=True)  # type: ignore
            except AttributeError as exception:
                if "object has no attribute 'reproject'" not in str(exception):
                    raise exception

            if isinstance(reference_elevation, np.ndarray):
                reference_elevation = np.ma.masked_array(
                    reference_elevation, mask=np.isnan(reference_elevation))

            assert reference_elevation.data.shape == self.data.shape, (
                f"'reference_elevation' shape ({reference_elevation.data.shape})"
                f" different from 'self' ({self.data.shape})")

        if method == "linear":
            self.filled_data = xdem.volume.linear_interpolation(self.data)
        elif method == "local_hypsometric":
            assert reference_elevation is not None
            assert mask is not None

            if not isinstance(mask, gu.Vector):
                mask = gu.Vector(mask)

            interpolated_ddem, nans = xdem.spatial_tools.get_array_and_mask(
                self.data.copy())
            entries = mask.ds[mask.ds.intersects(
                shapely.geometry.box(*self.bounds))]

            ddem_mask = nans.copy().squeeze()
            for i in entries.index:
                feature_mask = (gu.Vector(
                    entries.loc[entries.index == i]).create_mask(self)
                                ).reshape(interpolated_ddem.shape)
                if np.count_nonzero(feature_mask) == 0:
                    continue
                try:
                    with warnings.catch_warnings():
                        warnings.filterwarnings("ignore",
                                                "Not enough valid bins")
                        interpolated_ddem = np.asarray(
                            xdem.volume.hypsometric_interpolation(
                                interpolated_ddem,
                                reference_elevation.data,
                                mask=feature_mask))
                except ValueError as exception:
                    # Skip the feature if too few glacier values exist.
                    if "x and y arrays must have at least 2 entries" in str(
                            exception):
                        continue
                    raise exception
                # Set the validity flag of all values within the feature to be valid
                ddem_mask[feature_mask] = False

                # All values that were nan in the start and are without the updated validity mask should now be nan
                # The above interpolates values outside of the dDEM, so this is necessary.
                interpolated_ddem[ddem_mask] = np.nan

            diff = abs(np.nanmean(interpolated_ddem - self.data))
            assert diff < 0.01, (diff, self.data.mean())

            self.filled_data = xdem.volume.linear_interpolation(
                interpolated_ddem)

        elif method == "regional_hypsometric":
            assert reference_elevation is not None
            assert mask is not None

            mask_array = xdem.coreg.mask_as_array(self, mask).reshape(
                self.data.shape)

            self.filled_data = xdem.volume.hypsometric_interpolation(
                self.data, reference_elevation.data, mask=mask_array).data

        else:
            raise NotImplementedError(
                f"Interpolation method '{method}' not supported")

        return self.filled_data
Esempio n. 12
0
def test_read_paths_vector(test_dataset: str) -> None:
    warnings.simplefilter("error")
    assert isinstance(gu.Vector(datasets.get_path(test_dataset)), gu.Vector)
Esempio n. 13
0
    def test_init(self) -> None:

        vector = gu.Vector(GLACIER_OUTLINES_URL)

        assert isinstance(vector, gu.Vector)
"""Example script to load a vector file."""
import warnings

warnings.simplefilter(
    "ignore"
)  # Temporarily filter warnings since something's up with GeoPandas (2021-05-20).
import geoutils as gu

filename = gu.datasets.get_path("glacier_outlines")

outlines = gu.Vector(filename)
# TEXT
# Load an example Landsat image
filename = gu.datasets.get_path("landsat_B4")
image = gu.Raster(filename)

# Generate a boolean mask from the glacier outlines.
mask = outlines.create_mask(image)
Esempio n. 15
0
"""
Loading and understanding Vectors
=================================

This is (right now) a dummy example for showing the functionality of :class:`geoutils.Vector`.
"""

import matplotlib.pyplot as plt

import geoutils as gu

# %%
# Example raster:
glaciers = gu.Vector(gu.datasets.get_path("glacier_outlines"))

# %%
# Info:
print(glaciers)

# %%
# A plot:
for _, glacier in glaciers.ds.iterrows():
    plt.plot(*glacier.geometry.exterior.xy)
plt.show()