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.

Files changed (59) hide show
  1. {yirgacheffe-1.9.4/yirgacheffe.egg-info → yirgacheffe-1.9.5}/PKG-INFO +1 -1
  2. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/pyproject.toml +1 -1
  3. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_datatypes.py +46 -0
  4. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_multiband.py +7 -5
  5. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_openers.py +26 -0
  6. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_operators.py +24 -23
  7. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_reduce.py +4 -3
  8. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/__init__.py +1 -1
  9. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/enumeration.py +30 -1
  10. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_core.py +50 -1
  11. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/group.py +1 -1
  12. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/window.py +9 -0
  13. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5/yirgacheffe.egg-info}/PKG-INFO +1 -1
  14. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/LICENSE +0 -0
  15. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/MANIFEST.in +0 -0
  16. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/README.md +0 -0
  17. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/setup.cfg +0 -0
  18. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_area.py +0 -0
  19. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_auto_windowing.py +0 -0
  20. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_constants.py +0 -0
  21. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_group.py +0 -0
  22. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_h3layer.py +0 -0
  23. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_intersection.py +0 -0
  24. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_nodata.py +0 -0
  25. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_optimisation.py +0 -0
  26. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_parallel_operators.py +0 -0
  27. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_pickle.py +0 -0
  28. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_pixel_coord.py +0 -0
  29. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_projection.py +0 -0
  30. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_raster.py +0 -0
  31. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_rescaling.py +0 -0
  32. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_rounding.py +0 -0
  33. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_save_with_window.py +0 -0
  34. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_sum_with_window.py +0 -0
  35. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_uniform_area_layer.py +0 -0
  36. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_union.py +0 -0
  37. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_vectors.py +0 -0
  38. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/tests/test_window.py +0 -0
  39. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/__init__.py +0 -0
  40. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/mlx.py +0 -0
  41. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_backends/numpy.py +0 -0
  42. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/_operators.py +0 -0
  43. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/constants.py +0 -0
  44. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/__init__.py +0 -0
  45. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/area.py +0 -0
  46. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/base.py +0 -0
  47. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/constant.py +0 -0
  48. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/h3layer.py +0 -0
  49. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/rasters.py +0 -0
  50. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/rescaled.py +0 -0
  51. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/layers/vectors.py +0 -0
  52. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/operators.py +0 -0
  53. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/py.typed +0 -0
  54. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe/rounding.py +0 -0
  55. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/SOURCES.txt +0 -0
  56. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/dependency_links.txt +0 -0
  57. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/entry_points.txt +0 -0
  58. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/yirgacheffe.egg-info/requires.txt +0 -0
  59. {yirgacheffe-1.9.4 → yirgacheffe-1.9.5}/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.9.4
3
+ Version: 1.9.5
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
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "yirgacheffe"
9
- version = "1.9.4"
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
- from tests.helpers import gdal_dataset_with_data
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 = RasterLayer(gdal_dataset_with_data((-1.0, 1.0), 1.0, data1))
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 = RasterLayer.layer_from_file(target_path, band=i+1)
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 = RasterLayer(gdal_dataset_with_data((-100+i, 100+i), 1, data1))
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 = RasterLayer.layer_from_file(target_path, band=i+1)
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe.constants, "YSTEP", 1)
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 yirgacheffe.read_raster(src_filename) as layer1:
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(yirgacheffe._backends.BACKEND != "NUMPY", reason="Only applies for numpy")
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(yirgacheffe.constants, "YSTEP", 1)
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 yirgacheffe.read_raster(src_filename) as layer1:
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), yirgacheffe.WGS_84_PROJECTION)
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), yirgacheffe.WGS_84_PROJECTION)
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe.constants, "YSTEP", blocksize)
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(yirgacheffe.constants, "YSTEP", blocksize)
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
- RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data1)) as layer1,
1699
- RasterLayer(gdal_dataset_with_data((0.0, 0.0), 0.02, data2)) as layer2,
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
- from yirgacheffe.layers import RasterLayer
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
- layers = [RasterLayer(gdal_dataset_with_data((0,0), 1.0, x)) for x in data]
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 DataType.of_gdal(self.layers[0].datatype)
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yirgacheffe
3
- Version: 1.9.4
3
+ Version: 1.9.5
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
File without changes
File without changes
File without changes
File without changes