yirgacheffe 1.7.4__py3-none-any.whl → 1.7.6__py3-none-any.whl

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/__init__.py CHANGED
@@ -12,7 +12,7 @@ except ModuleNotFoundError:
12
12
  pyproject_data = tomllib.load(f)
13
13
  __version__ = pyproject_data["project"]["version"]
14
14
 
15
- from ._core import read_raster, read_rasters, read_shape, read_shape_like
15
+ from ._core import read_raster, read_rasters, read_shape, read_shape_like, constant, read_narrow_raster
16
16
  from .constants import WGS_84_PROJECTION
17
17
 
18
18
  gdal.UseExceptions()
yirgacheffe/_core.py CHANGED
@@ -1,7 +1,9 @@
1
1
  from pathlib import Path
2
2
  from typing import Optional, Sequence, Tuple, Union
3
3
 
4
+ from .layers.area import UniformAreaLayer
4
5
  from .layers.base import YirgacheffeLayer
6
+ from .layers.constant import ConstantLayer
5
7
  from .layers.group import GroupLayer, TiledGroupLayer
6
8
  from .layers.rasters import RasterLayer
7
9
  from .layers.vectors import VectorLayer
@@ -31,6 +33,33 @@ def read_raster(
31
33
  """
32
34
  return RasterLayer.layer_from_file(filename, band, ignore_nodata)
33
35
 
36
+ def read_narrow_raster(
37
+ filename: Union[Path,str],
38
+ band: int = 1,
39
+ ignore_nodata: bool = False,
40
+ ) -> RasterLayer:
41
+ """Open a 1 pixel wide raster file as a global raster.
42
+
43
+ This exists for the special use case where an area per pixel raster would have the same value per horizontal row
44
+ (e.g., a WGS84 map projection). For that case you can use this to load a raster that is 1 pixel wide and have
45
+ it automatically expanded to act like a global raster in calculations.
46
+
47
+ Parameters
48
+ ----------
49
+ filename : Path
50
+ Path of raster file to open.
51
+ band : int, default=1
52
+ For multi-band rasters, which band to use (defaults to first if not specified)
53
+ ignore_nodata : bool, default=False
54
+ If the GeoTIFF has a NODATA value, don't subsitute that value for NaN
55
+
56
+ Returns
57
+ -------
58
+ RasterLayer
59
+ Returns an layer representing the raster data.
60
+ """
61
+ return UniformAreaLayer.layer_from_file(filename, band, ignore_nodata)
62
+
34
63
  def read_rasters(
35
64
  filenames : Sequence[Union[Path,str]],
36
65
  tiled: bool=False
@@ -132,3 +161,23 @@ def read_shape_like(
132
161
  datatype,
133
162
  burn_value,
134
163
  )
164
+
165
+ def constant(value: Union[int,float]) -> ConstantLayer:
166
+ """Generate a layer that has the same value in all pixels regardless of scale, projection, and area.
167
+
168
+ Generally this should not be necessary unless you must have the constant as the first term in an
169
+ expression, as Yirgacheffe will automatically convert numbers into constant layers. However if the
170
+ constant is the first term in the expression it must be wrapped by this call otherwise Python will
171
+ not know that it should be part of the Yirgacheffe expression.
172
+
173
+ Parameters
174
+ ----------
175
+ value : int or float
176
+ The value to be in each pixel of the expression term.
177
+
178
+ Returns
179
+ -------
180
+ ConstantLayer
181
+ Returns a constant layer of the provided value.
182
+ """
183
+ return ConstantLayer(value)
@@ -97,8 +97,6 @@ class RasterLayer(YirgacheffeLayer):
97
97
  threads: Optional[int]=None,
98
98
  bands: int=1
99
99
  ) -> RasterLayer:
100
- width = layer.window.xsize
101
- height = layer.window.ysize
102
100
  if area is None:
103
101
  area = layer.area
104
102
  assert area is not None
@@ -117,6 +115,12 @@ class RasterLayer(YirgacheffeLayer):
117
115
  area.left, projection.xstep, 0.0, area.top, 0.0, projection.ystep
118
116
  )
119
117
 
118
+ if area is None:
119
+ og_width = layer.window.xsize
120
+ og_height = layer.window.ysize
121
+ assert (og_width == width) and (og_height == height), \
122
+ f"original size ({og_width}, {og_height}) != estimated ({width}, {height})"
123
+
120
124
  if datatype is None:
121
125
  datatype_arg = layer.datatype
122
126
  elif isinstance(datatype, int):
@@ -4,8 +4,10 @@ from pathlib import Path
4
4
  from typing import Any, Optional, Tuple, Union
5
5
  from typing_extensions import NotRequired
6
6
 
7
+ import deprecation
7
8
  from osgeo import gdal, ogr
8
9
 
10
+ from .. import __version__
9
11
  from ..operators import DataType
10
12
  from ..window import Area, MapProjection, PixelScale
11
13
  from .base import YirgacheffeLayer
@@ -60,6 +62,12 @@ class RasteredVectorLayer(RasterLayer):
60
62
  VectorLayer."""
61
63
 
62
64
  @classmethod
65
+ @deprecation.deprecated(
66
+ deprecated_in="1.7",
67
+ removed_in="2.0",
68
+ current_version=__version__,
69
+ details="Use `VectorLayer` instead."
70
+ )
63
71
  def layer_from_file( # type: ignore[override] # pylint: disable=W0221
64
72
  cls,
65
73
  filename: Union[Path,str],
yirgacheffe/operators.py CHANGED
@@ -387,50 +387,9 @@ class LayerOperation(LayerMathMixin):
387
387
 
388
388
  @property
389
389
  def area(self) -> Area:
390
- # The type().__name__ here is to avoid a circular import dependancy
391
- lhs_area = self.lhs.area
392
- try:
393
- rhs_area = self.rhs.area
394
- except AttributeError:
395
- rhs_area = None
396
- try:
397
- other_area = self.other.area
398
- except AttributeError:
399
- other_area = None
400
-
401
- all_areas = [x for x in [lhs_area, rhs_area, other_area] if (x is not None) and (not x.is_world)]
402
-
403
- match self.window_op:
404
- case WindowOperation.NONE:
405
- return all_areas[0]
406
- case WindowOperation.LEFT:
407
- return lhs_area
408
- case WindowOperation.RIGHT:
409
- assert rhs_area is not None
410
- return rhs_area
411
- case WindowOperation.INTERSECTION:
412
- intersection = Area(
413
- left=max(x.left for x in all_areas),
414
- top=min(x.top for x in all_areas),
415
- right=min(x.right for x in all_areas),
416
- bottom=max(x.bottom for x in all_areas)
417
- )
418
- if (intersection.left >= intersection.right) or (intersection.bottom >= intersection.top):
419
- raise ValueError('No intersection possible')
420
- return intersection
421
- case WindowOperation.UNION:
422
- return Area(
423
- left=min(x.left for x in all_areas),
424
- top=max(x.top for x in all_areas),
425
- right=max(x.right for x in all_areas),
426
- bottom=min(x.bottom for x in all_areas)
427
- )
428
- case _:
429
- assert False, "Should not be reached"
390
+ return self._get_operation_area(self.map_projection)
430
391
 
431
392
  def _get_operation_area(self, projection: Optional[MapProjection]) -> Area:
432
-
433
- # The type().__name__ here is to avoid a circular import dependancy
434
393
  lhs_area = self.lhs._get_operation_area(projection)
435
394
  try:
436
395
  rhs_area = self.rhs._get_operation_area(projection)
@@ -462,12 +421,13 @@ class LayerOperation(LayerMathMixin):
462
421
  raise ValueError('No intersection possible')
463
422
  return intersection
464
423
  case WindowOperation.UNION:
465
- return Area(
424
+ union = Area(
466
425
  left=min(x.left for x in all_areas),
467
426
  top=max(x.top for x in all_areas),
468
427
  right=max(x.right for x in all_areas),
469
428
  bottom=min(x.bottom for x in all_areas)
470
429
  )
430
+ return union
471
431
  case _:
472
432
  assert False, "Should not be reached"
473
433
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yirgacheffe
3
- Version: 1.7.4
3
+ Version: 1.7.6
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
@@ -262,17 +262,33 @@ Notes:
262
262
  * You can have missing tiles, and these will be filled in with zeros.
263
263
  * You can have tiles that overlap, so long as they still conform to the rule that all tiles are the same size and on a grid.
264
264
 
265
- ### ConstantLayer
265
+ ### Constants
266
266
 
267
- This is there to simplify code when you have some optional layers. Rather than littering your code with checks, you can just use a constant layer, which can be included in calculations and will just return an fixed value as if it wasn't there. Useful with 0.0 or 1.0 for sum or multiplication null layers.
267
+ At times it is useful to have a fixed constant in an expression. Typically, similar to numpy, if an expression involving layers has a constant in, Yirgacheffe will apply that to all pixels in the equation without need for further elaboration:
268
+
269
+ ```python
270
+ with yg.read_raster("some_data.tif") as layer:
271
+ doubled_layer = layer * 2.0
272
+ ...
273
+ ```
274
+
275
+ This can be useful in tasks where you have an optional layer in your code. For example, here the code optionally loads an area-per-pixel layer, which if not present can just be substituted with a 1.0:
268
276
 
269
277
  ```python
270
278
  try:
271
- area_layer = RasterLayer.layer_from_file('myarea.tiff')
279
+ area_layer = yg.read_raster('myarea.tiff')
272
280
  except FileDoesNotExist:
273
- area_layer = ConstantLayer(0.0)
281
+ area_layer = 1.0
274
282
  ```
275
283
 
284
+ However, as with numpy, Python can not make the correct inference if the constant value is the first term in the equation. In that case you need to explicitly wrap the value with `constant` to help Python understand what is happening:
285
+
286
+ ```python
287
+ with yg.read_raster("some_data.tif") as layer:
288
+ result = yg.constant(1.0) / layer
289
+ ```
290
+
291
+
276
292
  ### H3CellLayer
277
293
 
278
294
  If you have H3 installed, you can generate a mask layer based on an H3 cell identifier, where pixels inside the cell will have a value of 1, and those outside will have a value of 0.
@@ -1,7 +1,7 @@
1
- yirgacheffe/__init__.py,sha256=flTXNQQs6k8nboEv9O4eJnlv8kZ11z5zrfWcmUovCLg,537
2
- yirgacheffe/_core.py,sha256=2CtRkVOpXBhFnj4fnpwSQBL3lJIvAmQJ4AgsMmKJOSs,4193
1
+ yirgacheffe/__init__.py,sha256=pY9dqmHHARfY44T-7-7y6Ah97qQHj9_0pgYTItI5TR8,567
2
+ yirgacheffe/_core.py,sha256=C3TefRffw8n57AQGTNXgyEtXXZb9exZcRFg0yxNtqlo,6062
3
3
  yirgacheffe/constants.py,sha256=uCWJwec3-ND-zVxYbsk1sdHKANl3ToNCTPg7MZb0j2g,434
4
- yirgacheffe/operators.py,sha256=DNZFBHRqwlZq8HHNv72vU5jDBwikDCyuwyo8RmE59bg,36228
4
+ yirgacheffe/operators.py,sha256=PIF3ec2ogGf2-8D7m56usNNer1bOe0HA9kL5JOqpbnQ,34576
5
5
  yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
6
6
  yirgacheffe/window.py,sha256=0Wy3BT4SZLyviDwzLcX8LYOo2MeZ2zXCWAiJNpMbQpc,9505
7
7
  yirgacheffe/_backends/__init__.py,sha256=jN-2iRrHStnPI6cNL7XhwhsROtI0EaGfIrbF5c-ECV0,334
@@ -14,12 +14,12 @@ yirgacheffe/layers/base.py,sha256=MPVGEsFRPuRDYtL1OBu7XP26kBDWfpS3RS3twYKBOQc,14
14
14
  yirgacheffe/layers/constant.py,sha256=XQ1ibeSckAcUOow-dMUlZiW5S2MKeFquOz_m8Y027GI,1437
15
15
  yirgacheffe/layers/group.py,sha256=YgA0Bl0lAO2KwTT57126rXfyPq6MCssaaFrTQLe377s,16182
16
16
  yirgacheffe/layers/h3layer.py,sha256=Ys6F-e4Jre7lbFBYErF_4oidQx22WkWMKpHpQ7pPDTs,9875
17
- yirgacheffe/layers/rasters.py,sha256=-yECyz3Odhy1er0ilJ9bfLUseI2cTHfwqhP-H3ImUKo,13365
17
+ yirgacheffe/layers/rasters.py,sha256=w1lmZmvwU7tKUy84y8uqWNnVn-0T268VrsQTUKfQkP0,13565
18
18
  yirgacheffe/layers/rescaled.py,sha256=hkvsd7paDCyUViABxrAXdXPOZegdwiphibkdrBuRclk,3366
19
- yirgacheffe/layers/vectors.py,sha256=OpZaV2MgM0v4-CbrCNy_AHv3T2bvV9PFytolIzPPXFc,19900
20
- yirgacheffe-1.7.4.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
- yirgacheffe-1.7.4.dist-info/METADATA,sha256=-HBVApZog3E94bukfIQJD6SLrg9feJiLm8tLr2Kt7cU,22588
22
- yirgacheffe-1.7.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- yirgacheffe-1.7.4.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
- yirgacheffe-1.7.4.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
- yirgacheffe-1.7.4.dist-info/RECORD,,
19
+ yirgacheffe/layers/vectors.py,sha256=8tt0rCkhrT-HZi90rEvv8qL6cVSYLG5HZTqqTz6BuTU,20118
20
+ yirgacheffe-1.7.6.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
+ yirgacheffe-1.7.6.dist-info/METADATA,sha256=kUhrFtnD5Me9SSD0VBCk48z6YLJ9U7vU94Fto5VSDZY,23134
22
+ yirgacheffe-1.7.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ yirgacheffe-1.7.6.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
+ yirgacheffe-1.7.6.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
+ yirgacheffe-1.7.6.dist-info/RECORD,,