yirgacheffe 1.3.3__tar.gz → 1.4.0__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.3.3/yirgacheffe.egg-info → yirgacheffe-1.4.0}/PKG-INFO +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/pyproject.toml +1 -1
- yirgacheffe-1.4.0/tests/test_area.py +21 -0
- yirgacheffe-1.4.0/tests/test_auto_windowing.py +284 -0
- yirgacheffe-1.4.0/tests/test_constants.py +32 -0
- yirgacheffe-1.4.0/tests/test_datatypes.py +67 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_group.py +4 -4
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_h3layer.py +10 -8
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_intersection.py +2 -3
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_multiband.py +2 -2
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_operators.py +7 -8
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_optimisation.py +2 -3
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_parallel_operators.py +13 -13
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_pickle.py +4 -3
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_raster.py +2 -12
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_rescaling.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_save_with_window.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_sum_with_window.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_uniform_area_layer.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_union.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_vectors.py +16 -30
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/__init__.py +0 -3
- {yirgacheffe-1.3.3/yirgacheffe/backends → yirgacheffe-1.4.0/yirgacheffe/_backends}/__init__.py +1 -1
- {yirgacheffe-1.3.3/yirgacheffe/backends → yirgacheffe-1.4.0/yirgacheffe/_backends}/mlx.py +1 -1
- yirgacheffe-1.4.0/yirgacheffe/layers/__init__.py +14 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/base.py +20 -7
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/constant.py +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/group.py +14 -11
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/h3layer.py +7 -2
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/rasters.py +27 -16
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/rescaled.py +3 -2
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/vectors.py +37 -30
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/operators.py +35 -13
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/window.py +93 -2
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0/yirgacheffe.egg-info}/PKG-INFO +1 -1
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe.egg-info/SOURCES.txt +5 -5
- yirgacheffe-1.3.3/tests/test_area.py +0 -21
- yirgacheffe-1.3.3/tests/test_auto_windowing.py +0 -284
- yirgacheffe-1.3.3/tests/test_datatypes.py +0 -67
- yirgacheffe-1.3.3/yirgacheffe/h3layer.py +0 -2
- yirgacheffe-1.3.3/yirgacheffe/layers/__init__.py +0 -43
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/LICENSE +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/MANIFEST.in +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/README.md +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/setup.cfg +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_base.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_rounding.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/tests/test_window.py +0 -0
- {yirgacheffe-1.3.3/yirgacheffe/backends → yirgacheffe-1.4.0/yirgacheffe/_backends}/enumeration.py +0 -0
- {yirgacheffe-1.3.3/yirgacheffe/backends → yirgacheffe-1.4.0/yirgacheffe/_backends}/numpy.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/constants.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/layers/area.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe/rounding.py +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe.egg-info/dependency_links.txt +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe.egg-info/entry_points.txt +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe.egg-info/requires.txt +0 -0
- {yirgacheffe-1.3.3 → yirgacheffe-1.4.0}/yirgacheffe.egg-info/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "yirgacheffe"
|
|
9
|
-
version = "1.
|
|
9
|
+
version = "1.4.0"
|
|
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" }]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
# I've no idea why pylint dislikes this particular import but accepts
|
|
4
|
+
# other entries in the module.
|
|
5
|
+
from yirgacheffe.window import Area # pylint: disable=E0401, E0611
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
"lhs,rhs,is_equal,overlaps",
|
|
9
|
+
[
|
|
10
|
+
# Obvious equality
|
|
11
|
+
(Area(-10.0, 10.0, 10.0, -10.0), Area(-10.0, 10.0, 10.0, -10.0), True, True),
|
|
12
|
+
(Area(-9.0, 9.0, 9.0, -9.0), Area(-10.0, 10.0, 10.0, -10.0), False, True), # subset
|
|
13
|
+
(Area(-9.0, 9.0, -1.0, 1.0), Area(1.0, -1.0, 9.0, -9.0), False, False),
|
|
14
|
+
(Area(-10.0, 10.0, 1.0, -10.0), Area(-1.0, 10.0, 10.0, -10.0), False, True),
|
|
15
|
+
]
|
|
16
|
+
)
|
|
17
|
+
def test_area_operators(lhs: Area, rhs: Area, is_equal: bool, overlaps: bool) -> None:
|
|
18
|
+
assert (lhs == rhs) == is_equal
|
|
19
|
+
assert (lhs != rhs) == (not is_equal)
|
|
20
|
+
assert (lhs.overlaps(rhs)) == overlaps
|
|
21
|
+
assert (rhs.overlaps(lhs)) == overlaps
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import yirgacheffe
|
|
8
|
+
from tests.helpers import gdal_dataset_with_data, make_vectors_with_mutlile_ids
|
|
9
|
+
from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer
|
|
10
|
+
from yirgacheffe.window import Area
|
|
11
|
+
|
|
12
|
+
def test_add_windows() -> None:
|
|
13
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
14
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
15
|
+
|
|
16
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
17
|
+
layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
|
|
18
|
+
|
|
19
|
+
assert layer1.area != layer2.area
|
|
20
|
+
assert layer1.window != layer2.window
|
|
21
|
+
|
|
22
|
+
calc = layer1 + layer2
|
|
23
|
+
|
|
24
|
+
assert calc.area == layer2.area
|
|
25
|
+
assert calc.window == layer2.window
|
|
26
|
+
|
|
27
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
28
|
+
calc.save(result)
|
|
29
|
+
|
|
30
|
+
expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
31
|
+
actual = result.read_array(0, 0, 4, 4)
|
|
32
|
+
assert (expected == actual).all()
|
|
33
|
+
|
|
34
|
+
def test_multiply_windows() -> None:
|
|
35
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
36
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
37
|
+
|
|
38
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
39
|
+
layer2 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2))
|
|
40
|
+
|
|
41
|
+
assert layer1.area != layer2.area
|
|
42
|
+
assert layer1.window != layer2.window
|
|
43
|
+
|
|
44
|
+
calc = layer1 * layer2
|
|
45
|
+
|
|
46
|
+
assert calc.area == layer1.area
|
|
47
|
+
assert calc.window == layer1.window
|
|
48
|
+
|
|
49
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
50
|
+
calc.save(result)
|
|
51
|
+
|
|
52
|
+
expected = np.array([[10, 40], [150, 240]])
|
|
53
|
+
actual = result.read_array(0, 0, 2, 2)
|
|
54
|
+
assert (expected == actual).all()
|
|
55
|
+
|
|
56
|
+
def test_add_windows_offset() -> None:
|
|
57
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
58
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
59
|
+
|
|
60
|
+
layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
|
|
61
|
+
layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
|
|
62
|
+
|
|
63
|
+
assert layer1.area != layer2.area
|
|
64
|
+
assert layer1.window != layer2.window
|
|
65
|
+
|
|
66
|
+
calc = layer1 + layer2
|
|
67
|
+
|
|
68
|
+
assert calc.area == layer2.area
|
|
69
|
+
|
|
70
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
71
|
+
calc.save(result)
|
|
72
|
+
|
|
73
|
+
expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
|
|
74
|
+
actual = result.read_array(0, 0, 4, 4)
|
|
75
|
+
assert (expected == actual).all()
|
|
76
|
+
|
|
77
|
+
def test_multiply_windows_offset() -> None:
|
|
78
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
79
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
80
|
+
|
|
81
|
+
layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
|
|
82
|
+
layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
|
|
83
|
+
|
|
84
|
+
assert layer1.area != layer2.area
|
|
85
|
+
assert layer1.window != layer2.window
|
|
86
|
+
|
|
87
|
+
calc = layer1 * layer2
|
|
88
|
+
|
|
89
|
+
assert calc.area == layer1.area
|
|
90
|
+
|
|
91
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
92
|
+
calc.save(result)
|
|
93
|
+
|
|
94
|
+
expected = np.array([[60, 140], [300, 440]])
|
|
95
|
+
actual = result.read_array(0, 0, 2, 2)
|
|
96
|
+
assert (expected == actual).all()
|
|
97
|
+
|
|
98
|
+
def test_add_windows_sum() -> None:
|
|
99
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
100
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
101
|
+
|
|
102
|
+
layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
|
|
103
|
+
layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
|
|
104
|
+
|
|
105
|
+
calc = layer1 + layer2
|
|
106
|
+
total = calc.sum()
|
|
107
|
+
|
|
108
|
+
expected = np.array([[10, 20, 30, 40], [50, 61, 72, 80], [90, 103, 114, 120], [130, 140, 150, 160]])
|
|
109
|
+
assert total == np.sum(expected)
|
|
110
|
+
|
|
111
|
+
def test_multiply_windows_sum() -> None:
|
|
112
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
113
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
114
|
+
|
|
115
|
+
layer1 = RasterLayer(gdal_dataset_with_data((-0.02, 0.02), 0.02, data1))
|
|
116
|
+
layer2 = RasterLayer(gdal_dataset_with_data((-0.04, 0.04), 0.02, data2))
|
|
117
|
+
|
|
118
|
+
calc = layer1 * layer2
|
|
119
|
+
total = calc.sum()
|
|
120
|
+
|
|
121
|
+
expected = np.array([[60, 140], [300, 440]])
|
|
122
|
+
assert total == np.sum(expected)
|
|
123
|
+
|
|
124
|
+
def test_constant_layer_result_rhs_add() -> None:
|
|
125
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
126
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
127
|
+
const_layer = ConstantLayer(1.0)
|
|
128
|
+
|
|
129
|
+
calc = layer1 + const_layer
|
|
130
|
+
|
|
131
|
+
assert calc.area == layer1.area
|
|
132
|
+
|
|
133
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
134
|
+
calc.save(result)
|
|
135
|
+
actual = result.read_array(0, 0, 4, 2)
|
|
136
|
+
|
|
137
|
+
expected = 1.0 + data1
|
|
138
|
+
|
|
139
|
+
assert (expected == actual).all()
|
|
140
|
+
|
|
141
|
+
def test_constant_layer_result_lhs_add() -> None:
|
|
142
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
143
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
144
|
+
const_layer = ConstantLayer(1.0)
|
|
145
|
+
result = RasterLayer.empty_raster_layer_like(layer1)
|
|
146
|
+
|
|
147
|
+
intersection = RasterLayer.find_intersection([layer1, const_layer])
|
|
148
|
+
const_layer.set_window_for_intersection(intersection)
|
|
149
|
+
layer1.set_window_for_intersection(intersection)
|
|
150
|
+
|
|
151
|
+
calc = const_layer + layer1
|
|
152
|
+
|
|
153
|
+
assert calc.area == layer1.area
|
|
154
|
+
|
|
155
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
156
|
+
calc.save(result)
|
|
157
|
+
actual = result.read_array(0, 0, 4, 2)
|
|
158
|
+
|
|
159
|
+
expected = 1.0 + data1
|
|
160
|
+
|
|
161
|
+
assert (expected == actual).all()
|
|
162
|
+
|
|
163
|
+
def test_constant_layer_result_rhs_multiply() -> None:
|
|
164
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
165
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
166
|
+
const_layer = ConstantLayer(2.0)
|
|
167
|
+
|
|
168
|
+
calc = layer1 * const_layer
|
|
169
|
+
|
|
170
|
+
assert calc.area == layer1.area
|
|
171
|
+
|
|
172
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
173
|
+
calc.save(result)
|
|
174
|
+
actual = result.read_array(0, 0, 4, 2)
|
|
175
|
+
|
|
176
|
+
expected = data1 * 2.0
|
|
177
|
+
|
|
178
|
+
assert (expected == actual).all()
|
|
179
|
+
|
|
180
|
+
def test_constant_layer_result_lhs_multiply() -> None:
|
|
181
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
182
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
183
|
+
const_layer = ConstantLayer(2.0)
|
|
184
|
+
result = RasterLayer.empty_raster_layer_like(layer1)
|
|
185
|
+
|
|
186
|
+
intersection = RasterLayer.find_intersection([layer1, const_layer])
|
|
187
|
+
const_layer.set_window_for_intersection(intersection)
|
|
188
|
+
layer1.set_window_for_intersection(intersection)
|
|
189
|
+
|
|
190
|
+
calc = const_layer * layer1
|
|
191
|
+
|
|
192
|
+
assert calc.area == layer1.area
|
|
193
|
+
|
|
194
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
195
|
+
calc.save(result)
|
|
196
|
+
actual = result.read_array(0, 0, 4, 2)
|
|
197
|
+
|
|
198
|
+
expected = 2.0 * data1
|
|
199
|
+
|
|
200
|
+
assert (expected == actual).all()
|
|
201
|
+
|
|
202
|
+
def test_vector_layers_add() -> None:
|
|
203
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
204
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 1.0, data1))
|
|
205
|
+
|
|
206
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
207
|
+
path = os.path.join(tempdir, "test.gpkg")
|
|
208
|
+
areas = {
|
|
209
|
+
(Area(-10.0, 10.0, 0.0, 0.0), 42),
|
|
210
|
+
(Area(0.0, 0.0, 10, -10), 43)
|
|
211
|
+
}
|
|
212
|
+
make_vectors_with_mutlile_ids(areas, path)
|
|
213
|
+
|
|
214
|
+
burn_value = 2
|
|
215
|
+
layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
|
|
216
|
+
layer2_total = layer2.sum()
|
|
217
|
+
assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
|
|
218
|
+
|
|
219
|
+
calc = layer1 + layer2
|
|
220
|
+
|
|
221
|
+
assert calc.area == layer2.area
|
|
222
|
+
|
|
223
|
+
total = calc.sum()
|
|
224
|
+
assert total == layer2_total + np.sum(data1)
|
|
225
|
+
|
|
226
|
+
def test_vector_layers_multiply() -> None:
|
|
227
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
228
|
+
layer1 = RasterLayer(gdal_dataset_with_data((-1.0, 1.0), 1.0, data1))
|
|
229
|
+
|
|
230
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
231
|
+
path = os.path.join(tempdir, "test.gpkg")
|
|
232
|
+
areas = {
|
|
233
|
+
(Area(-10.0, 10.0, 0.0, 0.0), 42),
|
|
234
|
+
(Area(0.0, 0.0, 10, -10), 43)
|
|
235
|
+
}
|
|
236
|
+
make_vectors_with_mutlile_ids(areas, path)
|
|
237
|
+
|
|
238
|
+
burn_value = 2
|
|
239
|
+
layer2 = VectorLayer.layer_from_file(path, None, layer1.pixel_scale, layer1.projection, burn_value=burn_value)
|
|
240
|
+
layer2_total = layer2.sum()
|
|
241
|
+
assert layer2_total == ((layer2.window.xsize * layer2.window.ysize) / 2) * burn_value
|
|
242
|
+
|
|
243
|
+
calc = layer1 * layer2
|
|
244
|
+
|
|
245
|
+
assert calc.area == layer1.area
|
|
246
|
+
|
|
247
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
248
|
+
calc.save(result)
|
|
249
|
+
actual = result.read_array(0, 0, 2, 2)
|
|
250
|
+
|
|
251
|
+
expected = np.array([[2, 0], [0, 8]])
|
|
252
|
+
assert (expected == actual).all()
|
|
253
|
+
|
|
254
|
+
@pytest.mark.skipif(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
255
|
+
def test_parallel_save_windows() -> None:
|
|
256
|
+
data1 = np.array([[1, 2], [3, 4]])
|
|
257
|
+
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
258
|
+
|
|
259
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
260
|
+
layer1_filename = os.path.join(tempdir, "layer1.tif")
|
|
261
|
+
layer1_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1, filename=layer1_filename)
|
|
262
|
+
layer1_dataset.Close()
|
|
263
|
+
|
|
264
|
+
layer2_filename = os.path.join(tempdir, "layer2.tif")
|
|
265
|
+
layer2_dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data2, filename=layer2_filename)
|
|
266
|
+
layer2_dataset.Close()
|
|
267
|
+
|
|
268
|
+
layer1 = RasterLayer.layer_from_file(layer1_filename)
|
|
269
|
+
layer2 = RasterLayer.layer_from_file(layer2_filename)
|
|
270
|
+
|
|
271
|
+
assert layer1.area != layer2.area
|
|
272
|
+
assert layer1.window != layer2.window
|
|
273
|
+
|
|
274
|
+
calc = layer1 + layer2
|
|
275
|
+
|
|
276
|
+
assert calc.area == layer2.area
|
|
277
|
+
assert calc.window == layer2.window
|
|
278
|
+
|
|
279
|
+
result = RasterLayer.empty_raster_layer_like(calc)
|
|
280
|
+
calc.parallel_save(result)
|
|
281
|
+
|
|
282
|
+
expected = np.array([[11, 22, 30, 40], [53, 64, 70, 80], [90, 100, 110, 120], [130, 140, 150, 160]])
|
|
283
|
+
actual = result.read_array(0, 0, 4, 4)
|
|
284
|
+
assert (expected == actual).all()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
import yirgacheffe
|
|
4
|
+
from yirgacheffe.layers import RasterLayer, ConstantLayer
|
|
5
|
+
from yirgacheffe.operators import DataType
|
|
6
|
+
from yirgacheffe.window import Area, PixelScale
|
|
7
|
+
|
|
8
|
+
def test_constant_save() -> None:
|
|
9
|
+
area = Area(left=-1.0, right=1.0, top=1.0, bottom=-1.0)
|
|
10
|
+
scale = PixelScale(0.1, -0.1)
|
|
11
|
+
with RasterLayer.empty_raster_layer(area, scale, DataType.Float32) as result:
|
|
12
|
+
with ConstantLayer(42.0) as c:
|
|
13
|
+
c.save(result)
|
|
14
|
+
|
|
15
|
+
expected = np.full((20, 20), 42.0)
|
|
16
|
+
actual = result.read_array(0, 0, 20, 20)
|
|
17
|
+
|
|
18
|
+
assert (expected == actual).all()
|
|
19
|
+
|
|
20
|
+
def test_constant_parallel_save(monkeypatch) -> None:
|
|
21
|
+
area = Area(left=-1.0, right=1.0, top=1.0, bottom=-1.0)
|
|
22
|
+
scale = PixelScale(0.1, -0.1)
|
|
23
|
+
with RasterLayer.empty_raster_layer(area, scale, DataType.Float32) as result:
|
|
24
|
+
with ConstantLayer(42.0) as c:
|
|
25
|
+
with monkeypatch.context() as m:
|
|
26
|
+
m.setattr(yirgacheffe.constants, "YSTEP", 1)
|
|
27
|
+
c.parallel_save(result)
|
|
28
|
+
|
|
29
|
+
expected = np.full((20, 20), 42.0)
|
|
30
|
+
actual = result.read_array(0, 0, 20, 20)
|
|
31
|
+
|
|
32
|
+
assert (expected == actual).all()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pytest
|
|
4
|
+
from osgeo import gdal
|
|
5
|
+
|
|
6
|
+
from yirgacheffe.operators import DataType
|
|
7
|
+
from yirgacheffe._backends import backend, BACKEND
|
|
8
|
+
from yirgacheffe.layers import RasterLayer
|
|
9
|
+
|
|
10
|
+
from tests.helpers import gdal_dataset_with_data
|
|
11
|
+
|
|
12
|
+
@pytest.mark.parametrize("gtype", [
|
|
13
|
+
gdal.GDT_Int8,
|
|
14
|
+
gdal.GDT_Int16,
|
|
15
|
+
gdal.GDT_Int32,
|
|
16
|
+
gdal.GDT_Int64,
|
|
17
|
+
gdal.GDT_Byte,
|
|
18
|
+
gdal.GDT_UInt16,
|
|
19
|
+
gdal.GDT_UInt32,
|
|
20
|
+
gdal.GDT_UInt64,
|
|
21
|
+
gdal.GDT_Float32,
|
|
22
|
+
])
|
|
23
|
+
def test_round_trip(gtype) -> None:
|
|
24
|
+
ytype = DataType.of_gdal(gtype)
|
|
25
|
+
backend_type = backend.dtype_to_backed(ytype)
|
|
26
|
+
assert backend.backend_to_dtype(backend_type) == ytype
|
|
27
|
+
|
|
28
|
+
@pytest.mark.parametrize("ytype", [
|
|
29
|
+
DataType.Int8,
|
|
30
|
+
DataType.Int16,
|
|
31
|
+
DataType.Int32,
|
|
32
|
+
DataType.Int64,
|
|
33
|
+
DataType.UInt8,
|
|
34
|
+
DataType.UInt16,
|
|
35
|
+
DataType.UInt32,
|
|
36
|
+
DataType.UInt64,
|
|
37
|
+
DataType.Float32,
|
|
38
|
+
DataType.Float64,
|
|
39
|
+
])
|
|
40
|
+
def test_round_trip_from_gdal(ytype) -> None:
|
|
41
|
+
gtype = ytype.to_gdal()
|
|
42
|
+
assert DataType.of_gdal(gtype) == ytype
|
|
43
|
+
|
|
44
|
+
def test_round_trip_float64() -> None:
|
|
45
|
+
backend_type = backend.dtype_to_backed(DataType.Float64)
|
|
46
|
+
ytype = backend.backend_to_dtype(backend_type)
|
|
47
|
+
print(BACKEND, "sad")
|
|
48
|
+
match BACKEND:
|
|
49
|
+
case "NUMPY":
|
|
50
|
+
assert ytype == DataType.Float64
|
|
51
|
+
case "MLX":
|
|
52
|
+
assert ytype == DataType.Float32
|
|
53
|
+
|
|
54
|
+
def test_float_to_int() -> None:
|
|
55
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.5, 6.5, 7.5, 8.5]])
|
|
56
|
+
|
|
57
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
58
|
+
# Note the float 32 here is to rule out that writing the result to the
|
|
59
|
+
# new dataset was what caused the truncation
|
|
60
|
+
result = RasterLayer.empty_raster_layer_like(layer1, datatype=DataType.Float32)
|
|
61
|
+
|
|
62
|
+
comp = layer1.astype(DataType.UInt8)
|
|
63
|
+
comp.save(result)
|
|
64
|
+
|
|
65
|
+
expected = backend.promote(np.array([[1, 2, 3, 4], [5, 6, 7, 8]]))
|
|
66
|
+
actual = backend.demote_array(result.read_array(0, 0, 4, 2))
|
|
67
|
+
assert (expected == actual).all()
|
|
@@ -5,7 +5,7 @@ import tempfile
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
|
-
from helpers import gdal_dataset_of_region, gdal_dataset_with_data, make_vectors_with_id, generate_child_tile
|
|
8
|
+
from tests.helpers import gdal_dataset_of_region, gdal_dataset_with_data, make_vectors_with_id, generate_child_tile
|
|
9
9
|
from yirgacheffe import WGS_84_PROJECTION
|
|
10
10
|
from yirgacheffe.layers import GroupLayer, RasterLayer, TiledGroupLayer, VectorLayer
|
|
11
11
|
from yirgacheffe.window import Area, PixelScale, Window
|
|
@@ -35,7 +35,7 @@ def test_valid_file_list():
|
|
|
35
35
|
assert group.area == area
|
|
36
36
|
assert group.window == Window(0, 0, 100, 100)
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def test_valid_file_list_from_dir():
|
|
39
39
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
40
40
|
path = os.path.join(tempdir, "test.tif")
|
|
41
41
|
area = Area(-10, 10, 10, -10)
|
|
@@ -221,8 +221,8 @@ def test_with_window_adjust(klass):
|
|
|
221
221
|
|
|
222
222
|
# Test before we apply a window
|
|
223
223
|
row = group.read_array(0, 0, 100, 1)[0]
|
|
224
|
-
for idx in
|
|
225
|
-
assert
|
|
224
|
+
for idx, val in enumerate(row):
|
|
225
|
+
assert val == math.ceil((idx + 1) / 10.0)
|
|
226
226
|
|
|
227
227
|
# Test also for manual offsets that we get expected result
|
|
228
228
|
for idx in range(0, 10):
|
|
@@ -6,8 +6,10 @@ from osgeo import gdal
|
|
|
6
6
|
from yirgacheffe import WGS_84_PROJECTION
|
|
7
7
|
from yirgacheffe.layers import RasterLayer, H3CellLayer
|
|
8
8
|
from yirgacheffe.window import Area, PixelScale
|
|
9
|
-
from yirgacheffe.
|
|
10
|
-
|
|
9
|
+
from yirgacheffe._backends import backend
|
|
10
|
+
|
|
11
|
+
# work around of pylint
|
|
12
|
+
demote_array = backend.demote_array
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
@pytest.mark.parametrize(
|
|
@@ -135,10 +137,10 @@ def test_h3_layer_clipped(lat: float, lng: float) -> None:
|
|
|
135
137
|
|
|
136
138
|
# whilst we're here, check that we do have an filled border (i.e., does window for
|
|
137
139
|
# intersection do the right thing)
|
|
138
|
-
assert np.sum(
|
|
139
|
-
assert np.sum(
|
|
140
|
-
assert np.sum(
|
|
141
|
-
assert np.sum(
|
|
140
|
+
assert np.sum(demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 5))) > 0.0
|
|
141
|
+
assert np.sum(demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 5, h3_layer.window.xsize, 5))) > 0.0
|
|
142
|
+
assert np.sum(demote_array(h3_layer.read_array(0, 0, 5, h3_layer.window.ysize))) > 0.0
|
|
143
|
+
assert np.sum(demote_array(h3_layer.read_array(h3_layer.window.xsize - 5, 0, 5, h3_layer.window.ysize))) > 0.0
|
|
142
144
|
|
|
143
145
|
@pytest.mark.parametrize(
|
|
144
146
|
"lat,lng",
|
|
@@ -189,8 +191,8 @@ def test_h3_layer_wrapped_on_projection(lat: float, lng: float) -> None:
|
|
|
189
191
|
assert expanded_area == area
|
|
190
192
|
|
|
191
193
|
# whilst we're here, check that we do have an empty border (i.e., does window for union do the right thing)
|
|
192
|
-
assert np.sum(
|
|
193
|
-
assert np.sum(
|
|
194
|
+
assert np.sum(demote_array(h3_layer.read_array(0, 0, h3_layer.window.xsize, 2))) == 0.0
|
|
195
|
+
assert np.sum(demote_array(h3_layer.read_array(0, h3_layer.window.ysize - 2, h3_layer.window.xsize, 2))) == 0.0
|
|
194
196
|
|
|
195
197
|
def test_h3_layer_overlapped():
|
|
196
198
|
# This is based on a regression, where somehow I made tiles not tesselate properly
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from osgeo import gdal
|
|
3
3
|
|
|
4
|
-
from helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
|
|
4
|
+
from tests.helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
|
|
5
5
|
from yirgacheffe.window import Area, PixelScale, Window
|
|
6
|
-
from yirgacheffe.layers import RasterLayer, ConstantLayer
|
|
7
|
-
from yirgacheffe.h3layer import H3CellLayer
|
|
6
|
+
from yirgacheffe.layers import RasterLayer, ConstantLayer, H3CellLayer
|
|
8
7
|
from yirgacheffe import WGS_84_PROJECTION
|
|
9
8
|
|
|
10
9
|
|
|
@@ -4,7 +4,7 @@ import tempfile
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from osgeo import gdal
|
|
6
6
|
|
|
7
|
-
from helpers import gdal_dataset_with_data
|
|
7
|
+
from tests.helpers import gdal_dataset_with_data
|
|
8
8
|
from yirgacheffe.layers import RasterLayer
|
|
9
9
|
from yirgacheffe.window import Area, PixelScale
|
|
10
10
|
|
|
@@ -52,7 +52,7 @@ def test_stack_tifs_with_area_match() -> None:
|
|
|
52
52
|
for layer in source_layers:
|
|
53
53
|
layer.set_window_for_intersection(intersection)
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
layer = source_layers[-1]
|
|
56
56
|
assert layer.window.xsize == 100 - (bands - 1)
|
|
57
57
|
assert layer.window.ysize == 100 - (bands - 1)
|
|
58
58
|
|
|
@@ -5,13 +5,12 @@ import tempfile
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pytest
|
|
7
7
|
import torch
|
|
8
|
-
from osgeo import gdal
|
|
9
8
|
|
|
10
|
-
from helpers import gdal_dataset_with_data
|
|
11
9
|
import yirgacheffe
|
|
12
10
|
from yirgacheffe.layers import RasterLayer, ConstantLayer
|
|
13
11
|
from yirgacheffe.operators import LayerOperation, DataType
|
|
14
|
-
from yirgacheffe.
|
|
12
|
+
from yirgacheffe._backends import backend
|
|
13
|
+
from tests.helpers import gdal_dataset_with_data
|
|
15
14
|
|
|
16
15
|
def test_add_byte_layers() -> None:
|
|
17
16
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
|
|
@@ -71,7 +70,7 @@ def test_add_byte_layers_with_callback(skip, expected_steps) -> None:
|
|
|
71
70
|
|
|
72
71
|
comp = layer1 + layer2
|
|
73
72
|
comp.ystep = skip
|
|
74
|
-
comp.save(result, callback=
|
|
73
|
+
comp.save(result, callback=callback_possitions.append)
|
|
75
74
|
|
|
76
75
|
expected = data1 + data2
|
|
77
76
|
actual = result.read_array(0, 0, 4, 2)
|
|
@@ -585,7 +584,7 @@ def test_direct_layer_save_and_sum() -> None:
|
|
|
585
584
|
assert (data1 == actual_data).all()
|
|
586
585
|
assert expected_sum == actual_sum
|
|
587
586
|
|
|
588
|
-
@pytest.mark.skipif(yirgacheffe.
|
|
587
|
+
@pytest.mark.skipif(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
589
588
|
def test_add_to_float_layer_by_np_array() -> None:
|
|
590
589
|
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
591
590
|
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
@@ -620,7 +619,7 @@ def test_write_mulitband_raster() -> None:
|
|
|
620
619
|
|
|
621
620
|
assert (expected == actual).all()
|
|
622
621
|
|
|
623
|
-
@pytest.mark.skipif(yirgacheffe.
|
|
622
|
+
@pytest.mark.skipif(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
624
623
|
def test_save_and_sum_float32(monkeypatch) -> None:
|
|
625
624
|
random.seed(42)
|
|
626
625
|
data = []
|
|
@@ -644,7 +643,7 @@ def test_save_and_sum_float32(monkeypatch) -> None:
|
|
|
644
643
|
actual = layer1.save(store, and_sum=True)
|
|
645
644
|
assert expected == actual
|
|
646
645
|
|
|
647
|
-
@pytest.mark.skipif(yirgacheffe.
|
|
646
|
+
@pytest.mark.skipif(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
648
647
|
def test_parallel_save_and_sum_float32(monkeypatch) -> None:
|
|
649
648
|
random.seed(42)
|
|
650
649
|
data = []
|
|
@@ -672,7 +671,7 @@ def test_parallel_save_and_sum_float32(monkeypatch) -> None:
|
|
|
672
671
|
actual = layer1.parallel_save(store, and_sum=True)
|
|
673
672
|
assert expected == actual
|
|
674
673
|
|
|
675
|
-
@pytest.mark.skipif(yirgacheffe.
|
|
674
|
+
@pytest.mark.skipif(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
676
675
|
def test_sum_float32(monkeypatch) -> None:
|
|
677
676
|
random.seed(42)
|
|
678
677
|
data = []
|
|
@@ -4,8 +4,7 @@ import numpy as np
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
6
|
from yirgacheffe import WGS_84_PROJECTION
|
|
7
|
-
from yirgacheffe.
|
|
8
|
-
from yirgacheffe.layers import PixelScale, ConstantLayer, RasterLayer
|
|
7
|
+
from yirgacheffe.layers import PixelScale, RasterLayer, H3CellLayer
|
|
9
8
|
from yirgacheffe.window import Area
|
|
10
9
|
import yirgacheffe.operators as yo
|
|
11
10
|
|
|
@@ -14,7 +13,7 @@ class NaiveH3CellLayer(H3CellLayer):
|
|
|
14
13
|
so the H3CellLayer has a bunch of tricks to try reduce the work done. This is a naive
|
|
15
14
|
version that checks for every cell."""
|
|
16
15
|
|
|
17
|
-
def read_array(self, xoffset, yoffset, xsize, ysize):
|
|
16
|
+
def read_array(self, xoffset, yoffset, xsize, ysize): # pylint: disable=W0237
|
|
18
17
|
res = np.zeros((ysize, xsize), dtype=float)
|
|
19
18
|
start_x = self._active_area.left + (xoffset * self._pixel_scale.xstep)
|
|
20
19
|
start_y = self._active_area.top + (yoffset * self._pixel_scale.ystep)
|