yirgacheffe 1.9.4__tar.gz → 1.9.5__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.9.4/yirgacheffe.egg-info → yirgacheffe-1.9.5}/PKG-INFO +1 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/pyproject.toml +1 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_datatypes.py +46 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_multiband.py +7 -5
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_openers.py +26 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_operators.py +24 -23
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_reduce.py +4 -3
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/__init__.py +1 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/enumeration.py +30 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_core.py +50 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/group.py +1 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/window.py +9 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5/yirgacheffe.egg-info}/PKG-INFO +1 -1
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/LICENSE +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/MANIFEST.in +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/README.md +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/setup.cfg +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_area.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_auto_windowing.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_constants.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_group.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_h3layer.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_intersection.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_nodata.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_optimisation.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_parallel_operators.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_pickle.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_pixel_coord.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_projection.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_raster.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_rescaling.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_rounding.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_save_with_window.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_sum_with_window.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_uniform_area_layer.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_union.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_vectors.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_window.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/__init__.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/mlx.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/numpy.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_operators.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/constants.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/__init__.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/area.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/base.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/constant.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/h3layer.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/rasters.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/rescaled.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/vectors.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/operators.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/py.typed +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/rounding.py +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/SOURCES.txt +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/dependency_links.txt +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/entry_points.txt +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/requires.txt +0 -0
- {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/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.
|
|
9
|
+
version = "1.9.5"
|
|
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" }]
|
|
@@ -64,3 +64,49 @@ def test_float_to_int() -> None:
|
|
|
64
64
|
expected = backend.promote(np.array([[1, 2, 3, 4], [5, 6, 7, 8]]))
|
|
65
65
|
actual = result.read_array(0, 0, 4, 2)
|
|
66
66
|
assert (expected == actual).all()
|
|
67
|
+
|
|
68
|
+
@pytest.mark.parametrize("array,expected_type", [
|
|
69
|
+
(
|
|
70
|
+
np.ones((2, 2)).astype(np.int8),
|
|
71
|
+
DataType.Int8,
|
|
72
|
+
),
|
|
73
|
+
(
|
|
74
|
+
np.ones((2, 2)).astype(np.int16),
|
|
75
|
+
DataType.Int16,
|
|
76
|
+
),
|
|
77
|
+
(
|
|
78
|
+
np.ones((2, 2)).astype(np.int32),
|
|
79
|
+
DataType.Int32,
|
|
80
|
+
),
|
|
81
|
+
(
|
|
82
|
+
np.ones((2, 2)).astype(np.int64),
|
|
83
|
+
DataType.Int64,
|
|
84
|
+
),
|
|
85
|
+
(
|
|
86
|
+
np.ones((2, 2)).astype(np.uint8),
|
|
87
|
+
DataType.UInt8,
|
|
88
|
+
),
|
|
89
|
+
(
|
|
90
|
+
np.ones((2, 2)).astype(np.uint16),
|
|
91
|
+
DataType.UInt16,
|
|
92
|
+
),
|
|
93
|
+
(
|
|
94
|
+
np.ones((2, 2)).astype(np.uint32),
|
|
95
|
+
DataType.UInt32,
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
np.ones((2, 2)).astype(np.uint64),
|
|
99
|
+
DataType.UInt64,
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
np.ones((2, 2)).astype(np.float32),
|
|
103
|
+
DataType.Float32,
|
|
104
|
+
),
|
|
105
|
+
(
|
|
106
|
+
np.ones((2, 2)).astype(np.float64),
|
|
107
|
+
DataType.Float64,
|
|
108
|
+
),
|
|
109
|
+
])
|
|
110
|
+
def test_of_Array(array: np.ndarray, expected_type: DataType) -> None:
|
|
111
|
+
ytype = DataType.of_array(array)
|
|
112
|
+
assert ytype == expected_type
|
|
@@ -4,7 +4,7 @@ import tempfile
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from osgeo import gdal
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import yirgacheffe as yg
|
|
8
8
|
from yirgacheffe.layers import RasterLayer
|
|
9
9
|
from yirgacheffe.window import Area, PixelScale
|
|
10
10
|
|
|
@@ -23,9 +23,10 @@ def test_simple_two_band_image() -> None:
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
# Create a set of rasters in turn to fill each band
|
|
26
|
+
projection = yg.MapProjection("epsg:4326", 1.0, -1.0)
|
|
26
27
|
for i in range(bands):
|
|
27
28
|
data1 = np.full((2, 2), i+1)
|
|
28
|
-
layer1 =
|
|
29
|
+
layer1 = yg.from_array(data1, (-1.0, 1.0), projection)
|
|
29
30
|
layer1.save(target, band=i+1)
|
|
30
31
|
|
|
31
32
|
# force things to disk
|
|
@@ -33,7 +34,7 @@ def test_simple_two_band_image() -> None:
|
|
|
33
34
|
|
|
34
35
|
#check they do what we expect
|
|
35
36
|
for i in range(bands):
|
|
36
|
-
o =
|
|
37
|
+
o = yg.read_raster(target_path, band=i+1)
|
|
37
38
|
assert o.sum() == (4 * (i + 1))
|
|
38
39
|
|
|
39
40
|
def test_stack_tifs_with_area_match() -> None:
|
|
@@ -43,9 +44,10 @@ def test_stack_tifs_with_area_match() -> None:
|
|
|
43
44
|
# slight alignment offset when we create them)
|
|
44
45
|
bands = 4
|
|
45
46
|
source_layers = []
|
|
47
|
+
projection = yg.MapProjection("epsg:4326", 1.0, -1.0)
|
|
46
48
|
for i in range(bands):
|
|
47
49
|
data1 = np.full((100, 100), i+1)
|
|
48
|
-
layer1 =
|
|
50
|
+
layer1 = yg.from_array(data1, (-100+i, 100+i), projection)
|
|
49
51
|
source_layers.append(layer1)
|
|
50
52
|
|
|
51
53
|
intersection = RasterLayer.find_intersection(source_layers)
|
|
@@ -66,5 +68,5 @@ def test_stack_tifs_with_area_match() -> None:
|
|
|
66
68
|
|
|
67
69
|
#check they do what we expect
|
|
68
70
|
for i in range(bands):
|
|
69
|
-
o =
|
|
71
|
+
o = yg.read_raster(target_path, band=i+1)
|
|
70
72
|
assert o.sum() == ((100 - (bands - 1)) * (100 - (bands - 1)) * (i + 1))
|
|
@@ -264,3 +264,29 @@ def test_constant() -> None:
|
|
|
264
264
|
expected = np.full((20, 20), 42.0)
|
|
265
265
|
actual = result.read_array(0, 0, 20, 20)
|
|
266
266
|
assert (expected == actual).all()
|
|
267
|
+
|
|
268
|
+
def test_create_simple_float() -> None:
|
|
269
|
+
projection = MapProjection(WGS_84_PROJECTION, 1.0, -1.0)
|
|
270
|
+
data = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
271
|
+
with yg.from_array(data, (-2.0, 1.0), projection) as layer:
|
|
272
|
+
expected_area = Area(left=-2.0, right=2.0, top=1.0, bottom=-1.0)
|
|
273
|
+
|
|
274
|
+
assert layer.map_projection == projection
|
|
275
|
+
assert layer.area == expected_area
|
|
276
|
+
assert layer.datatype == DataType.Float64
|
|
277
|
+
|
|
278
|
+
actual = layer.read_array(0, 0, 4, 2)
|
|
279
|
+
assert (data == actual).all()
|
|
280
|
+
|
|
281
|
+
def test_create_simple_direct_projection() -> None:
|
|
282
|
+
expected_projection = MapProjection(WGS_84_PROJECTION, 1.0, -1.0)
|
|
283
|
+
data = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
|
|
284
|
+
with yg.from_array(data, (-2.0, 1.0), (WGS_84_PROJECTION, (1.0, -1.0))) as layer:
|
|
285
|
+
expected_area = Area(left=-2.0, right=2.0, top=1.0, bottom=-1.0)
|
|
286
|
+
|
|
287
|
+
assert layer.map_projection == expected_projection
|
|
288
|
+
assert layer.area == expected_area
|
|
289
|
+
assert layer.datatype == DataType.Int64
|
|
290
|
+
|
|
291
|
+
actual = layer.read_array(0, 0, 4, 2)
|
|
292
|
+
assert (data == actual).all()
|
|
@@ -7,7 +7,7 @@ import numpy as np
|
|
|
7
7
|
import pytest
|
|
8
8
|
import torch
|
|
9
9
|
|
|
10
|
-
import yirgacheffe
|
|
10
|
+
import yirgacheffe as yg
|
|
11
11
|
from yirgacheffe.window import Area, PixelScale
|
|
12
12
|
from yirgacheffe.layers import ConstantLayer, RasterLayer, VectorLayer
|
|
13
13
|
from yirgacheffe.operators import DataType
|
|
@@ -619,7 +619,7 @@ def test_direct_layer_save_and_sum() -> None:
|
|
|
619
619
|
assert (data1 == actual_data).all()
|
|
620
620
|
assert expected_sum == actual_sum
|
|
621
621
|
|
|
622
|
-
@pytest.mark.skipif(
|
|
622
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
623
623
|
def test_add_to_float_layer_by_np_array() -> None:
|
|
624
624
|
data1 = np.array([[1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]])
|
|
625
625
|
layer1 = RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1))
|
|
@@ -654,7 +654,7 @@ def test_write_mulitband_raster() -> None:
|
|
|
654
654
|
|
|
655
655
|
assert (expected == actual).all()
|
|
656
656
|
|
|
657
|
-
@pytest.mark.skipif(
|
|
657
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
658
658
|
def test_save_and_sum_float32(monkeypatch) -> None:
|
|
659
659
|
random.seed(42)
|
|
660
660
|
data = []
|
|
@@ -673,12 +673,12 @@ def test_save_and_sum_float32(monkeypatch) -> None:
|
|
|
673
673
|
|
|
674
674
|
with monkeypatch.context() as m:
|
|
675
675
|
for blocksize in range(1,11):
|
|
676
|
-
m.setattr(
|
|
676
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
677
677
|
with RasterLayer.empty_raster_layer_like(layer1) as store:
|
|
678
678
|
actual = layer1.save(store, and_sum=True)
|
|
679
679
|
assert expected == actual
|
|
680
680
|
|
|
681
|
-
@pytest.mark.skipif(
|
|
681
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
682
682
|
def test_parallel_save_and_sum_float32(monkeypatch) -> None:
|
|
683
683
|
random.seed(42)
|
|
684
684
|
data = []
|
|
@@ -701,12 +701,12 @@ def test_parallel_save_and_sum_float32(monkeypatch) -> None:
|
|
|
701
701
|
|
|
702
702
|
with monkeypatch.context() as m:
|
|
703
703
|
for blocksize in range(1,11):
|
|
704
|
-
m.setattr(
|
|
704
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
705
705
|
with RasterLayer.empty_raster_layer_like(layer1) as store:
|
|
706
706
|
actual = layer1.parallel_save(store, and_sum=True)
|
|
707
707
|
assert expected == actual
|
|
708
708
|
|
|
709
|
-
@pytest.mark.skipif(
|
|
709
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
710
710
|
def test_sum_float32(monkeypatch) -> None:
|
|
711
711
|
random.seed(42)
|
|
712
712
|
data = []
|
|
@@ -725,7 +725,7 @@ def test_sum_float32(monkeypatch) -> None:
|
|
|
725
725
|
|
|
726
726
|
with monkeypatch.context() as m:
|
|
727
727
|
for blocksize in range(1,11):
|
|
728
|
-
m.setattr(
|
|
728
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
729
729
|
actual = layer1.sum()
|
|
730
730
|
assert expected == actual
|
|
731
731
|
|
|
@@ -1511,21 +1511,21 @@ def test_to_geotiff_single_thread_and_sum() -> None:
|
|
|
1511
1511
|
actual = result.read_array(0, 0, 4, 2)
|
|
1512
1512
|
assert (expected == actual).all()
|
|
1513
1513
|
|
|
1514
|
-
@pytest.mark.skipif(
|
|
1514
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
1515
1515
|
@pytest.mark.parametrize("parallelism", [
|
|
1516
1516
|
2,
|
|
1517
1517
|
True,
|
|
1518
1518
|
])
|
|
1519
1519
|
def test_to_geotiff_parallel_thread(monkeypatch, parallelism) -> None:
|
|
1520
1520
|
with monkeypatch.context() as m:
|
|
1521
|
-
m.setattr(
|
|
1521
|
+
m.setattr(yg.constants, "YSTEP", 1)
|
|
1522
1522
|
m.setattr(LayerOperation, "save", None)
|
|
1523
1523
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
1524
1524
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
|
|
1525
1525
|
src_filename = os.path.join("src.tif")
|
|
1526
1526
|
dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1, filename=src_filename)
|
|
1527
1527
|
dataset.Close()
|
|
1528
|
-
with
|
|
1528
|
+
with yg.read_raster(src_filename) as layer1:
|
|
1529
1529
|
calc = layer1 * 2
|
|
1530
1530
|
filename = os.path.join(tempdir, "test.tif")
|
|
1531
1531
|
calc.to_geotiff(filename, parallelism=parallelism)
|
|
@@ -1535,21 +1535,21 @@ def test_to_geotiff_parallel_thread(monkeypatch, parallelism) -> None:
|
|
|
1535
1535
|
actual = result.read_array(0, 0, 4, 2)
|
|
1536
1536
|
assert (expected == actual).all()
|
|
1537
1537
|
|
|
1538
|
-
@pytest.mark.skipif(
|
|
1538
|
+
@pytest.mark.skipif(yg._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
|
|
1539
1539
|
@pytest.mark.parametrize("parallelism", [
|
|
1540
1540
|
2,
|
|
1541
1541
|
True,
|
|
1542
1542
|
])
|
|
1543
1543
|
def test_to_geotiff_parallel_thread_and_sum(monkeypatch, parallelism) -> None:
|
|
1544
1544
|
with monkeypatch.context() as m:
|
|
1545
|
-
m.setattr(
|
|
1545
|
+
m.setattr(yg.constants, "YSTEP", 1)
|
|
1546
1546
|
m.setattr(LayerOperation, "save", None)
|
|
1547
1547
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
1548
1548
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
|
|
1549
1549
|
src_filename = os.path.join("src.tif")
|
|
1550
1550
|
dataset = gdal_dataset_with_data((0.0, 0.0), 0.02, data1, filename=src_filename)
|
|
1551
1551
|
dataset.Close()
|
|
1552
|
-
with
|
|
1552
|
+
with yg.read_raster(src_filename) as layer1:
|
|
1553
1553
|
filename = os.path.join(tempdir, "test.tif")
|
|
1554
1554
|
calc = layer1 * 2
|
|
1555
1555
|
steps: list[float] = []
|
|
@@ -1574,7 +1574,7 @@ def test_raster_and_vector() -> None:
|
|
|
1574
1574
|
make_vectors_with_id(42, {area}, path)
|
|
1575
1575
|
assert path.exists()
|
|
1576
1576
|
|
|
1577
|
-
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0),
|
|
1577
|
+
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0), yg.WGS_84_PROJECTION)
|
|
1578
1578
|
|
|
1579
1579
|
calc = raster * vector
|
|
1580
1580
|
assert calc.sum() > 0.0
|
|
@@ -1590,7 +1590,7 @@ def test_raster_and_vector_mixed_projection() -> None:
|
|
|
1590
1590
|
make_vectors_with_id(42, {area}, path)
|
|
1591
1591
|
assert path.exists()
|
|
1592
1592
|
|
|
1593
|
-
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0),
|
|
1593
|
+
vector = VectorLayer.layer_from_file(path, None, PixelScale(1.0, -1.0), yg.WGS_84_PROJECTION)
|
|
1594
1594
|
|
|
1595
1595
|
with pytest.raises(ValueError):
|
|
1596
1596
|
_ = raster * vector
|
|
@@ -1626,7 +1626,7 @@ def test_isnan() -> None:
|
|
|
1626
1626
|
@pytest.mark.parametrize("blocksize", [1, 2, 4, 8])
|
|
1627
1627
|
def test_add_byte_layers_read_array_all(monkeypatch, blocksize) -> None:
|
|
1628
1628
|
with monkeypatch.context() as m:
|
|
1629
|
-
m.setattr(
|
|
1629
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
1630
1630
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
|
|
1631
1631
|
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80]])
|
|
1632
1632
|
|
|
@@ -1642,7 +1642,7 @@ def test_add_byte_layers_read_array_all(monkeypatch, blocksize) -> None:
|
|
|
1642
1642
|
@pytest.mark.parametrize("blocksize", [1, 2, 4, 8])
|
|
1643
1643
|
def test_add_byte_layers_read_array_partial_horizontal(monkeypatch, blocksize) -> None:
|
|
1644
1644
|
with monkeypatch.context() as m:
|
|
1645
|
-
m.setattr(
|
|
1645
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
1646
1646
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
|
|
1647
1647
|
data2 = np.array([[10, 20, 30, 40], [50, 60, 70, 80]])
|
|
1648
1648
|
|
|
@@ -1658,7 +1658,7 @@ def test_add_byte_layers_read_array_partial_horizontal(monkeypatch, blocksize) -
|
|
|
1658
1658
|
@pytest.mark.parametrize("blocksize", [1, 2, 4, 8])
|
|
1659
1659
|
def test_add_byte_layers_read_array_partial_vertical(monkeypatch, blocksize) -> None:
|
|
1660
1660
|
with monkeypatch.context() as m:
|
|
1661
|
-
m.setattr(
|
|
1661
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
1662
1662
|
data1 = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
|
|
1663
1663
|
data2 = np.array([[10, 20], [30, 40], [50, 60], [70, 80]])
|
|
1664
1664
|
|
|
@@ -1674,7 +1674,7 @@ def test_add_byte_layers_read_array_partial_vertical(monkeypatch, blocksize) ->
|
|
|
1674
1674
|
@pytest.mark.parametrize("blocksize", [1, 2, 4, 8])
|
|
1675
1675
|
def test_add_byte_layers_read_array_partial(monkeypatch, blocksize) -> None:
|
|
1676
1676
|
with monkeypatch.context() as m:
|
|
1677
|
-
m.setattr(
|
|
1677
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
1678
1678
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
|
|
1679
1679
|
data2 = np.array([[10, 10, 10, 10], [20, 20, 20, 20], [30, 30, 30, 30], [40, 40, 40, 40]])
|
|
1680
1680
|
|
|
@@ -1690,13 +1690,14 @@ def test_add_byte_layers_read_array_partial(monkeypatch, blocksize) -> None:
|
|
|
1690
1690
|
@pytest.mark.parametrize("blocksize", [1, 2, 4, 8])
|
|
1691
1691
|
def test_add_byte_layers_read_array_superset(monkeypatch, blocksize) -> None:
|
|
1692
1692
|
with monkeypatch.context() as m:
|
|
1693
|
-
m.setattr(
|
|
1693
|
+
m.setattr(yg.constants, "YSTEP", blocksize)
|
|
1694
1694
|
data1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
|
|
1695
1695
|
data2 = np.array([[10, 10, 10, 10], [20, 20, 20, 20], [30, 30, 30, 30], [40, 40, 40, 40]])
|
|
1696
1696
|
|
|
1697
|
+
projection = yg.MapProjection("epsg:4326", 0.02, -0.02)
|
|
1697
1698
|
with (
|
|
1698
|
-
|
|
1699
|
-
|
|
1699
|
+
yg.from_array(data1, (0.0, 0.0), projection) as layer1,
|
|
1700
|
+
yg.from_array(data2, (0.0, 0.0), projection) as layer2,
|
|
1700
1701
|
):
|
|
1701
1702
|
comp = layer1 + layer2
|
|
1702
1703
|
inner_expected = data1 + data2
|
|
@@ -3,8 +3,7 @@ import operator
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
from tests.helpers import gdal_dataset_with_data
|
|
6
|
+
import yirgacheffe as yg
|
|
8
7
|
|
|
9
8
|
def test_add_similar_layers() -> None:
|
|
10
9
|
data = [
|
|
@@ -13,7 +12,9 @@ def test_add_similar_layers() -> None:
|
|
|
13
12
|
np.array([[100, 200, 300, 400], [500, 600, 700, 800]]),
|
|
14
13
|
]
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
origin = (0.0, 0.0)
|
|
16
|
+
map_projection = yg.MapProjection("epsg:4326", 1.0, -1.0)
|
|
17
|
+
layers = [yg.from_array(x, origin, map_projection) for x in data]
|
|
17
18
|
|
|
18
19
|
summed_layers = reduce(operator.add, layers)
|
|
19
20
|
actual = summed_layers.read_array(0, 0, 4, 2)
|
|
@@ -13,7 +13,7 @@ except ModuleNotFoundError:
|
|
|
13
13
|
__version__ = pyproject_data["project"]["version"]
|
|
14
14
|
|
|
15
15
|
from .layers import YirgacheffeLayer
|
|
16
|
-
from ._core import read_raster, read_rasters, read_shape, read_shape_like, constant, read_narrow_raster
|
|
16
|
+
from ._core import read_raster, read_rasters, read_shape, read_shape_like, constant, read_narrow_raster, from_array
|
|
17
17
|
from .constants import WGS_84_PROJECTION
|
|
18
18
|
from .window import Area, MapProjection, Window
|
|
19
19
|
from ._backends.enumeration import dtype as DataType
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from enum import Enum
|
|
2
4
|
|
|
5
|
+
import numpy as np
|
|
3
6
|
from osgeo import gdal
|
|
4
7
|
|
|
5
8
|
class operators(Enum):
|
|
@@ -77,5 +80,31 @@ class dtype(Enum):
|
|
|
77
80
|
return self.value
|
|
78
81
|
|
|
79
82
|
@classmethod
|
|
80
|
-
def of_gdal(cls, val):
|
|
83
|
+
def of_gdal(cls, val: int) -> dtype:
|
|
81
84
|
return cls(val)
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def of_array(cls, val: np.ndarray) -> dtype:
|
|
88
|
+
match val.dtype:
|
|
89
|
+
case np.float32:
|
|
90
|
+
return dtype.Float32
|
|
91
|
+
case np.float64:
|
|
92
|
+
return dtype.Float64
|
|
93
|
+
case np.int8:
|
|
94
|
+
return dtype.Int8
|
|
95
|
+
case np.int16:
|
|
96
|
+
return dtype.Int16
|
|
97
|
+
case np.int32:
|
|
98
|
+
return dtype.Int32
|
|
99
|
+
case np.int64:
|
|
100
|
+
return dtype.Int64
|
|
101
|
+
case np.uint8:
|
|
102
|
+
return dtype.UInt8
|
|
103
|
+
case np.uint16:
|
|
104
|
+
return dtype.UInt16
|
|
105
|
+
case np.uint32:
|
|
106
|
+
return dtype.UInt32
|
|
107
|
+
case np.uint64:
|
|
108
|
+
return dtype.UInt64
|
|
109
|
+
case _:
|
|
110
|
+
raise ValueError
|
|
@@ -3,13 +3,15 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Sequence
|
|
5
5
|
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
6
8
|
from .layers.area import UniformAreaLayer
|
|
7
9
|
from .layers.base import YirgacheffeLayer
|
|
8
10
|
from .layers.constant import ConstantLayer
|
|
9
11
|
from .layers.group import GroupLayer, TiledGroupLayer
|
|
10
12
|
from .layers.rasters import RasterLayer
|
|
11
13
|
from .layers.vectors import VectorLayer
|
|
12
|
-
from .window import MapProjection
|
|
14
|
+
from .window import Area, MapProjection
|
|
13
15
|
from ._backends.enumeration import dtype as DataType
|
|
14
16
|
|
|
15
17
|
def read_raster(
|
|
@@ -161,3 +163,50 @@ def constant(value: int | float) -> YirgacheffeLayer:
|
|
|
161
163
|
A constant layer of the provided value.
|
|
162
164
|
"""
|
|
163
165
|
return ConstantLayer(value)
|
|
166
|
+
|
|
167
|
+
def from_array(
|
|
168
|
+
values: np.ndarray,
|
|
169
|
+
origin: tuple[float, float],
|
|
170
|
+
projection: MapProjection | tuple[str, tuple[float, float]],
|
|
171
|
+
) -> YirgacheffeLayer:
|
|
172
|
+
"""Creates an in-memory layer from a numerical array.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
values: a 2D array of data values, with Y on the first dimension, X on
|
|
176
|
+
the second dimension.
|
|
177
|
+
origin: the position of the top left pixel in the geospatial space
|
|
178
|
+
projection: the map projection and pixel scale to use.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
A geospatial layer that uses the provided data for its values.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
if projection is None:
|
|
185
|
+
raise ValueError("Projection must not be none")
|
|
186
|
+
|
|
187
|
+
if not isinstance(projection, MapProjection):
|
|
188
|
+
projection_name, scale_tuple = projection
|
|
189
|
+
projection = MapProjection(projection_name, scale_tuple[0], scale_tuple[1])
|
|
190
|
+
|
|
191
|
+
dims = values.shape
|
|
192
|
+
|
|
193
|
+
area = Area(
|
|
194
|
+
left=origin[0],
|
|
195
|
+
top=origin[1],
|
|
196
|
+
right=origin[0] + (projection.xstep * dims[1]),
|
|
197
|
+
bottom=origin[1] + (projection.ystep * dims[0])
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
layer = RasterLayer.empty_raster_layer(
|
|
201
|
+
area,
|
|
202
|
+
scale=projection.scale,
|
|
203
|
+
datatype=DataType.of_array(values),
|
|
204
|
+
filename=None,
|
|
205
|
+
projection=projection.name,
|
|
206
|
+
)
|
|
207
|
+
assert layer._dataset
|
|
208
|
+
assert layer._dataset.RasterXSize == dims[1]
|
|
209
|
+
assert layer._dataset.RasterYSize == dims[0]
|
|
210
|
+
layer._dataset.GetRasterBand(1).WriteArray(values, 0, 0)
|
|
211
|
+
|
|
212
|
+
return layer
|
|
@@ -81,7 +81,7 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
81
81
|
|
|
82
82
|
@property
|
|
83
83
|
def datatype(self) -> DataType:
|
|
84
|
-
return
|
|
84
|
+
return self.layers[0].datatype
|
|
85
85
|
|
|
86
86
|
def set_window_for_intersection(self, new_area: Area) -> None:
|
|
87
87
|
super().set_window_for_intersection(new_area)
|
|
@@ -22,6 +22,15 @@ class MapProjection:
|
|
|
22
22
|
name: The map projection used in WKT format.
|
|
23
23
|
xstep: The number of units horizontal distance a step of one pixel makes in the map projection.
|
|
24
24
|
ystep: The number of units vertical distance a step of one pixel makes in the map projection.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
Create a map projection using an EPSG code:
|
|
28
|
+
|
|
29
|
+
>>> proj_wgs84 = MapProjection("epsg:4326", 0.001, -0.001)
|
|
30
|
+
|
|
31
|
+
Create a projection using an ESRI code:
|
|
32
|
+
|
|
33
|
+
>>> proj_esri = MapProjection("esri:54030", 1000, -1000)
|
|
25
34
|
"""
|
|
26
35
|
|
|
27
36
|
def __init__(self, projection_string: str, xstep: float, ystep: float) -> None:
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|