yirgacheffe 1.6.1__py3-none-any.whl → 1.7.1__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.
yirgacheffe/operators.py CHANGED
@@ -12,14 +12,15 @@ from multiprocessing.managers import SharedMemoryManager
12
12
  from pathlib import Path
13
13
  from typing import Callable, Dict, Optional, Union
14
14
 
15
+ import deprecation
15
16
  import numpy as np
16
17
  import numpy.typing as npt
17
18
  from osgeo import gdal
18
19
  from dill import dumps, loads # type: ignore
19
20
 
20
- from . import constants
21
- from .rounding import are_pixel_scales_equal_enough, round_up_pixels, round_down_pixels
22
- from .window import Area, PixelScale, Window
21
+ from . import constants, __version__
22
+ from .rounding import round_up_pixels, round_down_pixels
23
+ from .window import Area, PixelScale, MapProjection, Window
23
24
  from ._backends import backend
24
25
  from ._backends.enumeration import operators as op
25
26
  from ._backends.enumeration import dtype as DataType
@@ -38,14 +39,17 @@ class LayerConstant:
38
39
  def __init__(self, val):
39
40
  self.val = val
40
41
 
41
- def __str__(self):
42
+ def __str__(self) -> str:
42
43
  return str(self.val)
43
44
 
44
- def _eval(self, _area, _index, _step, _target_window):
45
+ def _eval(self, _area, _projection, _index, _step, _target_window):
45
46
  return self.val
46
47
 
47
48
  @property
48
- def area(self):
49
+ def area(self) -> Area:
50
+ return Area.world()
51
+
52
+ def _get_operation_area(self, _projection) -> Area:
49
53
  return Area.world()
50
54
 
51
55
  class LayerMathMixin:
@@ -95,12 +99,26 @@ class LayerMathMixin:
95
99
  def __or__(self, other):
96
100
  return LayerOperation(self, op.OR, other, window_op=WindowOperation.UNION)
97
101
 
98
- def _eval(self, area, index, step, target_window=None):
102
+ def _eval(
103
+ self,
104
+ area,
105
+ projection,
106
+ index,
107
+ step,
108
+ target_window=None
109
+ ):
99
110
  try:
100
111
  window = self.window if target_window is None else target_window
101
- return self._read_array_for_area(area, 0, index, window.xsize, step)
112
+ return self._read_array_for_area(area, projection, 0, index, window.xsize, step)
102
113
  except AttributeError:
103
- return self._read_array_for_area(area, 0, index, target_window.xsize if target_window else 1, step)
114
+ return self._read_array_for_area(
115
+ area,
116
+ projection,
117
+ 0,
118
+ index,
119
+ target_window.xsize if target_window else 1,
120
+ step
121
+ )
104
122
 
105
123
  def nan_to_num(self, nan=0, posinf=None, neginf=None):
106
124
  return LayerOperation(
@@ -314,7 +332,7 @@ class LayerOperation(LayerMathMixin):
314
332
  else:
315
333
  raise ValueError("Numpy arrays are no allowed")
316
334
  else:
317
- if not are_pixel_scales_equal_enough([lhs.pixel_scale, rhs.pixel_scale]):
335
+ if not lhs.map_projection == rhs.map_projection:
318
336
  raise ValueError("Not all layers are at the same pixel scale")
319
337
  self.rhs = rhs
320
338
  else:
@@ -329,7 +347,7 @@ class LayerOperation(LayerMathMixin):
329
347
  else:
330
348
  raise ValueError("Numpy arrays are no allowed")
331
349
  else:
332
- if not are_pixel_scales_equal_enough([lhs.pixel_scale, other.pixel_scale]):
350
+ if not lhs.map_projection == other.map_projection:
333
351
  raise ValueError("Not all layers are at the same pixel scale")
334
352
  self.other = other
335
353
  else:
@@ -403,7 +421,56 @@ class LayerOperation(LayerMathMixin):
403
421
  case _:
404
422
  assert False, "Should not be reached"
405
423
 
424
+ def _get_operation_area(self, projection: Optional[MapProjection]) -> Area:
425
+
426
+ # The type().__name__ here is to avoid a circular import dependancy
427
+ lhs_area = self.lhs._get_operation_area(projection)
428
+ try:
429
+ rhs_area = self.rhs._get_operation_area(projection)
430
+ except AttributeError:
431
+ rhs_area = None
432
+ try:
433
+ other_area = self.other._get_operation_area(projection)
434
+ except AttributeError:
435
+ other_area = None
436
+
437
+ all_areas = [x for x in [lhs_area, rhs_area, other_area] if (x is not None) and (not x.is_world)]
438
+
439
+ match self.window_op:
440
+ case WindowOperation.NONE:
441
+ return all_areas[0]
442
+ case WindowOperation.LEFT:
443
+ return lhs_area
444
+ case WindowOperation.RIGHT:
445
+ assert rhs_area is not None
446
+ return rhs_area
447
+ case WindowOperation.INTERSECTION:
448
+ intersection = Area(
449
+ left=max(x.left for x in all_areas),
450
+ top=min(x.top for x in all_areas),
451
+ right=min(x.right for x in all_areas),
452
+ bottom=max(x.bottom for x in all_areas)
453
+ )
454
+ if (intersection.left >= intersection.right) or (intersection.bottom >= intersection.top):
455
+ raise ValueError('No intersection possible')
456
+ return intersection
457
+ case WindowOperation.UNION:
458
+ return Area(
459
+ left=min(x.left for x in all_areas),
460
+ top=max(x.top for x in all_areas),
461
+ right=max(x.right for x in all_areas),
462
+ bottom=min(x.bottom for x in all_areas)
463
+ )
464
+ case _:
465
+ assert False, "Should not be reached"
466
+
406
467
  @property
468
+ @deprecation.deprecated(
469
+ deprecated_in="1.7",
470
+ removed_in="2.0",
471
+ current_version=__version__,
472
+ details="Use `map_projection` instead."
473
+ )
407
474
  def pixel_scale(self) -> PixelScale:
408
475
  # Because we test at construction that pixel scales for RHS/other are roughly equal,
409
476
  # I believe this should be sufficient...
@@ -418,19 +485,22 @@ class LayerOperation(LayerMathMixin):
418
485
 
419
486
  @property
420
487
  def window(self) -> Window:
421
- pixel_scale = self.pixel_scale
422
- area = self.area
488
+ projection = self.map_projection
489
+ if projection is None:
490
+ # This can happen if your source layers are say just constants
491
+ raise AttributeError("No window without projection")
492
+ area = self._get_operation_area(projection)
423
493
  assert area is not None
424
494
 
425
495
  return Window(
426
- xoff=round_down_pixels(area.left / pixel_scale.xstep, pixel_scale.xstep),
427
- yoff=round_down_pixels(area.top / (pixel_scale.ystep * -1.0), pixel_scale.ystep * -1.0),
496
+ xoff=round_down_pixels(area.left / projection.xstep, projection.xstep),
497
+ yoff=round_down_pixels(area.top / (projection.ystep * -1.0), projection.ystep * -1.0),
428
498
  xsize=round_up_pixels(
429
- (area.right - area.left) / pixel_scale.xstep, pixel_scale.xstep
499
+ (area.right - area.left) / projection.xstep, projection.xstep
430
500
  ),
431
501
  ysize=round_up_pixels(
432
- (area.top - area.bottom) / (pixel_scale.ystep * -1.0),
433
- (pixel_scale.ystep * -1.0)
502
+ (area.top - area.bottom) / (projection.ystep * -1.0),
503
+ (projection.ystep * -1.0)
434
504
  ),
435
505
  )
436
506
 
@@ -440,23 +510,53 @@ class LayerOperation(LayerMathMixin):
440
510
  return self.lhs.datatype
441
511
 
442
512
  @property
513
+ @deprecation.deprecated(
514
+ deprecated_in="1.7",
515
+ removed_in="2.0",
516
+ current_version=__version__,
517
+ details="Use `map_projection` instead."
518
+ )
443
519
  def projection(self):
444
520
  try:
445
- return self.lhs.projection
521
+ projection = self.lhs.projection
446
522
  except AttributeError:
447
- return self.rhs.projection
523
+ projection = None
448
524
 
449
- def _eval(self, area: Area, index: int, step: int, target_window:Optional[Window]=None):
525
+ if projection is None:
526
+ projection = self.rhs.projection
527
+ return projection
528
+
529
+ @property
530
+ def map_projection(self) -> Optional[MapProjection]:
531
+ try:
532
+ projection = self.lhs.map_projection
533
+ except AttributeError:
534
+ projection = None
535
+
536
+ if projection is None:
537
+ try:
538
+ projection = self.rhs.map_projection
539
+ except AttributeError:
540
+ pass
541
+ return projection
542
+
543
+ def _eval(
544
+ self,
545
+ area: Area,
546
+ projection: MapProjection,
547
+ index: int,
548
+ step: int,
549
+ target_window:Optional[Window]=None
550
+ ):
450
551
 
451
552
  if self.buffer_padding:
452
553
  if target_window:
453
554
  target_window = target_window.grow(self.buffer_padding)
454
- pixel_scale = self.pixel_scale
455
- area = area.grow(self.buffer_padding * pixel_scale.xstep)
555
+ area = area.grow(self.buffer_padding * projection.xstep)
456
556
  # The index doesn't need updating because we updated area/window
457
557
  step += (2 * self.buffer_padding)
458
558
 
459
- lhs_data = self.lhs._eval(area, index, step, target_window)
559
+ lhs_data = self.lhs._eval(area, projection, index, step, target_window)
460
560
 
461
561
  if self.operator is None:
462
562
  return lhs_data
@@ -469,12 +569,12 @@ class LayerOperation(LayerMathMixin):
469
569
 
470
570
  if self.other is not None:
471
571
  assert self.rhs is not None
472
- rhs_data = self.rhs._eval(area, index, step, target_window)
473
- other_data = self.other._eval(area, index, step, target_window)
572
+ rhs_data = self.rhs._eval(area, projection, index, step, target_window)
573
+ other_data = self.other._eval(area, projection, index, step, target_window)
474
574
  return operator(lhs_data, rhs_data, other_data, **self.kwargs)
475
575
 
476
576
  if self.rhs is not None:
477
- rhs_data = self.rhs._eval(area, index, step, target_window)
577
+ rhs_data = self.rhs._eval(area, projection, index, step, target_window)
478
578
  return operator(lhs_data, rhs_data, **self.kwargs)
479
579
 
480
580
  return operator(lhs_data, **self.kwargs)
@@ -486,22 +586,24 @@ class LayerOperation(LayerMathMixin):
486
586
  # of the sum are done in different types.
487
587
  res = 0.0
488
588
  computation_window = self.window
589
+ projection = self.map_projection
489
590
  for yoffset in range(0, computation_window.ysize, self.ystep):
490
591
  step=self.ystep
491
592
  if yoffset+step > computation_window.ysize:
492
593
  step = computation_window.ysize - yoffset
493
- chunk = self._eval(self.area, yoffset, step, computation_window)
594
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
494
595
  res += backend.sum_op(chunk)
495
596
  return res
496
597
 
497
598
  def min(self):
498
599
  res = None
499
600
  computation_window = self.window
601
+ projection = self.map_projection
500
602
  for yoffset in range(0, computation_window.ysize, self.ystep):
501
603
  step=self.ystep
502
604
  if yoffset+step > computation_window.ysize:
503
605
  step = computation_window.ysize - yoffset
504
- chunk = self._eval(self.area, yoffset, step, computation_window)
606
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
505
607
  chunk_min = backend.min_op(chunk)
506
608
  if (res is None) or (res > chunk_min):
507
609
  res = chunk_min
@@ -510,11 +612,12 @@ class LayerOperation(LayerMathMixin):
510
612
  def max(self):
511
613
  res = None
512
614
  computation_window = self.window
615
+ projection = self.map_projection
513
616
  for yoffset in range(0, computation_window.ysize, self.ystep):
514
617
  step=self.ystep
515
618
  if yoffset+step > computation_window.ysize:
516
619
  step = computation_window.ysize - yoffset
517
- chunk = self._eval(self.area, yoffset, step, computation_window)
620
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
518
621
  chunk_max = backend.max_op(chunk)
519
622
  if (res is None) or (chunk_max > res):
520
623
  res = chunk_max
@@ -533,14 +636,24 @@ class LayerOperation(LayerMathMixin):
533
636
  except AttributeError as exc:
534
637
  raise ValueError("Layer must be a raster backed layer") from exc
535
638
 
639
+ projection = self.map_projection
640
+
536
641
  destination_window = destination_layer.window
642
+ destination_projection = destination_layer.map_projection
643
+ assert destination_projection is not None
644
+
645
+ if projection is None:
646
+ projection = destination_projection
647
+ else:
648
+ if projection != destination_projection:
649
+ raise ValueError("Destination layer and input layers have different projection/scale")
537
650
 
538
651
  # If we're calculating purely from a constant layer, then we don't have a window or area
539
652
  # so we should use the destination raster details.
540
653
  try:
541
654
  computation_window = self.window
542
- computation_area = self.area
543
- except AttributeError:
655
+ computation_area = self._get_operation_area(projection)
656
+ except (AttributeError, IndexError):
544
657
  computation_window = destination_window
545
658
  computation_area = destination_layer.area
546
659
 
@@ -556,7 +669,7 @@ class LayerOperation(LayerMathMixin):
556
669
  step=self.ystep
557
670
  if yoffset+step > computation_window.ysize:
558
671
  step = computation_window.ysize - yoffset
559
- chunk = self._eval(computation_area, yoffset, step, computation_window)
672
+ chunk = self._eval(computation_area, projection, yoffset, step, computation_window)
560
673
  if isinstance(chunk, (float, int)):
561
674
  chunk = backend.full((step, destination_window.xsize), chunk)
562
675
  band.WriteArray(
@@ -573,7 +686,7 @@ class LayerOperation(LayerMathMixin):
573
686
 
574
687
  def _parallel_worker(self, index, shared_mem, sem, np_dtype, width, input_queue, output_queue, computation_window):
575
688
  arr = np.ndarray((self.ystep, width), dtype=np_dtype, buffer=shared_mem.buf)
576
-
689
+ projection = self.map_projection
577
690
  try:
578
691
  while True:
579
692
  # We acquire the lock so we know we have somewhere to put the
@@ -591,7 +704,7 @@ class LayerOperation(LayerMathMixin):
591
704
  break
592
705
  yoffset, step = task
593
706
 
594
- result = self._eval(self.area, yoffset, step, computation_window)
707
+ result = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
595
708
  backend.eval_op(result)
596
709
 
597
710
  arr[:step] = backend.demote_array(result)
@@ -628,7 +741,7 @@ class LayerOperation(LayerMathMixin):
628
741
  assert (destination_layer is not None) or and_sum
629
742
  try:
630
743
  computation_window = self.window
631
- except AttributeError:
744
+ except (AttributeError, IndexError):
632
745
  # This is most likely because the calculation is on a constant layer (or combination of only constant
633
746
  # layers) and there's no real benefit to parallel saving then, so to keep this code from getting yet
634
747
  # more complicated just fall back to the single threaded path
@@ -828,12 +941,12 @@ class LayerOperation(LayerMathMixin):
828
941
 
829
942
  class ShaderStyleOperation(LayerOperation):
830
943
 
831
- def _eval(self, area, index, step, target_window=None):
944
+ def _eval(self, area, projection, index, step, target_window=None):
832
945
  if target_window is None:
833
946
  target_window = self.window
834
- lhs_data = self.lhs._eval(area, index, step, target_window)
947
+ lhs_data = self.lhs._eval(area, projection, index, step, target_window)
835
948
  if self.rhs is not None:
836
- rhs_data = self.rhs._eval(area, index, step, target_window)
949
+ rhs_data = self.rhs._eval(area, projection, index, step, target_window)
837
950
  else:
838
951
  rhs_data = None
839
952
 
yirgacheffe/window.py CHANGED
@@ -7,6 +7,47 @@ from typing import List, Optional, Tuple
7
7
 
8
8
  PixelScale = namedtuple('PixelScale', ['xstep', 'ystep'])
9
9
 
10
+ @dataclass
11
+ class MapProjection:
12
+ """Records the map projection and the size of the pixels in a layer.
13
+
14
+ This superceeeds the old PixelScale class, which will be removed in version 2.0.
15
+
16
+ Parameters
17
+ ----------
18
+ name : str
19
+ The map projection used.
20
+ xstep : float
21
+ The number of units horizontal distance a step of one pixel makes in the map projection.
22
+ ystep : float
23
+ The number of units verticle distance a step of one pixel makes in the map projection.
24
+
25
+ Attributes
26
+ ----------
27
+ name : str
28
+ The map projection used.
29
+ xstep : float
30
+ The number of units horizontal distance a step of one pixel makes in the map projection.
31
+ ystep : float
32
+ The number of units verticle distance a step of one pixel makes in the map projection.
33
+ """
34
+
35
+ name : str
36
+ xstep : float
37
+ ystep : float
38
+
39
+ def __eq__(self, other) -> bool:
40
+ if other is None:
41
+ return True
42
+ # to avoid circular dependancies
43
+ from .rounding import are_pixel_scales_equal_enough # pylint: disable=C0415
44
+ return (self.name == other.name) and \
45
+ are_pixel_scales_equal_enough([self.scale, other.scale])
46
+
47
+ @property
48
+ def scale(self) -> PixelScale:
49
+ return PixelScale(self.xstep, self.ystep)
50
+
10
51
  @dataclass
11
52
  class Area:
12
53
  """Class to hold a geospatial area of data in the given projection.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yirgacheffe
3
- Version: 1.6.1
3
+ Version: 1.7.1
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.read_shape_like('species123.geojson', like=habitat_map)
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', (0.001, -0.001), WGS_84_PROJECTION) as layer:
187
+ with yg.read_shape('range.gpkg') as layer:
186
188
  ...
187
189
  ```
188
190
 
189
- It is more common that when a shape file is loaded that its pixel size and projection will want to be made to match that of an existing raster (as per the opening area of habitat example). For that there is the following convenience method:
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
- with yg.read_raster("test.tif") as raster_layer:
194
- with yg.read_shape_like('range.gpkg', raster_layer) as shape_layer:
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
@@ -0,0 +1,25 @@
1
+ yirgacheffe/__init__.py,sha256=flTXNQQs6k8nboEv9O4eJnlv8kZ11z5zrfWcmUovCLg,537
2
+ yirgacheffe/_core.py,sha256=2CtRkVOpXBhFnj4fnpwSQBL3lJIvAmQJ4AgsMmKJOSs,4193
3
+ yirgacheffe/constants.py,sha256=uCWJwec3-ND-zVxYbsk1sdHKANl3ToNCTPg7MZb0j2g,434
4
+ yirgacheffe/operators.py,sha256=fqk61NW_BjNuuBVPx_nvxPbgBs839cx6WztGOxrtiuE,35653
5
+ yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
6
+ yirgacheffe/window.py,sha256=0Wy3BT4SZLyviDwzLcX8LYOo2MeZ2zXCWAiJNpMbQpc,9505
7
+ yirgacheffe/_backends/__init__.py,sha256=jN-2iRrHStnPI6cNL7XhwhsROtI0EaGfIrbF5c-ECV0,334
8
+ yirgacheffe/_backends/enumeration.py,sha256=pADawllxpW_hW-IVVvZpHWIKzvEMs9aaqfkZRD1zjnY,1003
9
+ yirgacheffe/_backends/mlx.py,sha256=2vOTMqHbQbeqt81Eq_8hxWDXZHaPsDpbXkALRVGEnnw,6130
10
+ yirgacheffe/_backends/numpy.py,sha256=cYO628s4-5K_-Bp3CrnHegzYSZfkt2QC8iE9oOOMtvA,4069
11
+ yirgacheffe/layers/__init__.py,sha256=mYKjw5YTcMNv_hMy7a6K4yRzIuNUbR8WuBTw4WIAmSk,435
12
+ yirgacheffe/layers/area.py,sha256=OFOM1_dMblzXLW29TwEqfdgSecl6aNs04bKJwUydLH0,3914
13
+ yirgacheffe/layers/base.py,sha256=4BjtEBzAHBWu06k-9Q7J1bm11xNILKDgA2cxuARxVyI,14344
14
+ yirgacheffe/layers/constant.py,sha256=XQ1ibeSckAcUOow-dMUlZiW5S2MKeFquOz_m8Y027GI,1437
15
+ yirgacheffe/layers/group.py,sha256=QyrECH5IthmBVV1debqttNvZGVocE-azdayJsvd6qqI,16096
16
+ yirgacheffe/layers/h3layer.py,sha256=Ys6F-e4Jre7lbFBYErF_4oidQx22WkWMKpHpQ7pPDTs,9875
17
+ yirgacheffe/layers/rasters.py,sha256=-yECyz3Odhy1er0ilJ9bfLUseI2cTHfwqhP-H3ImUKo,13365
18
+ yirgacheffe/layers/rescaled.py,sha256=hkvsd7paDCyUViABxrAXdXPOZegdwiphibkdrBuRclk,3366
19
+ yirgacheffe/layers/vectors.py,sha256=OpZaV2MgM0v4-CbrCNy_AHv3T2bvV9PFytolIzPPXFc,19900
20
+ yirgacheffe-1.7.1.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
+ yirgacheffe-1.7.1.dist-info/METADATA,sha256=KJuxRRohoo57E8Vcaft3WsItttbVaFK5eAHsf0GRMos,22351
22
+ yirgacheffe-1.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ yirgacheffe-1.7.1.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
+ yirgacheffe-1.7.1.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
+ yirgacheffe-1.7.1.dist-info/RECORD,,
@@ -1,25 +0,0 @@
1
- yirgacheffe/__init__.py,sha256=n0v998xPOMMS6hdAQ16UNzmJUdnN5612HRtdudwjYa4,302
2
- yirgacheffe/_core.py,sha256=0E56yP63vUiwi0g6ntUzmKhOuWQWoh3sSD6Ui8SWWRI,4082
3
- yirgacheffe/constants.py,sha256=uCWJwec3-ND-zVxYbsk1sdHKANl3ToNCTPg7MZb0j2g,434
4
- yirgacheffe/operators.py,sha256=4REikGD_hDZjY3jfUfo4NmrrCXXu5hn1tYKedbwUlvg,31609
5
- yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
6
- yirgacheffe/window.py,sha256=kR8sHQ6lcixpndOWC18wLRgbgS8y00tq4Fkh8PLESvM,8209
7
- yirgacheffe/_backends/__init__.py,sha256=jN-2iRrHStnPI6cNL7XhwhsROtI0EaGfIrbF5c-ECV0,334
8
- yirgacheffe/_backends/enumeration.py,sha256=pADawllxpW_hW-IVVvZpHWIKzvEMs9aaqfkZRD1zjnY,1003
9
- yirgacheffe/_backends/mlx.py,sha256=2vOTMqHbQbeqt81Eq_8hxWDXZHaPsDpbXkALRVGEnnw,6130
10
- yirgacheffe/_backends/numpy.py,sha256=cYO628s4-5K_-Bp3CrnHegzYSZfkt2QC8iE9oOOMtvA,4069
11
- yirgacheffe/layers/__init__.py,sha256=mYKjw5YTcMNv_hMy7a6K4yRzIuNUbR8WuBTw4WIAmSk,435
12
- yirgacheffe/layers/area.py,sha256=Qs5N5XMrQwk7StE_Rky94X7BhavRxgRmpC6mXLeu2HQ,3905
13
- yirgacheffe/layers/base.py,sha256=AgFe1HoWNuJWm2z_CgEE5o-3j-5hdC8HuNpYIM_h8HE,12672
14
- yirgacheffe/layers/constant.py,sha256=PiRiAgcvOE1Li-fFItt6P_cj8IOlwTf_xi5G_iaqHok,1440
15
- yirgacheffe/layers/group.py,sha256=e3pyQb35Ma-CPqY0dB4xDjMk3m2DQzzKiMGLSbBMY7c,16292
16
- yirgacheffe/layers/h3layer.py,sha256=Hy8kJF9-EQnLaRbZlj4TLSRfpq2-dJga8x4jiiPUHYo,9919
17
- yirgacheffe/layers/rasters.py,sha256=stZOi0sojJqMybvtKpvzfXlFJwRUvW7mA77Q3B4nhzA,13296
18
- yirgacheffe/layers/rescaled.py,sha256=uam0dsidKpP97gQBig34zXefyNruUbwAnQaeuN68KE4,3104
19
- yirgacheffe/layers/vectors.py,sha256=4BCGRSzbkFfsGZwLsQS9WelMXV5hDCcLmGGW6mf6MjU,15839
20
- yirgacheffe-1.6.1.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
- yirgacheffe-1.6.1.dist-info/METADATA,sha256=fn6CGfn17HeAcGhGO1YEbBdc_9WUjTsTnTZPZfQFNU8,22402
22
- yirgacheffe-1.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- yirgacheffe-1.6.1.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
- yirgacheffe-1.6.1.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
- yirgacheffe-1.6.1.dist-info/RECORD,,