yirgacheffe 1.6.1__tar.gz → 1.7.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.6.1/yirgacheffe.egg-info → yirgacheffe-1.7.0}/PKG-INFO +11 -9
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/README.md +8 -8
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/pyproject.toml +7 -1
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_base.py +7 -13
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_h3layer.py +32 -18
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_intersection.py +5 -5
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_multiband.py +1 -1
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_openers.py +33 -5
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_operators.py +60 -2
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_optimisation.py +26 -24
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_pickle.py +2 -2
- yirgacheffe-1.7.0/tests/test_projection.py +32 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_raster.py +3 -3
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_rescaling.py +26 -21
- yirgacheffe-1.7.0/yirgacheffe/__init__.py +18 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/_core.py +10 -12
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/area.py +4 -4
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/base.py +99 -62
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/constant.py +3 -3
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/group.py +5 -7
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/h3layer.py +17 -17
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/rasters.py +14 -15
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/rescaled.py +12 -9
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/vectors.py +126 -45
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/operators.py +152 -39
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/window.py +41 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0/yirgacheffe.egg-info}/PKG-INFO +11 -9
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe.egg-info/SOURCES.txt +1 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe.egg-info/requires.txt +2 -0
- yirgacheffe-1.6.1/yirgacheffe/__init__.py +0 -11
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/LICENSE +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/MANIFEST.in +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/setup.cfg +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_area.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_auto_windowing.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_constants.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_datatypes.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_group.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_nodata.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_parallel_operators.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_rounding.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_save_with_window.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_sum_with_window.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_uniform_area_layer.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_union.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_vectors.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/tests/test_window.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/_backends/__init__.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/_backends/enumeration.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/_backends/mlx.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/_backends/numpy.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/constants.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/layers/__init__.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe/rounding.py +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe.egg-info/dependency_links.txt +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe.egg-info/entry_points.txt +0 -0
- {yirgacheffe-1.6.1 → yirgacheffe-1.7.0}/yirgacheffe.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yirgacheffe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
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
|
|
@@ -14,6 +14,8 @@ Requires-Dist: gdal[numpy]
|
|
|
14
14
|
Requires-Dist: scikit-image
|
|
15
15
|
Requires-Dist: torch
|
|
16
16
|
Requires-Dist: dill
|
|
17
|
+
Requires-Dist: deprecation
|
|
18
|
+
Requires-Dist: tomli
|
|
17
19
|
Provides-Extra: dev
|
|
18
20
|
Requires-Dist: mypy; extra == "dev"
|
|
19
21
|
Requires-Dist: pylint; extra == "dev"
|
|
@@ -57,7 +59,7 @@ import yirgaceffe as yg
|
|
|
57
59
|
|
|
58
60
|
habitat_map = yg.read_raster("habitats.tif")
|
|
59
61
|
elevation_map = yg.read_raster('elevation.tif')
|
|
60
|
-
range_polygon = yg.
|
|
62
|
+
range_polygon = yg.read_shape('species123.geojson')
|
|
61
63
|
area_per_pixel_map = yg.read_raster('area_per_pixel.tif')
|
|
62
64
|
|
|
63
65
|
refined_habitat = habitat_map.isin([...species habitat codes...])
|
|
@@ -177,22 +179,22 @@ with VectorLayer.layer_from_file('range.gpkg', PixelScale(0.001, -0.001), WGS_84
|
|
|
177
179
|
...
|
|
178
180
|
```
|
|
179
181
|
|
|
180
|
-
The new 2.0 way of doing this is:
|
|
182
|
+
The new 2.0 way of doing this is, if you plan to use the vector layer in calculation with other raster layers that will have projection information:
|
|
181
183
|
|
|
182
184
|
```python
|
|
183
185
|
import yirgacheffe as yg
|
|
184
186
|
|
|
185
|
-
with yg.read_shape('range.gpkg'
|
|
187
|
+
with yg.read_shape('range.gpkg') as layer:
|
|
186
188
|
...
|
|
187
189
|
```
|
|
188
190
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
Of if you plan to use the layer on its own and want to specify a rasterisation projection you can do:
|
|
191
192
|
|
|
192
193
|
```python
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
import yirgacheffe as yg
|
|
195
|
+
|
|
196
|
+
with yg.read_shape('range.gpkg', (yg.WGS_84_PROJECTION, (0.001, -0.001))) as layer:
|
|
197
|
+
...
|
|
196
198
|
```
|
|
197
199
|
|
|
198
200
|
### GroupLayer
|
|
@@ -32,7 +32,7 @@ import yirgaceffe as yg
|
|
|
32
32
|
|
|
33
33
|
habitat_map = yg.read_raster("habitats.tif")
|
|
34
34
|
elevation_map = yg.read_raster('elevation.tif')
|
|
35
|
-
range_polygon = yg.
|
|
35
|
+
range_polygon = yg.read_shape('species123.geojson')
|
|
36
36
|
area_per_pixel_map = yg.read_raster('area_per_pixel.tif')
|
|
37
37
|
|
|
38
38
|
refined_habitat = habitat_map.isin([...species habitat codes...])
|
|
@@ -152,22 +152,22 @@ with VectorLayer.layer_from_file('range.gpkg', PixelScale(0.001, -0.001), WGS_84
|
|
|
152
152
|
...
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
The new 2.0 way of doing this is:
|
|
155
|
+
The new 2.0 way of doing this is, if you plan to use the vector layer in calculation with other raster layers that will have projection information:
|
|
156
156
|
|
|
157
157
|
```python
|
|
158
158
|
import yirgacheffe as yg
|
|
159
159
|
|
|
160
|
-
with yg.read_shape('range.gpkg'
|
|
160
|
+
with yg.read_shape('range.gpkg') as layer:
|
|
161
161
|
...
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
Of if you plan to use the layer on its own and want to specify a rasterisation projection you can do:
|
|
166
165
|
|
|
167
166
|
```python
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
import yirgacheffe as yg
|
|
168
|
+
|
|
169
|
+
with yg.read_shape('range.gpkg', (yg.WGS_84_PROJECTION, (0.001, -0.001))) as layer:
|
|
170
|
+
...
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
### GroupLayer
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "yirgacheffe"
|
|
9
|
-
version = "1.
|
|
9
|
+
version = "1.7.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" }]
|
|
@@ -18,6 +18,8 @@ dependencies = [
|
|
|
18
18
|
"scikit-image",
|
|
19
19
|
"torch",
|
|
20
20
|
"dill",
|
|
21
|
+
"deprecation",
|
|
22
|
+
"tomli"
|
|
21
23
|
]
|
|
22
24
|
requires-python = ">=3.10"
|
|
23
25
|
|
|
@@ -37,3 +39,7 @@ ignore_missing_imports = true
|
|
|
37
39
|
[[tool.mypy.overrides]]
|
|
38
40
|
module = "h3.*"
|
|
39
41
|
ignore_missing_imports = true
|
|
42
|
+
|
|
43
|
+
[[tool.mypy.overrides]]
|
|
44
|
+
module = "deprecation.*"
|
|
45
|
+
ignore_missing_imports = true
|
|
@@ -5,13 +5,12 @@ import pytest
|
|
|
5
5
|
|
|
6
6
|
from yirgacheffe import WGS_84_PROJECTION
|
|
7
7
|
from yirgacheffe.layers import YirgacheffeLayer
|
|
8
|
-
from yirgacheffe.window import Area,
|
|
8
|
+
from yirgacheffe.window import Area, MapProjection
|
|
9
9
|
|
|
10
10
|
def test_pixel_to_latlng_unsupported_projection() -> None:
|
|
11
11
|
layer = YirgacheffeLayer(
|
|
12
12
|
Area(-10, 10, 10, -10),
|
|
13
|
-
|
|
14
|
-
"OTHER PROJECTION"
|
|
13
|
+
MapProjection("OTHER PROJECTION", 0.02, -0.02),
|
|
15
14
|
)
|
|
16
15
|
with pytest.raises(NotImplementedError):
|
|
17
16
|
_ = layer.latlng_for_pixel(10, 10)
|
|
@@ -19,8 +18,7 @@ def test_pixel_to_latlng_unsupported_projection() -> None:
|
|
|
19
18
|
def test_pixel_from_latlng_unsupported_projection() -> None:
|
|
20
19
|
layer = YirgacheffeLayer(
|
|
21
20
|
Area(-10, 10, 10, -10),
|
|
22
|
-
|
|
23
|
-
"OTHER PROJECTION"
|
|
21
|
+
MapProjection("OTHER PROJECTION", 0.02, -0.02),
|
|
24
22
|
)
|
|
25
23
|
with pytest.raises(NotImplementedError):
|
|
26
24
|
_ = layer.pixel_for_latlng(10.0, 10.0)
|
|
@@ -63,8 +61,7 @@ def test_pixel_from_latlng_unsupported_projection() -> None:
|
|
|
63
61
|
def test_latlng_for_pixel(area: Area, pixel: Tuple[int,int], expected: Tuple[float,float]) -> None:
|
|
64
62
|
layer = YirgacheffeLayer(
|
|
65
63
|
area,
|
|
66
|
-
|
|
67
|
-
WGS_84_PROJECTION
|
|
64
|
+
MapProjection(WGS_84_PROJECTION, 0.2, -0.2),
|
|
68
65
|
)
|
|
69
66
|
result = layer.latlng_for_pixel(*pixel)
|
|
70
67
|
assert math.isclose(result[0], expected[0])
|
|
@@ -93,8 +90,7 @@ def test_latlng_for_pixel(area: Area, pixel: Tuple[int,int], expected: Tuple[flo
|
|
|
93
90
|
def test_pixel_for_latlng(area: Area, coord: Tuple[float,float], expected: Tuple[int,int]) -> None:
|
|
94
91
|
layer = YirgacheffeLayer(
|
|
95
92
|
area,
|
|
96
|
-
|
|
97
|
-
WGS_84_PROJECTION
|
|
93
|
+
MapProjection(WGS_84_PROJECTION, 0.2, -0.2),
|
|
98
94
|
)
|
|
99
95
|
result = layer.pixel_for_latlng(*coord)
|
|
100
96
|
assert result == expected
|
|
@@ -149,8 +145,7 @@ def test_latlng_for_pixel_with_intersection(
|
|
|
149
145
|
) -> None:
|
|
150
146
|
layer = YirgacheffeLayer(
|
|
151
147
|
area,
|
|
152
|
-
|
|
153
|
-
WGS_84_PROJECTION
|
|
148
|
+
MapProjection(WGS_84_PROJECTION, 0.2, -0.2),
|
|
154
149
|
)
|
|
155
150
|
layer.set_window_for_intersection(window)
|
|
156
151
|
result = layer.latlng_for_pixel(*pixel)
|
|
@@ -188,8 +183,7 @@ def test_pixel_for_latlng_with_intersection(
|
|
|
188
183
|
) -> None:
|
|
189
184
|
layer = YirgacheffeLayer(
|
|
190
185
|
area,
|
|
191
|
-
|
|
192
|
-
WGS_84_PROJECTION
|
|
186
|
+
MapProjection(WGS_84_PROJECTION, 0.2, -0.2),
|
|
193
187
|
)
|
|
194
188
|
layer.set_window_for_intersection(window)
|
|
195
189
|
result = layer.pixel_for_latlng(*coord)
|
|
@@ -5,7 +5,7 @@ from osgeo import gdal
|
|
|
5
5
|
|
|
6
6
|
from yirgacheffe import WGS_84_PROJECTION
|
|
7
7
|
from yirgacheffe.layers import RasterLayer, H3CellLayer
|
|
8
|
-
from yirgacheffe.window import Area,
|
|
8
|
+
from yirgacheffe.window import Area, MapProjection
|
|
9
9
|
from yirgacheffe._backends import backend
|
|
10
10
|
|
|
11
11
|
# work around of pylint
|
|
@@ -21,7 +21,7 @@ demote_array = backend.demote_array
|
|
|
21
21
|
)
|
|
22
22
|
def test_h3_layer(cell_id: str, is_valid: bool, expected_zoom: int) -> None:
|
|
23
23
|
if is_valid:
|
|
24
|
-
with H3CellLayer(cell_id,
|
|
24
|
+
with H3CellLayer(cell_id, MapProjection(WGS_84_PROJECTION, 0.001, -0.001)) as layer:
|
|
25
25
|
assert layer.zoom == expected_zoom
|
|
26
26
|
assert layer.projection == WGS_84_PROJECTION
|
|
27
27
|
|
|
@@ -35,7 +35,7 @@ def test_h3_layer(cell_id: str, is_valid: bool, expected_zoom: int) -> None:
|
|
|
35
35
|
assert one_count != 0
|
|
36
36
|
else:
|
|
37
37
|
with pytest.raises(ValueError):
|
|
38
|
-
with H3CellLayer(cell_id,
|
|
38
|
+
with H3CellLayer(cell_id, MapProjection(WGS_84_PROJECTION, 0.001, -0.001)) as _layer:
|
|
39
39
|
pass
|
|
40
40
|
|
|
41
41
|
@pytest.mark.parametrize(
|
|
@@ -53,8 +53,10 @@ def test_h3_layer(cell_id: str, is_valid: bool, expected_zoom: int) -> None:
|
|
|
53
53
|
def test_h3_layer_magnifications(lat: float, lng: float) -> None:
|
|
54
54
|
for zoom in range(6, 10):
|
|
55
55
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
56
|
-
h3_layer = H3CellLayer(
|
|
57
|
-
|
|
56
|
+
h3_layer = H3CellLayer(
|
|
57
|
+
cell_id,
|
|
58
|
+
MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
59
|
+
)
|
|
58
60
|
on_cell_count = h3_layer.sum()
|
|
59
61
|
total_count = h3_layer.window.xsize * h3_layer.window.ysize
|
|
60
62
|
assert 0 < on_cell_count < total_count
|
|
@@ -74,14 +76,18 @@ def test_h3_layer_magnifications(lat: float, lng: float) -> None:
|
|
|
74
76
|
def test_h3_layer_not_clipped(lat: float, lng: float) -> None:
|
|
75
77
|
for zoom in range(6, 10):
|
|
76
78
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
projection = MapProjection(
|
|
80
|
+
WGS_84_PROJECTION,
|
|
81
|
+
0.000898315284120,
|
|
82
|
+
-0.000898315284120
|
|
83
|
+
)
|
|
84
|
+
h3_layer = H3CellLayer(cell_id, projection)
|
|
79
85
|
|
|
80
86
|
on_cell_count = h3_layer.sum()
|
|
81
87
|
assert on_cell_count > 0.0
|
|
82
88
|
|
|
83
89
|
before_window = h3_layer.window
|
|
84
|
-
abs_xstep, abs_ystep = abs(
|
|
90
|
+
abs_xstep, abs_ystep = abs(projection.xstep), abs(projection.ystep)
|
|
85
91
|
expanded_area = Area(
|
|
86
92
|
left=h3_layer.area.left - (12 * abs_xstep),
|
|
87
93
|
top=h3_layer.area.top + (12 * abs_ystep),
|
|
@@ -115,14 +121,18 @@ def test_h3_layer_not_clipped(lat: float, lng: float) -> None:
|
|
|
115
121
|
def test_h3_layer_clipped(lat: float, lng: float) -> None:
|
|
116
122
|
for zoom in range(6, 8):
|
|
117
123
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
projection = MapProjection(
|
|
125
|
+
WGS_84_PROJECTION,
|
|
126
|
+
0.000898315284120,
|
|
127
|
+
-0.000898315284120
|
|
128
|
+
)
|
|
129
|
+
h3_layer = H3CellLayer(cell_id, projection)
|
|
120
130
|
|
|
121
131
|
on_cell_count = h3_layer.sum()
|
|
122
132
|
assert on_cell_count > 0.0
|
|
123
133
|
|
|
124
134
|
before_window = h3_layer.window
|
|
125
|
-
abs_xstep, abs_ystep = abs(
|
|
135
|
+
abs_xstep, abs_ystep = abs(projection.xstep), abs(projection.ystep)
|
|
126
136
|
expanded_area = Area(
|
|
127
137
|
left=h3_layer.area.left + (2 * abs_xstep),
|
|
128
138
|
top=h3_layer.area.top - (2 * abs_ystep),
|
|
@@ -151,8 +161,8 @@ def test_h3_layer_clipped(lat: float, lng: float) -> None:
|
|
|
151
161
|
)
|
|
152
162
|
def test_h3_layer_wrapped_on_projection(lat: float, lng: float) -> None:
|
|
153
163
|
cell_id = h3.latlng_to_cell(lat, lng, 3)
|
|
154
|
-
|
|
155
|
-
h3_layer = H3CellLayer(cell_id,
|
|
164
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.01, -0.01)
|
|
165
|
+
h3_layer = H3CellLayer(cell_id, projection)
|
|
156
166
|
|
|
157
167
|
# Just sanity check this test has caught a cell that wraps the entire planet and is testing
|
|
158
168
|
# what we think it is testing:
|
|
@@ -165,14 +175,14 @@ def test_h3_layer_wrapped_on_projection(lat: float, lng: float) -> None:
|
|
|
165
175
|
# check they are all of a similarish size - we had a bug early on where we'd
|
|
166
176
|
# mistakenly invert the area for the band, counting all the cells across the planet
|
|
167
177
|
for cell_id in h3.grid_ring(cell_id, 1):
|
|
168
|
-
neighbour = H3CellLayer(cell_id,
|
|
178
|
+
neighbour = H3CellLayer(cell_id, projection)
|
|
169
179
|
neighbour_area = neighbour.sum()
|
|
170
180
|
# We're happy if they're within 10% for now
|
|
171
181
|
assert abs((neighbour_area - area) / area) < 0.1
|
|
172
182
|
|
|
173
183
|
|
|
174
184
|
before_window = h3_layer.window
|
|
175
|
-
_, abs_ystep = abs(
|
|
185
|
+
_, abs_ystep = abs(projection.xstep), abs(projection.ystep)
|
|
176
186
|
expanded_area = Area(
|
|
177
187
|
left=h3_layer.area.left,
|
|
178
188
|
top=h3_layer.area.top + (22 * abs_ystep),
|
|
@@ -198,7 +208,11 @@ def test_h3_layer_overlapped():
|
|
|
198
208
|
# This is based on a regression, where somehow I made tiles not tesselate properly
|
|
199
209
|
left, top = (121.26706, 19.45338)
|
|
200
210
|
right, bottom = (121.62494, 19.18478)
|
|
201
|
-
|
|
211
|
+
projection = MapProjection(
|
|
212
|
+
WGS_84_PROJECTION,
|
|
213
|
+
0.000898315284120,
|
|
214
|
+
-0.000898315284120
|
|
215
|
+
)
|
|
202
216
|
|
|
203
217
|
cells = h3.geo_to_cells(h3.LatLngPoly([
|
|
204
218
|
(top, left),
|
|
@@ -208,13 +222,13 @@ def test_h3_layer_overlapped():
|
|
|
208
222
|
],), 7)
|
|
209
223
|
|
|
210
224
|
tiles = [
|
|
211
|
-
H3CellLayer(cell_id,
|
|
225
|
+
H3CellLayer(cell_id, projection)
|
|
212
226
|
for cell_id in cells]
|
|
213
227
|
|
|
214
228
|
union = RasterLayer.find_union(tiles)
|
|
215
229
|
union = union.grow(0.02)
|
|
216
230
|
|
|
217
|
-
scratch = RasterLayer.empty_raster_layer(union, scale, gdal.GDT_Float64)
|
|
231
|
+
scratch = RasterLayer.empty_raster_layer(union, projection.scale, gdal.GDT_Float64)
|
|
218
232
|
|
|
219
233
|
# In scratch we should only have 0 or 1 values, but if there are any overlaps we should get 2s...
|
|
220
234
|
|
|
@@ -2,7 +2,7 @@ import pytest
|
|
|
2
2
|
from osgeo import gdal
|
|
3
3
|
|
|
4
4
|
from tests.helpers import gdal_dataset_of_region, gdal_empty_dataset_of_region
|
|
5
|
-
from yirgacheffe.window import Area,
|
|
5
|
+
from yirgacheffe.window import Area, MapProjection, Window
|
|
6
6
|
from yirgacheffe.layers import RasterLayer, ConstantLayer, H3CellLayer
|
|
7
7
|
from yirgacheffe import WGS_84_PROJECTION
|
|
8
8
|
|
|
@@ -149,10 +149,10 @@ def test_intersection_stability():
|
|
|
149
149
|
# a rounding error that causes set_window_for_* methods to wobble depending on how far
|
|
150
150
|
# away from the top left thing where. adding round_down_pixels fixed this.
|
|
151
151
|
cells = ["874b93aaeffffff", "874b93a85ffffff", "874b93aa3ffffff", "874b93a84ffffff", "874b93a80ffffff"]
|
|
152
|
-
|
|
152
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
153
153
|
|
|
154
154
|
tiles = [
|
|
155
|
-
H3CellLayer(cell_id,
|
|
155
|
+
H3CellLayer(cell_id, projection)
|
|
156
156
|
for cell_id in cells]
|
|
157
157
|
|
|
158
158
|
# composing the same tiles within different areas should not cause them to
|
|
@@ -160,8 +160,8 @@ def test_intersection_stability():
|
|
|
160
160
|
union = RasterLayer.find_union(tiles)
|
|
161
161
|
superunion = union.grow(0.02)
|
|
162
162
|
|
|
163
|
-
scratch1 = RasterLayer.empty_raster_layer(union, scale, gdal.GDT_Float64, name='s1')
|
|
164
|
-
scratch2 = RasterLayer.empty_raster_layer(superunion, scale, gdal.GDT_Float64, name='s2')
|
|
163
|
+
scratch1 = RasterLayer.empty_raster_layer(union, projection.scale, gdal.GDT_Float64, name='s1')
|
|
164
|
+
scratch2 = RasterLayer.empty_raster_layer(superunion, projection.scale, gdal.GDT_Float64, name='s2')
|
|
165
165
|
|
|
166
166
|
relative_offsets = {}
|
|
167
167
|
|
|
@@ -8,7 +8,7 @@ import pytest
|
|
|
8
8
|
import yirgacheffe as yg
|
|
9
9
|
from yirgacheffe import WGS_84_PROJECTION
|
|
10
10
|
from yirgacheffe.layers import InvalidRasterBand
|
|
11
|
-
from yirgacheffe.window import Area,
|
|
11
|
+
from yirgacheffe.window import Area, MapProjection, Window
|
|
12
12
|
from tests.helpers import gdal_dataset_of_region, gdal_multiband_dataset_with_data, \
|
|
13
13
|
make_vectors_with_id, make_vectors_with_mutlile_ids
|
|
14
14
|
|
|
@@ -75,7 +75,7 @@ def test_open_multiband_raster() -> None:
|
|
|
75
75
|
|
|
76
76
|
def test_shape_from_nonexistent_file() -> None:
|
|
77
77
|
with pytest.raises(FileNotFoundError):
|
|
78
|
-
_ = yg.read_shape("this_file_does_not_exist.gpkg", (1.0, -1.0)
|
|
78
|
+
_ = yg.read_shape("this_file_does_not_exist.gpkg", (WGS_84_PROJECTION, (1.0, -1.0)))
|
|
79
79
|
|
|
80
80
|
def test_open_gpkg() -> None:
|
|
81
81
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
@@ -83,19 +83,47 @@ def test_open_gpkg() -> None:
|
|
|
83
83
|
area = Area(-10.0, 10.0, 10.0, 0.0)
|
|
84
84
|
make_vectors_with_id(42, {area}, path)
|
|
85
85
|
|
|
86
|
-
with yg.read_shape(path,
|
|
86
|
+
with yg.read_shape(path, (WGS_84_PROJECTION, (1.0, -1.0))) as layer:
|
|
87
87
|
assert layer.area == area
|
|
88
88
|
assert layer.geo_transform == (area.left, 1.0, 0.0, area.top, 0.0, -1.0)
|
|
89
89
|
assert layer.window == Window(0, 0, 20, 10)
|
|
90
|
+
assert layer.map_projection == MapProjection(WGS_84_PROJECTION, 1.0, -1.0)
|
|
90
91
|
assert layer.projection == WGS_84_PROJECTION
|
|
91
92
|
|
|
93
|
+
def test_open_gpkg_with_mapprojection() -> None:
|
|
94
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
95
|
+
path = os.path.join(tempdir, "test.gpkg")
|
|
96
|
+
area = Area(-10.0, 10.0, 10.0, 0.0)
|
|
97
|
+
make_vectors_with_id(42, {area}, path)
|
|
98
|
+
|
|
99
|
+
with yg.read_shape(path, MapProjection(WGS_84_PROJECTION, 1.0, -1.0)) as layer:
|
|
100
|
+
assert layer.area == area
|
|
101
|
+
assert layer.geo_transform == (area.left, 1.0, 0.0, area.top, 0.0, -1.0)
|
|
102
|
+
assert layer.window == Window(0, 0, 20, 10)
|
|
103
|
+
assert layer.map_projection == MapProjection(WGS_84_PROJECTION, 1.0, -1.0)
|
|
104
|
+
assert layer.projection == WGS_84_PROJECTION
|
|
105
|
+
|
|
106
|
+
def test_open_gpkg_with_no_projection() -> None:
|
|
107
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
108
|
+
path = os.path.join(tempdir, "test.gpkg")
|
|
109
|
+
area = Area(-10.0, 10.0, 10.0, 0.0)
|
|
110
|
+
make_vectors_with_id(42, {area}, path)
|
|
111
|
+
|
|
112
|
+
with yg.read_shape(path) as layer:
|
|
113
|
+
assert layer.area == area
|
|
114
|
+
assert layer.projection is None
|
|
115
|
+
with pytest.raises(AttributeError):
|
|
116
|
+
_ = layer.geo_transform
|
|
117
|
+
with pytest.raises(AttributeError):
|
|
118
|
+
_ = layer.window
|
|
119
|
+
|
|
92
120
|
def test_open_gpkg_direct_scale() -> None:
|
|
93
121
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
94
122
|
path = Path(tempdir) / "test.gpkg"
|
|
95
123
|
area = Area(-10.0, 10.0, 10.0, 0.0)
|
|
96
124
|
make_vectors_with_id(42, {area}, path)
|
|
97
125
|
|
|
98
|
-
with yg.read_shape(path, (1.0, -1.0)
|
|
126
|
+
with yg.read_shape(path, (WGS_84_PROJECTION, (1.0, -1.0))) as layer:
|
|
99
127
|
assert layer.area == area
|
|
100
128
|
assert layer.geo_transform == (area.left, 1.0, 0.0, area.top, 0.0, -1.0)
|
|
101
129
|
assert layer.window == Window(0, 0, 20, 10)
|
|
@@ -110,7 +138,7 @@ def test_open_gpkg_with_filter() -> None:
|
|
|
110
138
|
}
|
|
111
139
|
make_vectors_with_mutlile_ids(areas, path)
|
|
112
140
|
|
|
113
|
-
with yg.read_shape(path, (1.0, -1.0),
|
|
141
|
+
with yg.read_shape(path, (WGS_84_PROJECTION, (1.0, -1.0)), "id_no=42") as layer:
|
|
114
142
|
assert layer.area == Area(-10.0, 10.0, 0.0, 0.0)
|
|
115
143
|
assert layer.geo_transform == (-10.0, 1.0, 0.0, 10.0, 0.0, -1.0)
|
|
116
144
|
assert layer.window == Window(0, 0, 10, 10)
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import random
|
|
3
3
|
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
7
|
import pytest
|
|
7
8
|
import torch
|
|
8
9
|
|
|
9
10
|
import yirgacheffe
|
|
10
|
-
from yirgacheffe.
|
|
11
|
+
from yirgacheffe.window import Area, PixelScale
|
|
12
|
+
from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer
|
|
11
13
|
from yirgacheffe.operators import LayerOperation, DataType
|
|
12
14
|
from yirgacheffe._backends import backend
|
|
13
|
-
from tests.helpers import gdal_dataset_with_data
|
|
15
|
+
from tests.helpers import gdal_dataset_with_data, gdal_dataset_of_region, make_vectors_with_id
|
|
14
16
|
|
|
15
17
|
def test_add_byte_layers() -> None:
|
|
16
18
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
|
|
@@ -51,6 +53,15 @@ def test_error_of_pixel_scale_wrong_three_param() -> None:
|
|
|
51
53
|
with pytest.raises(ValueError):
|
|
52
54
|
_ = LayerOperation.where(layer1, layer2, layer3)
|
|
53
55
|
|
|
56
|
+
def test_incompatible_source_and_destination_projections() -> None:
|
|
57
|
+
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
58
|
+
|
|
59
|
+
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
60
|
+
|
|
61
|
+
with RasterLayer.empty_raster_layer(layer1.area, PixelScale(1.0, -1.0), layer1.datatype) as result:
|
|
62
|
+
with pytest.raises(ValueError):
|
|
63
|
+
layer1.save(result)
|
|
64
|
+
|
|
54
65
|
@pytest.mark.parametrize("skip,expected_steps", [
|
|
55
66
|
(1, [0.0, 0.5, 1.0]),
|
|
56
67
|
(2, [0.0, 1.0]),
|
|
@@ -1497,3 +1508,50 @@ def test_to_geotiff_parallel_thread_and_sum(monkeypatch) -> None:
|
|
|
1497
1508
|
expected = data1 * 2
|
|
1498
1509
|
actual = result.read_array(0, 0, 4, 2)
|
|
1499
1510
|
assert (expected == actual).all()
|
|
1511
|
+
|
|
1512
|
+
def test_raster_and_vector() -> None:
|
|
1513
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
1514
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(-10, 10, 10, -10), 1.0))
|
|
1515
|
+
assert raster.sum() > 0.0
|
|
1516
|
+
|
|
1517
|
+
path = Path(tempdir) / "test.gpkg"
|
|
1518
|
+
area = Area(-5.0, 5.0, 5.0, -5.0)
|
|
1519
|
+
make_vectors_with_id(42, {area}, path)
|
|
1520
|
+
assert path.exists
|
|
1521
|
+
|
|
1522
|
+
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0), yirgacheffe.WGS_84_PROJECTION)
|
|
1523
|
+
|
|
1524
|
+
calc = raster * vector
|
|
1525
|
+
assert calc.sum() > 0.0
|
|
1526
|
+
assert calc.sum() < raster.sum()
|
|
1527
|
+
|
|
1528
|
+
def test_raster_and_vector_mixed_projection() -> None:
|
|
1529
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
1530
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(-10, 10, 10, -10), 1.1))
|
|
1531
|
+
assert raster.sum() > 0.0
|
|
1532
|
+
|
|
1533
|
+
path = Path(tempdir) / "test.gpkg"
|
|
1534
|
+
area = Area(-5.0, 5.0, 5.0, -5.0)
|
|
1535
|
+
make_vectors_with_id(42, {area}, path)
|
|
1536
|
+
assert path.exists
|
|
1537
|
+
|
|
1538
|
+
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0), yirgacheffe.WGS_84_PROJECTION)
|
|
1539
|
+
|
|
1540
|
+
with pytest.raises(ValueError):
|
|
1541
|
+
_ = raster * vector
|
|
1542
|
+
|
|
1543
|
+
def test_raster_and_vector_no_scale_on_vector() -> None:
|
|
1544
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
1545
|
+
raster = RasterLayer(gdal_dataset_of_region(Area(-10, 10, 10, -10), 1.0))
|
|
1546
|
+
assert raster.sum() > 0.0
|
|
1547
|
+
|
|
1548
|
+
path = Path(tempdir) / "test.gpkg"
|
|
1549
|
+
area = Area(-5.0, 5.0, 5.0, -5.0)
|
|
1550
|
+
make_vectors_with_id(42, {area}, path)
|
|
1551
|
+
assert path.exists
|
|
1552
|
+
|
|
1553
|
+
vector = VectorLayer.layer_from_file(path, None, None, None)
|
|
1554
|
+
|
|
1555
|
+
calc = raster * vector
|
|
1556
|
+
assert calc.sum() > 0.0
|
|
1557
|
+
assert calc.sum() < raster.sum()
|
|
@@ -4,8 +4,8 @@ import numpy as np
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
6
|
from yirgacheffe import WGS_84_PROJECTION
|
|
7
|
-
from yirgacheffe.layers import
|
|
8
|
-
from yirgacheffe.window import Area
|
|
7
|
+
from yirgacheffe.layers import RasterLayer, H3CellLayer
|
|
8
|
+
from yirgacheffe.window import Area, MapProjection
|
|
9
9
|
import yirgacheffe.operators as yo
|
|
10
10
|
|
|
11
11
|
class NaiveH3CellLayer(H3CellLayer):
|
|
@@ -14,13 +14,14 @@ class NaiveH3CellLayer(H3CellLayer):
|
|
|
14
14
|
version that checks for every cell."""
|
|
15
15
|
|
|
16
16
|
def read_array(self, xoffset, yoffset, xsize, ysize): # pylint: disable=W0237
|
|
17
|
+
assert self._projection is not None
|
|
17
18
|
res = np.zeros((ysize, xsize), dtype=float)
|
|
18
|
-
start_x = self.
|
|
19
|
-
start_y = self.
|
|
19
|
+
start_x = self.area.left + (xoffset * self._projection.xstep)
|
|
20
|
+
start_y = self.area.top + (yoffset * self._projection.ystep)
|
|
20
21
|
for ypixel in range(ysize):
|
|
21
|
-
lat = start_y + (ypixel * self.
|
|
22
|
+
lat = start_y + (ypixel * self._projection.ystep)
|
|
22
23
|
for xpixel in range(xsize):
|
|
23
|
-
lng = start_x + (xpixel * self.
|
|
24
|
+
lng = start_x + (xpixel * self._projection.xstep)
|
|
24
25
|
this_cell = h3.latlng_to_cell(lat, lng, self.zoom)
|
|
25
26
|
if this_cell == self.cell_id:
|
|
26
27
|
res[ypixel][xpixel] = 1.0
|
|
@@ -41,8 +42,9 @@ class NaiveH3CellLayer(H3CellLayer):
|
|
|
41
42
|
def test_h3_vs_naive(lat: float, lng: float) -> None:
|
|
42
43
|
for zoom in range(5, 9):
|
|
43
44
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
46
|
+
optimised_layer = H3CellLayer(cell_id, projection)
|
|
47
|
+
naive_layer = NaiveH3CellLayer(cell_id, projection)
|
|
46
48
|
|
|
47
49
|
optimised_cell_count = optimised_layer.sum()
|
|
48
50
|
naive_cell_count = naive_layer.sum()
|
|
@@ -65,17 +67,17 @@ def test_h3_vs_naive(lat: float, lng: float) -> None:
|
|
|
65
67
|
def test_h3_vs_naive_for_union(lat: float, lng: float) -> None:
|
|
66
68
|
for zoom in range(7, 9):
|
|
67
69
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
68
|
-
|
|
69
|
-
optimised_layer = H3CellLayer(cell_id,
|
|
70
|
-
naive_layer = NaiveH3CellLayer(cell_id,
|
|
70
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
71
|
+
optimised_layer = H3CellLayer(cell_id, projection)
|
|
72
|
+
naive_layer = NaiveH3CellLayer(cell_id, projection)
|
|
71
73
|
|
|
72
74
|
before_cell_count = optimised_layer.sum()
|
|
73
75
|
|
|
74
76
|
superset_area = Area(
|
|
75
|
-
left=optimised_layer.area.left - (5 *
|
|
76
|
-
right=optimised_layer.area.right + (5 *
|
|
77
|
-
top=optimised_layer.area.top - (5 *
|
|
78
|
-
bottom=optimised_layer.area.bottom + (5 *
|
|
77
|
+
left=optimised_layer.area.left - (5 * projection.xstep),
|
|
78
|
+
right=optimised_layer.area.right + (5 * projection.xstep),
|
|
79
|
+
top=optimised_layer.area.top - (5 * projection.ystep),
|
|
80
|
+
bottom=optimised_layer.area.bottom + (5 * projection.ystep),
|
|
79
81
|
)
|
|
80
82
|
optimised_layer.set_window_for_union(superset_area)
|
|
81
83
|
naive_layer.set_window_for_union(superset_area)
|
|
@@ -101,17 +103,17 @@ def test_h3_vs_naive_for_union(lat: float, lng: float) -> None:
|
|
|
101
103
|
def test_h3_vs_naive_for_intersection(lat: float, lng: float) -> None:
|
|
102
104
|
for zoom in range(7, 9):
|
|
103
105
|
cell_id = h3.latlng_to_cell(lat, lng, zoom)
|
|
104
|
-
|
|
105
|
-
optimised_layer = H3CellLayer(cell_id,
|
|
106
|
-
naive_layer = NaiveH3CellLayer(cell_id,
|
|
106
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
107
|
+
optimised_layer = H3CellLayer(cell_id, projection)
|
|
108
|
+
naive_layer = NaiveH3CellLayer(cell_id, projection)
|
|
107
109
|
|
|
108
110
|
before_cell_count = optimised_layer.sum()
|
|
109
111
|
|
|
110
112
|
subset_area = Area(
|
|
111
|
-
left=optimised_layer.area.left + (2 *
|
|
112
|
-
right=optimised_layer.area.right - (2 *
|
|
113
|
-
top=optimised_layer.area.top + (2 *
|
|
114
|
-
bottom=optimised_layer.area.bottom - (2 *
|
|
113
|
+
left=optimised_layer.area.left + (2 * projection.xstep),
|
|
114
|
+
right=optimised_layer.area.right - (2 * projection.xstep),
|
|
115
|
+
top=optimised_layer.area.top + (2 * projection.ystep),
|
|
116
|
+
bottom=optimised_layer.area.bottom - (2 * projection.ystep),
|
|
115
117
|
)
|
|
116
118
|
optimised_layer.set_window_for_intersection(subset_area)
|
|
117
119
|
naive_layer.set_window_for_intersection(subset_area)
|
|
@@ -143,8 +145,8 @@ def test_h3_vs_naive_for_intersection(lat: float, lng: float) -> None:
|
|
|
143
145
|
def test_cells_dont_overlap(cell_id):
|
|
144
146
|
|
|
145
147
|
cluster = h3.grid_disk(cell_id, 1)
|
|
146
|
-
|
|
147
|
-
layers = [H3CellLayer(x,
|
|
148
|
+
projection = MapProjection(WGS_84_PROJECTION, 0.000898315284120,-0.000898315284120)
|
|
149
|
+
layers = [H3CellLayer(x, projection) for x in cluster]
|
|
148
150
|
|
|
149
151
|
union = RasterLayer.find_union(layers)
|
|
150
152
|
for layer in layers:
|
|
@@ -8,7 +8,7 @@ import numpy as np
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
10
|
from tests.helpers import gdal_dataset_of_region, make_vectors_with_id
|
|
11
|
-
from yirgacheffe.window import Area, PixelScale, Window
|
|
11
|
+
from yirgacheffe.window import Area, MapProjection, PixelScale, Window
|
|
12
12
|
from yirgacheffe.layers import ConstantLayer, GroupLayer, RasterLayer, RescaledRasterLayer, \
|
|
13
13
|
UniformAreaLayer, VectorLayer
|
|
14
14
|
from yirgacheffe import WGS_84_PROJECTION
|
|
@@ -181,7 +181,7 @@ def test_pickle_rescaled_raster_layer() -> None:
|
|
|
181
181
|
path = os.path.join(tempdir, "test.tif")
|
|
182
182
|
area = Area(-10, 10, 10, -10)
|
|
183
183
|
raster = RasterLayer(gdal_dataset_of_region(area, 0.02, filename=path))
|
|
184
|
-
layer = RescaledRasterLayer(raster,
|
|
184
|
+
layer = RescaledRasterLayer(raster, MapProjection(WGS_84_PROJECTION, 0.01, -0.01))
|
|
185
185
|
|
|
186
186
|
p = pickle.dumps(layer)
|
|
187
187
|
restore = pickle.loads(p)
|