yirgacheffe 1.6.0__py3-none-any.whl → 1.7.0__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/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(
@@ -229,6 +247,14 @@ class LayerMathMixin:
229
247
  def parallel_sum(self, callback=None, parallelism=None, band=1):
230
248
  return LayerOperation(self).parallel_sum(callback, parallelism, band)
231
249
 
250
+ def to_geotiff(
251
+ self,
252
+ filename: Union[Path,str],
253
+ and_sum: bool = False,
254
+ parallelism:Optional[int]=None
255
+ ) -> Optional[float]:
256
+ return LayerOperation(self).to_geotiff(filename, and_sum, parallelism)
257
+
232
258
  def sum(self):
233
259
  return LayerOperation(self).sum()
234
260
 
@@ -306,7 +332,7 @@ class LayerOperation(LayerMathMixin):
306
332
  else:
307
333
  raise ValueError("Numpy arrays are no allowed")
308
334
  else:
309
- if not are_pixel_scales_equal_enough([lhs.pixel_scale, rhs.pixel_scale]):
335
+ if not lhs.map_projection == rhs.map_projection:
310
336
  raise ValueError("Not all layers are at the same pixel scale")
311
337
  self.rhs = rhs
312
338
  else:
@@ -321,7 +347,7 @@ class LayerOperation(LayerMathMixin):
321
347
  else:
322
348
  raise ValueError("Numpy arrays are no allowed")
323
349
  else:
324
- if not are_pixel_scales_equal_enough([lhs.pixel_scale, other.pixel_scale]):
350
+ if not lhs.map_projection == other.map_projection:
325
351
  raise ValueError("Not all layers are at the same pixel scale")
326
352
  self.other = other
327
353
  else:
@@ -395,7 +421,56 @@ class LayerOperation(LayerMathMixin):
395
421
  case _:
396
422
  assert False, "Should not be reached"
397
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
+
398
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
+ )
399
474
  def pixel_scale(self) -> PixelScale:
400
475
  # Because we test at construction that pixel scales for RHS/other are roughly equal,
401
476
  # I believe this should be sufficient...
@@ -410,19 +485,22 @@ class LayerOperation(LayerMathMixin):
410
485
 
411
486
  @property
412
487
  def window(self) -> Window:
413
- pixel_scale = self.pixel_scale
414
- 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)
415
493
  assert area is not None
416
494
 
417
495
  return Window(
418
- xoff=round_down_pixels(area.left / pixel_scale.xstep, pixel_scale.xstep),
419
- 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),
420
498
  xsize=round_up_pixels(
421
- (area.right - area.left) / pixel_scale.xstep, pixel_scale.xstep
499
+ (area.right - area.left) / projection.xstep, projection.xstep
422
500
  ),
423
501
  ysize=round_up_pixels(
424
- (area.top - area.bottom) / (pixel_scale.ystep * -1.0),
425
- (pixel_scale.ystep * -1.0)
502
+ (area.top - area.bottom) / (projection.ystep * -1.0),
503
+ (projection.ystep * -1.0)
426
504
  ),
427
505
  )
428
506
 
@@ -432,23 +510,53 @@ class LayerOperation(LayerMathMixin):
432
510
  return self.lhs.datatype
433
511
 
434
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
+ )
435
519
  def projection(self):
436
520
  try:
437
- return self.lhs.projection
521
+ projection = self.lhs.projection
438
522
  except AttributeError:
439
- return self.rhs.projection
523
+ projection = None
524
+
525
+ if projection is None:
526
+ projection = self.rhs.projection
527
+ return projection
440
528
 
441
- def _eval(self, area: Area, index: int, step: int, target_window:Optional[Window]=None):
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
+ ):
442
551
 
443
552
  if self.buffer_padding:
444
553
  if target_window:
445
554
  target_window = target_window.grow(self.buffer_padding)
446
- pixel_scale = self.pixel_scale
447
- area = area.grow(self.buffer_padding * pixel_scale.xstep)
555
+ area = area.grow(self.buffer_padding * projection.xstep)
448
556
  # The index doesn't need updating because we updated area/window
449
557
  step += (2 * self.buffer_padding)
450
558
 
451
- lhs_data = self.lhs._eval(area, index, step, target_window)
559
+ lhs_data = self.lhs._eval(area, projection, index, step, target_window)
452
560
 
453
561
  if self.operator is None:
454
562
  return lhs_data
@@ -461,12 +569,12 @@ class LayerOperation(LayerMathMixin):
461
569
 
462
570
  if self.other is not None:
463
571
  assert self.rhs is not None
464
- rhs_data = self.rhs._eval(area, index, step, target_window)
465
- 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)
466
574
  return operator(lhs_data, rhs_data, other_data, **self.kwargs)
467
575
 
468
576
  if self.rhs is not None:
469
- rhs_data = self.rhs._eval(area, index, step, target_window)
577
+ rhs_data = self.rhs._eval(area, projection, index, step, target_window)
470
578
  return operator(lhs_data, rhs_data, **self.kwargs)
471
579
 
472
580
  return operator(lhs_data, **self.kwargs)
@@ -478,22 +586,24 @@ class LayerOperation(LayerMathMixin):
478
586
  # of the sum are done in different types.
479
587
  res = 0.0
480
588
  computation_window = self.window
589
+ projection = self.map_projection
481
590
  for yoffset in range(0, computation_window.ysize, self.ystep):
482
591
  step=self.ystep
483
592
  if yoffset+step > computation_window.ysize:
484
593
  step = computation_window.ysize - yoffset
485
- chunk = self._eval(self.area, yoffset, step, computation_window)
594
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
486
595
  res += backend.sum_op(chunk)
487
596
  return res
488
597
 
489
598
  def min(self):
490
599
  res = None
491
600
  computation_window = self.window
601
+ projection = self.map_projection
492
602
  for yoffset in range(0, computation_window.ysize, self.ystep):
493
603
  step=self.ystep
494
604
  if yoffset+step > computation_window.ysize:
495
605
  step = computation_window.ysize - yoffset
496
- chunk = self._eval(self.area, yoffset, step, computation_window)
606
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
497
607
  chunk_min = backend.min_op(chunk)
498
608
  if (res is None) or (res > chunk_min):
499
609
  res = chunk_min
@@ -502,11 +612,12 @@ class LayerOperation(LayerMathMixin):
502
612
  def max(self):
503
613
  res = None
504
614
  computation_window = self.window
615
+ projection = self.map_projection
505
616
  for yoffset in range(0, computation_window.ysize, self.ystep):
506
617
  step=self.ystep
507
618
  if yoffset+step > computation_window.ysize:
508
619
  step = computation_window.ysize - yoffset
509
- chunk = self._eval(self.area, yoffset, step, computation_window)
620
+ chunk = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
510
621
  chunk_max = backend.max_op(chunk)
511
622
  if (res is None) or (chunk_max > res):
512
623
  res = chunk_max
@@ -525,14 +636,24 @@ class LayerOperation(LayerMathMixin):
525
636
  except AttributeError as exc:
526
637
  raise ValueError("Layer must be a raster backed layer") from exc
527
638
 
639
+ projection = self.map_projection
640
+
528
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")
529
650
 
530
651
  # If we're calculating purely from a constant layer, then we don't have a window or area
531
652
  # so we should use the destination raster details.
532
653
  try:
533
654
  computation_window = self.window
534
- computation_area = self.area
535
- except AttributeError:
655
+ computation_area = self._get_operation_area(projection)
656
+ except (AttributeError, IndexError):
536
657
  computation_window = destination_window
537
658
  computation_area = destination_layer.area
538
659
 
@@ -548,7 +669,7 @@ class LayerOperation(LayerMathMixin):
548
669
  step=self.ystep
549
670
  if yoffset+step > computation_window.ysize:
550
671
  step = computation_window.ysize - yoffset
551
- chunk = self._eval(computation_area, yoffset, step, computation_window)
672
+ chunk = self._eval(computation_area, projection, yoffset, step, computation_window)
552
673
  if isinstance(chunk, (float, int)):
553
674
  chunk = backend.full((step, destination_window.xsize), chunk)
554
675
  band.WriteArray(
@@ -565,7 +686,7 @@ class LayerOperation(LayerMathMixin):
565
686
 
566
687
  def _parallel_worker(self, index, shared_mem, sem, np_dtype, width, input_queue, output_queue, computation_window):
567
688
  arr = np.ndarray((self.ystep, width), dtype=np_dtype, buffer=shared_mem.buf)
568
-
689
+ projection = self.map_projection
569
690
  try:
570
691
  while True:
571
692
  # We acquire the lock so we know we have somewhere to put the
@@ -583,7 +704,7 @@ class LayerOperation(LayerMathMixin):
583
704
  break
584
705
  yoffset, step = task
585
706
 
586
- result = self._eval(self.area, yoffset, step, computation_window)
707
+ result = self._eval(self._get_operation_area(projection), projection, yoffset, step, computation_window)
587
708
  backend.eval_op(result)
588
709
 
589
710
  arr[:step] = backend.demote_array(result)
@@ -620,7 +741,7 @@ class LayerOperation(LayerMathMixin):
620
741
  assert (destination_layer is not None) or and_sum
621
742
  try:
622
743
  computation_window = self.window
623
- except AttributeError:
744
+ except (AttributeError, IndexError):
624
745
  # This is most likely because the calculation is on a constant layer (or combination of only constant
625
746
  # layers) and there's no real benefit to parallel saving then, so to keep this code from getting yet
626
747
  # more complicated just fall back to the single threaded path
@@ -820,12 +941,12 @@ class LayerOperation(LayerMathMixin):
820
941
 
821
942
  class ShaderStyleOperation(LayerOperation):
822
943
 
823
- def _eval(self, area, index, step, target_window=None):
944
+ def _eval(self, area, projection, index, step, target_window=None):
824
945
  if target_window is None:
825
946
  target_window = self.window
826
- lhs_data = self.lhs._eval(area, index, step, target_window)
947
+ lhs_data = self.lhs._eval(area, projection, index, step, target_window)
827
948
  if self.rhs is not None:
828
- rhs_data = self.rhs._eval(area, index, step, target_window)
949
+ rhs_data = self.rhs._eval(area, projection, index, step, target_window)
829
950
  else:
830
951
  rhs_data = None
831
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.0
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.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...])
@@ -71,8 +73,8 @@ print(f'area for species 123: {aoh.sum()}')
71
73
  Similarly, you could save the result to a new raster layer:
72
74
 
73
75
  ```python
74
- ...
75
- aoh.to_geotiff("result.tif")
76
+ ...
77
+ aoh.to_geotiff("result.tif")
76
78
  ```
77
79
 
78
80
  Yirgacheffe will automatically infer if you want to do an intersection of maps or a union of the maps based on the operators you use (see below for a full table). You can explicitly override that if you want.
@@ -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=SjdIqNlIpePo2Ea5A88aqg1WSmqcmrqORRExBPuR-S0,4191
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=VCqN6oykGeS68IvKZ7my7otZo1lJpymAasIyw_zXY6E,14143
14
+ yirgacheffe/layers/constant.py,sha256=XQ1ibeSckAcUOow-dMUlZiW5S2MKeFquOz_m8Y027GI,1437
15
+ yirgacheffe/layers/group.py,sha256=tSkyJK6sp8VFxB8ieA3hzEeKLkP6cjW6iIOSLmdbL6c,16088
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=40XAgOAmkxY1liGizwgAaeVtYJYdkFCysh9HvzvmNOU,19731
20
+ yirgacheffe-1.7.0.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
+ yirgacheffe-1.7.0.dist-info/METADATA,sha256=DORzQDxIzC2lFGZki3xHzOdiCwzTOxJaWIBVjhso6_g,22351
22
+ yirgacheffe-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ yirgacheffe-1.7.0.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
+ yirgacheffe-1.7.0.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
+ yirgacheffe-1.7.0.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=03GKaGXn7E2VfA2UKwTUOinNuB7GtAhIO5XZec4jsFg,31364
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.0.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
21
- yirgacheffe-1.6.0.dist-info/METADATA,sha256=21WbEajGkbV-TBafy5uAjYLmGW7U0Lr2ur2IG4DXvkM,22410
22
- yirgacheffe-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- yirgacheffe-1.6.0.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
24
- yirgacheffe-1.6.0.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
25
- yirgacheffe-1.6.0.dist-info/RECORD,,