yirgacheffe 1.7.2__tar.gz → 1.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yirgacheffe might be problematic. Click here for more details.
- {yirgacheffe-1.7.2/yirgacheffe.egg-info → yirgacheffe-1.7.4}/PKG-INFO +4 -1
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/pyproject.toml +4 -1
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_intersection.py +36 -3
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_nodata.py +28 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_operators.py +12 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_union.py +35 -2
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/_backends/enumeration.py +1 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/_backends/mlx.py +2 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/_backends/numpy.py +2 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/base.py +11 -9
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/group.py +4 -3
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/operators.py +10 -1
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4/yirgacheffe.egg-info}/PKG-INFO +4 -1
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/LICENSE +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/MANIFEST.in +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/README.md +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/setup.cfg +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_area.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_auto_windowing.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_base.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_constants.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_datatypes.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_group.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_h3layer.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_multiband.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_openers.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_optimisation.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_parallel_operators.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_pickle.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_projection.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_raster.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_rescaling.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_rounding.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_save_with_window.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_sum_with_window.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_uniform_area_layer.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_vectors.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/tests/test_window.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/__init__.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/_backends/__init__.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/_core.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/constants.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/__init__.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/area.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/constant.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/h3layer.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/rasters.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/rescaled.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/layers/vectors.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/rounding.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe/window.py +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe.egg-info/SOURCES.txt +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe.egg-info/dependency_links.txt +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe.egg-info/entry_points.txt +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe.egg-info/requires.txt +0 -0
- {yirgacheffe-1.7.2 → yirgacheffe-1.7.4}/yirgacheffe.egg-info/top_level.txt +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yirgacheffe
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.4
|
|
4
4
|
Summary: Abstraction of gdal datasets for doing basic math operations
|
|
5
5
|
Author-email: Michael Dales <mwd24@cam.ac.uk>
|
|
6
6
|
License-Expression: ISC
|
|
7
7
|
Project-URL: Homepage, https://github.com/quantifyearth/yirgacheffe
|
|
8
|
+
Project-URL: Repository, https://github.com/quantifyearth/yirgacheffe.git
|
|
9
|
+
Project-URL: Issues, https://github.com/quantifyearth/yirgacheffe/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/quantifyearth/yirgacheffe/blob/main/CHANGES.md
|
|
8
11
|
Keywords: gdal,numpy,math
|
|
9
12
|
Requires-Python: >=3.10
|
|
10
13
|
Description-Content-Type: text/markdown
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "yirgacheffe"
|
|
9
|
-
version = "1.7.
|
|
9
|
+
version = "1.7.4"
|
|
10
10
|
description = "Abstraction of gdal datasets for doing basic math operations"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [{ name = "Michael Dales", email = "mwd24@cam.ac.uk" }]
|
|
@@ -28,6 +28,9 @@ dev = ["mypy", "pylint", "pytest", "h3", "pytest-cov", "mlx"]
|
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
30
30
|
Homepage = "https://github.com/quantifyearth/yirgacheffe"
|
|
31
|
+
Repository = "https://github.com/quantifyearth/yirgacheffe.git"
|
|
32
|
+
Issues = "https://github.com/quantifyearth/yirgacheffe/issues"
|
|
33
|
+
Changelog = "https://github.com/quantifyearth/yirgacheffe/blob/main/CHANGES.md"
|
|
31
34
|
|
|
32
35
|
[project.scripts]
|
|
33
36
|
realpython = "reader.__main__:main"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
1
4
|
import pytest
|
|
2
5
|
from osgeo import gdal
|
|
3
6
|
|
|
4
|
-
from tests.helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
|
|
7
|
+
from tests.helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region, make_vectors_with_id
|
|
5
8
|
from yirgacheffe.window import Area, MapProjection, Window
|
|
6
|
-
from yirgacheffe.layers import RasterLayer, ConstantLayer, H3CellLayer
|
|
9
|
+
from yirgacheffe.layers import RasterLayer, ConstantLayer, H3CellLayer, VectorLayer
|
|
7
10
|
from yirgacheffe import WGS_84_PROJECTION
|
|
8
11
|
|
|
9
12
|
|
|
@@ -56,6 +59,36 @@ def test_find_intersection_with_constant() -> None:
|
|
|
56
59
|
intersection = RasterLayer.find_intersection(layers)
|
|
57
60
|
assert intersection == layers[0].area
|
|
58
61
|
|
|
62
|
+
def test_find_intersection_with_vector_unbound() -> None:
|
|
63
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
64
|
+
path = Path(tempdir) / "test.gpkg"
|
|
65
|
+
area = Area(left=58, top=74, right=180, bottom=42)
|
|
66
|
+
make_vectors_with_id(42, {area}, path)
|
|
67
|
+
assert path.exists
|
|
68
|
+
|
|
69
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(left=-180.05, top=90.09, right=180.05, bottom=-90.09), 0.13))
|
|
70
|
+
vector = VectorLayer.layer_from_file(path, None, None, None)
|
|
71
|
+
assert vector.area == area
|
|
72
|
+
|
|
73
|
+
layers = [raster, vector]
|
|
74
|
+
intersection = RasterLayer.find_intersection(layers)
|
|
75
|
+
assert intersection == vector.area
|
|
76
|
+
|
|
77
|
+
def test_find_intersection_with_vector_bound() -> None:
|
|
78
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
79
|
+
path = Path(tempdir) / "test.gpkg"
|
|
80
|
+
area = Area(left=58, top=74, right=180, bottom=42)
|
|
81
|
+
make_vectors_with_id(42, {area}, path)
|
|
82
|
+
assert path.exists
|
|
83
|
+
|
|
84
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(left=-180.05, top=90.09, right=180.05, bottom=-90.09), 0.13))
|
|
85
|
+
vector = VectorLayer.layer_from_file(path, None, raster.map_projection.scale, raster.map_projection.name)
|
|
86
|
+
assert vector.area != area
|
|
87
|
+
|
|
88
|
+
layers = [raster, vector]
|
|
89
|
+
intersection = RasterLayer.find_intersection(layers)
|
|
90
|
+
assert intersection == vector.area
|
|
91
|
+
|
|
59
92
|
def test_find_intersection_different_pixel_pitch() -> None:
|
|
60
93
|
layers = [
|
|
61
94
|
RasterLayer(gdal_dataset_of_region(Area(-10, 10, 10, -10), 0.02)),
|
|
@@ -143,7 +176,7 @@ def test_find_intersection_nearly_same() -> None:
|
|
|
143
176
|
assert layers[0].window.xsize == other.window.xsize
|
|
144
177
|
assert layers[0].window.ysize == other.window.ysize
|
|
145
178
|
|
|
146
|
-
def test_intersection_stability():
|
|
179
|
+
def test_intersection_stability() -> None:
|
|
147
180
|
# This test uses h3 tiles as a lazy way to get some bounded regions,
|
|
148
181
|
# but the bug this test exercises is not h3 specific. This was another case of
|
|
149
182
|
# a rounding error that causes set_window_for_* methods to wobble depending on how far
|
|
@@ -62,3 +62,31 @@ def test_group_layer_with_nodata_values_ignore_nodata() -> None:
|
|
|
62
62
|
with GroupLayer([layer1, layer2]) as group:
|
|
63
63
|
actual = group.read_array(0, 0, 4, 2)
|
|
64
64
|
assert np.array_equal(data1, actual, equal_nan=True)
|
|
65
|
+
|
|
66
|
+
def test_group_layer_with_nodata_read_from_empty_area() -> None:
|
|
67
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 5.0, 5.0, 5.0]])
|
|
68
|
+
dataset1 = gdal_dataset_with_data((0.0, 10.0), 1.0, data1)
|
|
69
|
+
dataset1.GetRasterBand(1).SetNoDataValue(5.0)
|
|
70
|
+
|
|
71
|
+
data2 = np.array([[1.0, 1.0, 1.0, 1.0], [5.0, 6.0, 7.0, 8.0]])
|
|
72
|
+
dataset2 = gdal_dataset_with_data((0.0, -8.0), 1.0, data2)
|
|
73
|
+
dataset2.GetRasterBand(1).SetNoDataValue(1.0)
|
|
74
|
+
|
|
75
|
+
with RasterLayer(dataset1) as layer1:
|
|
76
|
+
with RasterLayer(dataset2) as layer2:
|
|
77
|
+
with GroupLayer([layer1, layer2]) as group:
|
|
78
|
+
|
|
79
|
+
assert group.window.xsize == 4
|
|
80
|
+
assert group.window.ysize == 20
|
|
81
|
+
|
|
82
|
+
actual = group.read_array(0, 0, 4, 2)
|
|
83
|
+
expected = np.array([[1.0, 2.0, 3.0, 4.0], [0.0, 0.0, 0.0, 0.0]])
|
|
84
|
+
assert np.array_equal(expected, actual, equal_nan=True)
|
|
85
|
+
|
|
86
|
+
actual = group.read_array(0, 10, 4, 2)
|
|
87
|
+
expected = np.array([[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]])
|
|
88
|
+
assert np.array_equal(expected, actual, equal_nan=True)
|
|
89
|
+
|
|
90
|
+
actual = group.read_array(0, 18, 4, 2)
|
|
91
|
+
expected = np.array([[0.0, 0.0, 0.0, 0.0], [5.0, 6.0, 7.0, 8.0]])
|
|
92
|
+
assert np.array_equal(expected, actual, equal_nan=True)
|
|
@@ -1567,3 +1567,15 @@ def test_raster_and_vector_no_scale_on_vector() -> None:
|
|
|
1567
1567
|
calc = raster * vector
|
|
1568
1568
|
assert calc.sum() > 0.0
|
|
1569
1569
|
assert calc.sum() < raster.sum()
|
|
1570
|
+
|
|
1571
|
+
def test_isnan() -> None:
|
|
1572
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 5.0, 8.0]])
|
|
1573
|
+
dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1)
|
|
1574
|
+
dataset.GetRasterBand(1).SetNoDataValue(5.0)
|
|
1575
|
+
with RasterLayer(dataset) as layer:
|
|
1576
|
+
calc = layer.isnan()
|
|
1577
|
+
with RasterLayer.empty_raster_layer_like(calc) as result:
|
|
1578
|
+
calc.save(result)
|
|
1579
|
+
actual = result.read_array(0, 0, 4, 2)
|
|
1580
|
+
expected = data1 == 5.0
|
|
1581
|
+
assert (expected == actual).all()
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
1
4
|
import pytest
|
|
2
5
|
|
|
3
|
-
from tests.helpers import gdal_dataset_of_region
|
|
6
|
+
from tests.helpers import gdal_dataset_of_region, make_vectors_with_id
|
|
4
7
|
from yirgacheffe.window import Area, Window
|
|
5
|
-
from yirgacheffe.layers import ConstantLayer, RasterLayer
|
|
8
|
+
from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
def test_find_union_empty_list() -> None:
|
|
@@ -62,6 +65,36 @@ def test_find_union_different_pixel_pitch() -> None:
|
|
|
62
65
|
with pytest.raises(ValueError):
|
|
63
66
|
_ = RasterLayer.find_union(layers)
|
|
64
67
|
|
|
68
|
+
def test_find_union_with_vector_unbound() -> None:
|
|
69
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
70
|
+
path = Path(tempdir) / "test.gpkg"
|
|
71
|
+
area = Area(left=58, top=74, right=180, bottom=42)
|
|
72
|
+
make_vectors_with_id(42, {area}, path)
|
|
73
|
+
assert path.exists
|
|
74
|
+
|
|
75
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(left=59.93, top=70.07, right=170.04, bottom=44.98), 0.13))
|
|
76
|
+
vector = VectorLayer.layer_from_file(path, None, None, None)
|
|
77
|
+
assert vector.area == area
|
|
78
|
+
|
|
79
|
+
layers = [raster, vector]
|
|
80
|
+
union = RasterLayer.find_union(layers)
|
|
81
|
+
assert union == vector.area
|
|
82
|
+
|
|
83
|
+
def test_find_union_with_vector_bound() -> None:
|
|
84
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
85
|
+
path = Path(tempdir) / "test.gpkg"
|
|
86
|
+
area = Area(left=58, top=74, right=180, bottom=42)
|
|
87
|
+
make_vectors_with_id(42, {area}, path)
|
|
88
|
+
assert path.exists
|
|
89
|
+
|
|
90
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(left=59.93, top=70.07, right=170.04, bottom=44.98), 0.13))
|
|
91
|
+
vector = VectorLayer.layer_from_file(path, None, raster.map_projection.scale, raster.map_projection.name)
|
|
92
|
+
assert vector.area != area
|
|
93
|
+
|
|
94
|
+
layers = [raster, vector]
|
|
95
|
+
union = RasterLayer.find_union(layers)
|
|
96
|
+
assert union == vector.area
|
|
97
|
+
|
|
65
98
|
@pytest.mark.parametrize("scale", [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09])
|
|
66
99
|
def test_set_union_self(scale) -> None:
|
|
67
100
|
layer = RasterLayer(gdal_dataset_of_region(Area(-10, 10, 10, -10), scale))
|
|
@@ -40,6 +40,7 @@ maximum = mx.maximum
|
|
|
40
40
|
minimum = mx.minimum
|
|
41
41
|
zeros = mx.zeros
|
|
42
42
|
pad = mx.pad
|
|
43
|
+
isnan = mx.isnan
|
|
43
44
|
isscalar = np.isscalar
|
|
44
45
|
full = mx.full
|
|
45
46
|
allclose = mx.allclose
|
|
@@ -218,4 +219,5 @@ operator_map : Dict[op,Callable] = {
|
|
|
218
219
|
op.FLOOR: mx.floor,
|
|
219
220
|
op.ROUND: mx.round,
|
|
220
221
|
op.CEIL: mx.ceil,
|
|
222
|
+
op.ISNAN: mx.isnan,
|
|
221
223
|
}
|
|
@@ -43,6 +43,7 @@ minimum = np.minimum
|
|
|
43
43
|
zeros = np.zeros
|
|
44
44
|
pad = np.pad
|
|
45
45
|
sum_op = lambda a: np.sum(a.astype(np.float64))
|
|
46
|
+
isnan = np.isnan
|
|
46
47
|
isscalar = np.isscalar
|
|
47
48
|
full = np.full
|
|
48
49
|
allclose = np.allclose
|
|
@@ -156,4 +157,5 @@ operator_map : Dict[op,Callable] = {
|
|
|
156
157
|
op.FLOOR: np.floor,
|
|
157
158
|
op.ROUND: np.round,
|
|
158
159
|
op.CEIL: np.ceil,
|
|
160
|
+
op.ISNAN: np.isnan,
|
|
159
161
|
}
|
|
@@ -91,7 +91,7 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
91
91
|
else:
|
|
92
92
|
return self._underlying_area
|
|
93
93
|
|
|
94
|
-
def _get_operation_area(self, projection: Optional[MapProjection]) -> Area:
|
|
94
|
+
def _get_operation_area(self, projection: Optional[MapProjection]=None) -> Area:
|
|
95
95
|
if self._projection is not None and projection is not None and self._projection != projection:
|
|
96
96
|
raise ValueError("Calculation projection does not match layer projection")
|
|
97
97
|
return self.area
|
|
@@ -119,11 +119,12 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
119
119
|
if not all(projections[0] == x for x in projections[1:]):
|
|
120
120
|
raise ValueError("Not all layers are at the same projectin or pixel scale")
|
|
121
121
|
|
|
122
|
+
layer_areas = [x._get_operation_area() for x in layers]
|
|
122
123
|
intersection = Area(
|
|
123
|
-
left=max(x.
|
|
124
|
-
top=min(x.
|
|
125
|
-
right=min(x.
|
|
126
|
-
bottom=max(x.
|
|
124
|
+
left=max(x.left for x in layer_areas),
|
|
125
|
+
top=min(x.top for x in layer_areas),
|
|
126
|
+
right=min(x.right for x in layer_areas),
|
|
127
|
+
bottom=max(x.bottom for x in layer_areas)
|
|
127
128
|
)
|
|
128
129
|
if (intersection.left >= intersection.right) or (intersection.bottom >= intersection.top):
|
|
129
130
|
raise ValueError('No intersection possible')
|
|
@@ -142,11 +143,12 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
142
143
|
if not all(projections[0] == x for x in projections[1:]):
|
|
143
144
|
raise ValueError("Not all layers are at the same projectin or pixel scale")
|
|
144
145
|
|
|
146
|
+
layer_areas = [x._get_operation_area() for x in layers]
|
|
145
147
|
return Area(
|
|
146
|
-
left=min(x.
|
|
147
|
-
top=max(x.
|
|
148
|
-
right=max(x.
|
|
149
|
-
bottom=min(x.
|
|
148
|
+
left=min(x.left for x in layer_areas),
|
|
149
|
+
top=max(x.top for x in layer_areas),
|
|
150
|
+
right=max(x.right for x in layer_areas),
|
|
151
|
+
bottom=min(x.bottom for x in layer_areas)
|
|
150
152
|
)
|
|
151
153
|
|
|
152
154
|
@property
|
|
@@ -114,8 +114,9 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
114
114
|
if (xsize <= 0) or (ysize <= 0):
|
|
115
115
|
raise ValueError("Request dimensions must be positive and non-zero")
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
assert
|
|
117
|
+
map_projection = self.map_projection
|
|
118
|
+
assert map_projection is not None
|
|
119
|
+
scale = map_projection.scale
|
|
119
120
|
|
|
120
121
|
target_window = Window(
|
|
121
122
|
window.xoff + xoffset,
|
|
@@ -151,7 +152,7 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
151
152
|
intersection.ysize
|
|
152
153
|
)
|
|
153
154
|
if layer.nodata is not None:
|
|
154
|
-
data
|
|
155
|
+
data = backend.where(backend.isnan(data), 0.0, data)
|
|
155
156
|
return data
|
|
156
157
|
|
|
157
158
|
result = np.zeros((ysize, xsize), dtype=float)
|
|
@@ -139,6 +139,13 @@ class LayerMathMixin:
|
|
|
139
139
|
test_elements=test_elements,
|
|
140
140
|
)
|
|
141
141
|
|
|
142
|
+
def isnan(self):
|
|
143
|
+
return LayerOperation(
|
|
144
|
+
self,
|
|
145
|
+
op.ISNAN,
|
|
146
|
+
window_op=WindowOperation.NONE,
|
|
147
|
+
)
|
|
148
|
+
|
|
142
149
|
def abs(self):
|
|
143
150
|
return LayerOperation(
|
|
144
151
|
self,
|
|
@@ -659,7 +666,9 @@ class LayerOperation(LayerMathMixin):
|
|
|
659
666
|
|
|
660
667
|
if (computation_window.xsize != destination_window.xsize) \
|
|
661
668
|
or (computation_window.ysize != destination_window.ysize):
|
|
662
|
-
raise ValueError("Destination raster window size does not match input raster window size
|
|
669
|
+
raise ValueError((f"Destination raster window size does not match input raster window size: "
|
|
670
|
+
f"{(destination_window.xsize, destination_window.ysize)} vs "
|
|
671
|
+
f"{(computation_window.xsize, computation_window.ysize)}"))
|
|
663
672
|
|
|
664
673
|
total = 0.0
|
|
665
674
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yirgacheffe
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.4
|
|
4
4
|
Summary: Abstraction of gdal datasets for doing basic math operations
|
|
5
5
|
Author-email: Michael Dales <mwd24@cam.ac.uk>
|
|
6
6
|
License-Expression: ISC
|
|
7
7
|
Project-URL: Homepage, https://github.com/quantifyearth/yirgacheffe
|
|
8
|
+
Project-URL: Repository, https://github.com/quantifyearth/yirgacheffe.git
|
|
9
|
+
Project-URL: Issues, https://github.com/quantifyearth/yirgacheffe/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/quantifyearth/yirgacheffe/blob/main/CHANGES.md
|
|
8
11
|
Keywords: gdal,numpy,math
|
|
9
12
|
Requires-Python: >=3.10
|
|
10
13
|
Description-Content-Type: text/markdown
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|