-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…dify-Min-max-Scaling Add proximity computation tool
- Loading branch information
Showing
4 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Proximity computation | ||
|
||
::: eis_toolkit.vector_processing.proximity_computation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
from numbers import Number | ||
|
||
import geopandas as gpd | ||
import numpy as np | ||
from beartype import beartype | ||
from beartype.typing import Literal, Tuple, Union | ||
from rasterio import profiles | ||
|
||
from eis_toolkit.transformations.linear import _min_max_scaling | ||
from eis_toolkit.vector_processing.distance_computation import distance_computation | ||
|
||
|
||
@beartype | ||
def proximity_computation( | ||
geodataframe: gpd.GeoDataFrame, | ||
raster_profile: Union[profiles.Profile, dict], | ||
maximum_distance: Number, | ||
scaling_method: Literal["linear"] = "linear", | ||
scale_range: Tuple[Number, Number] = (1, 0), | ||
) -> np.ndarray: | ||
"""Compute proximity to the nearest geometries. | ||
Args: | ||
geodataframe: The GeoDataFrame with geometries to determine proximity to. | ||
raster_profile: The raster profile of the raster in which the distances | ||
to the nearest geometry are determined. | ||
max_distance: The maximum distance in the output array beyond which proximity is considered 0. | ||
scaling_method: Scaling method used to produce the proximity values. Defaults to 'linear' | ||
scaling_range: Min and max values used for scaling the proximity values. Defaults to (1,0). | ||
Returns: | ||
A 2D numpy array with the scaled values. | ||
Raises: | ||
NonMatchingCrsException: The input raster profile and geodataframe have mismatching CRS. | ||
EmptyDataFrameException: The input geodataframe is empty. | ||
""" | ||
out_matrix = _linear_proximity_computation(geodataframe, raster_profile, maximum_distance, scale_range) | ||
|
||
return out_matrix | ||
|
||
|
||
@beartype | ||
def _linear_proximity_computation( | ||
geodataframe: gpd.GeoDataFrame, | ||
raster_profile: Union[profiles.Profile, dict], | ||
maximum_distance: Number, | ||
scaling_range: Tuple[Number, Number], | ||
) -> np.ndarray: | ||
"""Compute proximity to the nearest geometries. | ||
Args: | ||
geodataframe: The GeoDataFrame with geometries to determine proximity to. | ||
raster_profile: The raster profile of the raster in which the distances | ||
to the nearest geometry are determined. | ||
max_distance: The maximum distance in the output array. | ||
scaling_range: a tuple of maximum value in the scaling and minimum value. | ||
Returns: | ||
A 2D numpy array with the linearly scaled values. | ||
Raises: | ||
NonMatchingCrsException: The input raster profile and geodataframe have mismatching CRS. | ||
EmptyDataFrameException: The input geodataframe is empty. | ||
""" | ||
|
||
out_matrix = distance_computation(geodataframe, raster_profile, maximum_distance) | ||
|
||
out_matrix = _min_max_scaling(out_matrix, scaling_range) | ||
|
||
return out_matrix |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import sys | ||
|
||
import geopandas as gpd | ||
import numpy as np | ||
import pytest | ||
import rasterio | ||
|
||
from eis_toolkit.exceptions import NumericValueSignException | ||
from eis_toolkit.vector_processing.proximity_computation import proximity_computation | ||
from tests.raster_processing.clip_test import polygon_path as polygon_path | ||
from tests.raster_processing.clip_test import raster_path as SMALL_RASTER_PATH | ||
|
||
sys.path.append("../..") | ||
gdf = gpd.read_file(polygon_path) | ||
|
||
with rasterio.open(SMALL_RASTER_PATH) as test_raster: | ||
raster_profile = test_raster.profile | ||
|
||
EXPECTED_SMALL_RASTER_SHAPE = raster_profile["height"], raster_profile["width"] | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"geodataframe,raster_profile,expected_shape,maximum_distance,scale,scaling_range", | ||
[ | ||
pytest.param( | ||
gdf, | ||
raster_profile, | ||
EXPECTED_SMALL_RASTER_SHAPE, | ||
25, | ||
"linear", | ||
(1, 0), | ||
id="Inversion_and_scaling_between_1_and_0", | ||
), | ||
pytest.param( | ||
gdf, | ||
raster_profile, | ||
EXPECTED_SMALL_RASTER_SHAPE, | ||
25, | ||
"linear", | ||
(2, 1), | ||
id="Inversion_and_scaling_between_2_and_1", | ||
), | ||
], | ||
) | ||
def test_proximity_computation_inversion_with_expected_result( | ||
geodataframe, raster_profile, expected_shape, maximum_distance, scale, scaling_range | ||
): | ||
"""Tests if the enteries in the output matrix are between the minimum and maximum value.""" | ||
|
||
result = proximity_computation(geodataframe, raster_profile, maximum_distance, scale, scaling_range) | ||
|
||
assert result.shape == expected_shape | ||
# Assert that all values in result within scaling_range | ||
assert np.all((result >= scaling_range[1]) & (result <= scaling_range[0])), "Scaling out of scaling_range" | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"geodataframe,raster_profile,expected_shape,maximum_distance,scale,scaling_range", | ||
[ | ||
pytest.param( | ||
gdf, | ||
raster_profile, | ||
EXPECTED_SMALL_RASTER_SHAPE, | ||
25, | ||
"linear", | ||
(0, 1), | ||
id="Scaling_between_0_and_1", | ||
), | ||
pytest.param( | ||
gdf, | ||
raster_profile, | ||
EXPECTED_SMALL_RASTER_SHAPE, | ||
25, | ||
"linear", | ||
(1, 2), | ||
id="Scaling_between_1_and_2", | ||
), | ||
], | ||
) | ||
def test_proximity_computation_with_expected_result( | ||
geodataframe, raster_profile, expected_shape, maximum_distance, scale, scaling_range | ||
): | ||
"""Tests if the enteries in the output matrix are between the minimum and maximum value.""" | ||
|
||
result = proximity_computation(geodataframe, raster_profile, maximum_distance, scale, scaling_range) | ||
|
||
assert result.shape == expected_shape | ||
# Assert that all values in result within scaling_range | ||
assert np.all((result <= scaling_range[1]) & (result >= scaling_range[0])), "Scaling out of scaling_range" | ||
|
||
|
||
def test_proximity_computation_with_expected_error(): | ||
"""Tests if an exception is raised for a negative maximum distance.""" | ||
|
||
with pytest.raises(NumericValueSignException, match="Expected max distance to be a positive number."): | ||
result = proximity_computation(gdf, raster_profile, -25, "linear", (1, 0)) | ||
assert np.all((result >= 0) & (result <= 1)), "Scaling out of scaling_range" |