yirgacheffe 1.2.1__py3-none-any.whl → 1.3.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.
Potentially problematic release.
This version of yirgacheffe might be problematic. Click here for more details.
- yirgacheffe/backends/enumeration.py +24 -0
- yirgacheffe/backends/mlx.py +57 -1
- yirgacheffe/backends/numpy.py +87 -47
- yirgacheffe/layers/__init__.py +0 -1
- yirgacheffe/layers/base.py +2 -2
- yirgacheffe/layers/constant.py +3 -4
- yirgacheffe/layers/group.py +3 -2
- yirgacheffe/layers/h3layer.py +3 -3
- yirgacheffe/layers/rasters.py +16 -7
- yirgacheffe/layers/rescaled.py +2 -1
- yirgacheffe/layers/vectors.py +26 -9
- yirgacheffe/operators.py +14 -4
- {yirgacheffe-1.2.1.dist-info → yirgacheffe-1.3.1.dist-info}/METADATA +21 -1
- yirgacheffe-1.3.1.dist-info/RECORD +25 -0
- yirgacheffe-1.2.1.dist-info/RECORD +0 -25
- {yirgacheffe-1.2.1.dist-info → yirgacheffe-1.3.1.dist-info}/WHEEL +0 -0
- {yirgacheffe-1.2.1.dist-info → yirgacheffe-1.3.1.dist-info}/entry_points.txt +0 -0
- {yirgacheffe-1.2.1.dist-info → yirgacheffe-1.3.1.dist-info}/licenses/LICENSE +0 -0
- {yirgacheffe-1.2.1.dist-info → yirgacheffe-1.3.1.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
+
from osgeo import gdal
|
|
4
|
+
|
|
3
5
|
class operators(Enum):
|
|
4
6
|
ADD = 1
|
|
5
7
|
SUB = 2
|
|
@@ -32,3 +34,25 @@ class operators(Enum):
|
|
|
32
34
|
FLOORDIV = 29
|
|
33
35
|
CONV2D = 30
|
|
34
36
|
ABS = 31
|
|
37
|
+
ASTYPE = 32
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class dtype(Enum):
|
|
41
|
+
Float32 = gdal.GDT_Float32
|
|
42
|
+
Float64 = gdal.GDT_Float64
|
|
43
|
+
Byte = gdal.GDT_Byte
|
|
44
|
+
Int8 = gdal.GDT_Int8
|
|
45
|
+
Int16 = gdal.GDT_Int16
|
|
46
|
+
Int32 = gdal.GDT_Int32
|
|
47
|
+
Int64 = gdal.GDT_Int64
|
|
48
|
+
UInt8 = gdal.GDT_Byte
|
|
49
|
+
UInt16 = gdal.GDT_UInt16
|
|
50
|
+
UInt32 = gdal.GDT_UInt32
|
|
51
|
+
UInt64 = gdal.GDT_UInt64
|
|
52
|
+
|
|
53
|
+
def to_gdal(self):
|
|
54
|
+
return self.value
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def of_gdal(cls, val):
|
|
58
|
+
return cls(val)
|
yirgacheffe/backends/mlx.py
CHANGED
|
@@ -4,6 +4,7 @@ import mlx.core as mx # pylint: disable=E0001,E0611,E0401
|
|
|
4
4
|
import mlx.nn
|
|
5
5
|
|
|
6
6
|
from .enumeration import operators as op
|
|
7
|
+
from .enumeration import dtype
|
|
7
8
|
|
|
8
9
|
array_t = mx.array
|
|
9
10
|
float_t = mx.float32
|
|
@@ -121,9 +122,63 @@ def conv2d_op(data, weights):
|
|
|
121
122
|
preped_data = mx.array(np.reshape(unshifted_data_shape, conv_data_shape))
|
|
122
123
|
|
|
123
124
|
shifted_res = conv(preped_data)[0]
|
|
124
|
-
res =
|
|
125
|
+
res = mx.reshape(shifted_res, [1] + list(shifted_res.shape)[:-1])
|
|
125
126
|
return res[0]
|
|
126
127
|
|
|
128
|
+
|
|
129
|
+
def dtype_to_backed(dt):
|
|
130
|
+
match dt:
|
|
131
|
+
case dtype.Float32:
|
|
132
|
+
return mx.float32
|
|
133
|
+
case dtype.Float64:
|
|
134
|
+
return mx.float32
|
|
135
|
+
case dtype.Byte:
|
|
136
|
+
return mx.uint8
|
|
137
|
+
case dtype.Int8:
|
|
138
|
+
return mx.int8
|
|
139
|
+
case dtype.Int16:
|
|
140
|
+
return mx.int16
|
|
141
|
+
case dtype.Int32:
|
|
142
|
+
return mx.int32
|
|
143
|
+
case dtype.Int64:
|
|
144
|
+
return mx.int64
|
|
145
|
+
case dtype.UInt8:
|
|
146
|
+
return mx.uint8
|
|
147
|
+
case dtype.UInt16:
|
|
148
|
+
return mx.uint16
|
|
149
|
+
case dtype.UInt32:
|
|
150
|
+
return mx.uint32
|
|
151
|
+
case dtype.UInt64:
|
|
152
|
+
return mx.uint64
|
|
153
|
+
case _:
|
|
154
|
+
raise ValueError
|
|
155
|
+
|
|
156
|
+
def backend_to_dtype(val):
|
|
157
|
+
match val:
|
|
158
|
+
case mx.float32:
|
|
159
|
+
return dtype.Float32
|
|
160
|
+
case mx.int8:
|
|
161
|
+
return dtype.Int8
|
|
162
|
+
case mx.int16:
|
|
163
|
+
return dtype.Int16
|
|
164
|
+
case mx.int32:
|
|
165
|
+
return dtype.Int32
|
|
166
|
+
case mx.int64:
|
|
167
|
+
return dtype.Int64
|
|
168
|
+
case mx.uint8:
|
|
169
|
+
return dtype.Byte
|
|
170
|
+
case mx.uint16:
|
|
171
|
+
return dtype.UInt16
|
|
172
|
+
case mx.uint32:
|
|
173
|
+
return dtype.UInt32
|
|
174
|
+
case mx.uint64:
|
|
175
|
+
return dtype.UInt64
|
|
176
|
+
case _:
|
|
177
|
+
raise ValueError
|
|
178
|
+
|
|
179
|
+
def astype_op(data, datatype):
|
|
180
|
+
return data.astype(dtype_to_backed(datatype))
|
|
181
|
+
|
|
127
182
|
operator_map = {
|
|
128
183
|
op.ADD: mx.array.__add__,
|
|
129
184
|
op.SUB: mx.array.__sub__,
|
|
@@ -155,4 +210,5 @@ operator_map = {
|
|
|
155
210
|
op.FLOORDIV: mx.array.__floordiv__,
|
|
156
211
|
op.CONV2D: conv2d_op,
|
|
157
212
|
op.ABS: mx.abs,
|
|
213
|
+
op.ASTYPE: astype_op,
|
|
158
214
|
}
|
yirgacheffe/backends/numpy.py
CHANGED
|
@@ -3,6 +3,7 @@ import numpy as np
|
|
|
3
3
|
import torch
|
|
4
4
|
|
|
5
5
|
from .enumeration import operators as op
|
|
6
|
+
from .enumeration import dtype
|
|
6
7
|
|
|
7
8
|
array_t = np.ndarray
|
|
8
9
|
float_t = np.float64
|
|
@@ -61,52 +62,91 @@ def conv2d_op(data, weights):
|
|
|
61
62
|
res = conv(preped_data)
|
|
62
63
|
return res.detach().numpy()[0][0]
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
65
|
+
def dtype_to_backed(dt):
|
|
66
|
+
match dt:
|
|
67
|
+
case dtype.Float32:
|
|
68
|
+
return np.float32
|
|
69
|
+
case dtype.Float64:
|
|
70
|
+
return np.float64
|
|
71
|
+
case dtype.Byte:
|
|
72
|
+
return np.uint8
|
|
73
|
+
case dtype.Int8:
|
|
74
|
+
return np.int8
|
|
75
|
+
case dtype.Int16:
|
|
76
|
+
return np.int16
|
|
77
|
+
case dtype.Int32:
|
|
78
|
+
return np.int32
|
|
79
|
+
case dtype.Int64:
|
|
80
|
+
return np.int64
|
|
81
|
+
case dtype.UInt8:
|
|
82
|
+
return np.uint8
|
|
83
|
+
case dtype.UInt16:
|
|
84
|
+
return np.uint16
|
|
85
|
+
case dtype.UInt32:
|
|
86
|
+
return np.uint32
|
|
87
|
+
case dtype.UInt64:
|
|
88
|
+
return np.uint64
|
|
89
|
+
case _:
|
|
90
|
+
raise ValueError
|
|
91
|
+
|
|
92
|
+
def backend_to_dtype(val):
|
|
93
|
+
match val:
|
|
94
|
+
case np.float32:
|
|
95
|
+
return dtype.Float32
|
|
96
|
+
case np.float64:
|
|
97
|
+
return dtype.Float64
|
|
98
|
+
case np.int8:
|
|
99
|
+
return dtype.Int8
|
|
100
|
+
case np.int16:
|
|
101
|
+
return dtype.Int16
|
|
102
|
+
case np.int32:
|
|
103
|
+
return dtype.Int32
|
|
104
|
+
case np.int64:
|
|
105
|
+
return dtype.Int64
|
|
106
|
+
case np.uint8:
|
|
107
|
+
return dtype.Byte
|
|
108
|
+
case np.uint16:
|
|
109
|
+
return dtype.UInt16
|
|
110
|
+
case np.uint32:
|
|
111
|
+
return dtype.UInt32
|
|
112
|
+
case np.uint64:
|
|
113
|
+
return dtype.UInt64
|
|
114
|
+
case _:
|
|
115
|
+
raise ValueError
|
|
96
116
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
def astype_op(data, datatype):
|
|
118
|
+
return data.astype(dtype_to_backed(datatype))
|
|
119
|
+
|
|
120
|
+
operator_map = {
|
|
121
|
+
op.ADD: np.ndarray.__add__,
|
|
122
|
+
op.SUB: np.ndarray.__sub__,
|
|
123
|
+
op.MUL: np.ndarray.__mul__,
|
|
124
|
+
op.TRUEDIV: np.ndarray.__truediv__,
|
|
125
|
+
op.POW: np.ndarray.__pow__,
|
|
126
|
+
op.EQ: np.ndarray.__eq__,
|
|
127
|
+
op.NE: np.ndarray.__ne__,
|
|
128
|
+
op.LT: np.ndarray.__lt__,
|
|
129
|
+
op.LE: np.ndarray.__le__,
|
|
130
|
+
op.GT: np.ndarray.__gt__,
|
|
131
|
+
op.GE: np.ndarray.__ge__,
|
|
132
|
+
op.AND: np.ndarray.__and__,
|
|
133
|
+
op.OR: np.ndarray.__or__,
|
|
134
|
+
op.LOG: np.log,
|
|
135
|
+
op.LOG2: np.log2,
|
|
136
|
+
op.LOG10: np.log10,
|
|
137
|
+
op.EXP: np.exp,
|
|
138
|
+
op.EXP2: np.exp2,
|
|
139
|
+
op.CLIP: np.clip,
|
|
140
|
+
op.WHERE: np.where,
|
|
141
|
+
op.MIN: np.min,
|
|
142
|
+
op.MAX: np.max,
|
|
143
|
+
op.MINIMUM: np.minimum,
|
|
144
|
+
op.MAXIMUM: np.maximum,
|
|
145
|
+
op.NAN_TO_NUM: np.nan_to_num,
|
|
146
|
+
op.ISIN: np.isin,
|
|
147
|
+
op.REMAINDER: np.ndarray.__mod__,
|
|
148
|
+
op.FLOORDIV: np.ndarray.__floordiv__,
|
|
149
|
+
op.CONV2D: conv2d_op,
|
|
150
|
+
op.ABS: np.abs,
|
|
151
|
+
op.ASTYPE: astype_op,
|
|
112
152
|
}
|
yirgacheffe/layers/__init__.py
CHANGED
yirgacheffe/layers/base.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
from typing import Any, List, Optional, Tuple
|
|
3
3
|
|
|
4
|
-
from ..operators import LayerMathMixin
|
|
4
|
+
from ..operators import DataType, LayerMathMixin
|
|
5
5
|
from ..rounding import almost_equal, are_pixel_scales_equal_enough, round_up_pixels, round_down_pixels
|
|
6
6
|
from ..window import Area, PixelScale, Window
|
|
7
7
|
|
|
@@ -35,7 +35,7 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
35
35
|
self.close()
|
|
36
36
|
|
|
37
37
|
@property
|
|
38
|
-
def datatype(self) ->
|
|
38
|
+
def datatype(self) -> DataType:
|
|
39
39
|
raise NotImplementedError("Must be overridden by subclass")
|
|
40
40
|
|
|
41
41
|
@property
|
yirgacheffe/layers/constant.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Any, Union
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
3
|
+
from ..operators import DataType
|
|
5
4
|
from ..window import Area, PixelScale, Window
|
|
6
5
|
from .base import YirgacheffeLayer
|
|
7
6
|
from ..backends import backend
|
|
@@ -22,8 +21,8 @@ class ConstantLayer(YirgacheffeLayer):
|
|
|
22
21
|
self.value = float(value)
|
|
23
22
|
|
|
24
23
|
@property
|
|
25
|
-
def datatype(self) ->
|
|
26
|
-
return
|
|
24
|
+
def datatype(self) -> DataType:
|
|
25
|
+
return DataType.Float64
|
|
27
26
|
|
|
28
27
|
def check_pixel_scale(self, _scale: PixelScale) -> bool:
|
|
29
28
|
return True
|
yirgacheffe/layers/group.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
from typing import Any, List, Optional, TypeVar
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
+
from yirgacheffe.operators import DataType
|
|
7
8
|
|
|
8
9
|
from ..rounding import are_pixel_scales_equal_enough, round_down_pixels
|
|
9
10
|
from ..window import Area, Window
|
|
@@ -72,8 +73,8 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
72
73
|
pass
|
|
73
74
|
|
|
74
75
|
@property
|
|
75
|
-
def datatype(self):
|
|
76
|
-
return self.layers[0].datatype
|
|
76
|
+
def datatype(self) -> DataType:
|
|
77
|
+
return DataType.of_gdal(self.layers[0].datatype)
|
|
77
78
|
|
|
78
79
|
def set_window_for_intersection(self, new_area: Area) -> None:
|
|
79
80
|
super().set_window_for_intersection(new_area)
|
yirgacheffe/layers/h3layer.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import Any
|
|
|
3
3
|
|
|
4
4
|
import h3
|
|
5
5
|
import numpy as np
|
|
6
|
-
from
|
|
6
|
+
from yirgacheffe.operators import DataType
|
|
7
7
|
|
|
8
8
|
from ..rounding import round_up_pixels
|
|
9
9
|
from ..window import Area, PixelScale, Window
|
|
@@ -76,8 +76,8 @@ class H3CellLayer(YirgacheffeLayer):
|
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
@property
|
|
79
|
-
def datatype(self) ->
|
|
80
|
-
return
|
|
79
|
+
def datatype(self) -> DataType:
|
|
80
|
+
return DataType.Float64
|
|
81
81
|
|
|
82
82
|
def read_array_with_window(self, xoffset: int, yoffset: int, xsize: int, ysize: int, window: Window) -> Any:
|
|
83
83
|
if (xsize <= 0) or (ysize <= 0):
|
yirgacheffe/layers/rasters.py
CHANGED
|
@@ -9,6 +9,7 @@ from .. import WGS_84_PROJECTION
|
|
|
9
9
|
from ..window import Area, PixelScale, Window
|
|
10
10
|
from ..rounding import round_up_pixels
|
|
11
11
|
from .base import YirgacheffeLayer
|
|
12
|
+
from ..operators import DataType
|
|
12
13
|
from ..backends import backend
|
|
13
14
|
|
|
14
15
|
# Still to early to require Python 3.11 :/
|
|
@@ -27,7 +28,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
27
28
|
def empty_raster_layer(
|
|
28
29
|
area: Area,
|
|
29
30
|
scale: PixelScale,
|
|
30
|
-
datatype: int,
|
|
31
|
+
datatype: Union[int, DataType],
|
|
31
32
|
filename: Optional[str]=None,
|
|
32
33
|
projection: str=WGS_84_PROJECTION,
|
|
33
34
|
name: Optional[str]=None,
|
|
@@ -47,6 +48,10 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
47
48
|
bottom=math.floor(area.bottom / abs_ystep) * abs_ystep,
|
|
48
49
|
)
|
|
49
50
|
|
|
51
|
+
# This used to the the GDAL type, so we support that for legacy reasons
|
|
52
|
+
if isinstance(datatype, int):
|
|
53
|
+
datatype = DataType.of_gdal(datatype)
|
|
54
|
+
|
|
50
55
|
options = []
|
|
51
56
|
if threads is not None:
|
|
52
57
|
options.append(f"NUM_THREADS={threads}")
|
|
@@ -69,7 +74,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
69
74
|
round_up_pixels((pixel_friendly_area.right - pixel_friendly_area.left) / abs_xstep, abs_xstep),
|
|
70
75
|
round_up_pixels((pixel_friendly_area.top - pixel_friendly_area.bottom) / abs_ystep, abs_ystep),
|
|
71
76
|
bands,
|
|
72
|
-
datatype,
|
|
77
|
+
datatype.to_gdal(),
|
|
73
78
|
options
|
|
74
79
|
)
|
|
75
80
|
dataset.SetGeoTransform([
|
|
@@ -85,7 +90,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
85
90
|
layer: Any,
|
|
86
91
|
filename: Optional[str]=None,
|
|
87
92
|
area: Optional[Area]=None,
|
|
88
|
-
datatype: Optional[int]=None,
|
|
93
|
+
datatype: Optional[Union[int, DataType]]=None,
|
|
89
94
|
compress: bool=True,
|
|
90
95
|
nodata: Optional[Union[float,int]]=None,
|
|
91
96
|
nbits: Optional[int]=None,
|
|
@@ -98,6 +103,10 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
98
103
|
area = layer.area
|
|
99
104
|
assert area is not None
|
|
100
105
|
|
|
106
|
+
if datatype is not None:
|
|
107
|
+
if isinstance(datatype, int):
|
|
108
|
+
datatype = DataType.of_gdal(datatype)
|
|
109
|
+
|
|
101
110
|
scale = layer.pixel_scale
|
|
102
111
|
if scale is None:
|
|
103
112
|
raise ValueError("Can not work out area without explicit pixel scale")
|
|
@@ -130,7 +139,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
130
139
|
width,
|
|
131
140
|
height,
|
|
132
141
|
bands,
|
|
133
|
-
datatype if datatype is not None else layer.datatype,
|
|
142
|
+
(datatype if datatype is not None else layer.datatype).to_gdal(),
|
|
134
143
|
options,
|
|
135
144
|
)
|
|
136
145
|
dataset.SetGeoTransform(geo_transform)
|
|
@@ -181,7 +190,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
181
190
|
new_width,
|
|
182
191
|
new_height,
|
|
183
192
|
1,
|
|
184
|
-
source.datatype,
|
|
193
|
+
source.datatype.to_gdal(),
|
|
185
194
|
options
|
|
186
195
|
)
|
|
187
196
|
dataset.SetGeoTransform((
|
|
@@ -279,11 +288,11 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
279
288
|
raise FileNotFoundError(f"Failed to open pickled raster {self._dataset_path}") from exc
|
|
280
289
|
|
|
281
290
|
@property
|
|
282
|
-
def datatype(self) ->
|
|
291
|
+
def datatype(self) -> DataType:
|
|
283
292
|
if self._dataset is None:
|
|
284
293
|
self._unpark()
|
|
285
294
|
assert self._dataset
|
|
286
|
-
return self._dataset.GetRasterBand(1).DataType
|
|
295
|
+
return DataType.of_gdal(self._dataset.GetRasterBand(1).DataType)
|
|
287
296
|
|
|
288
297
|
def read_array_with_window(self, xoffset: int, yoffset: int, xsize: int, ysize: int, window: Window) -> Any:
|
|
289
298
|
if self._dataset is None:
|
yirgacheffe/layers/rescaled.py
CHANGED
|
@@ -2,6 +2,7 @@ from math import floor, ceil
|
|
|
2
2
|
from typing import Any, Optional
|
|
3
3
|
|
|
4
4
|
from skimage import transform
|
|
5
|
+
from yirgacheffe.operators import DataType
|
|
5
6
|
|
|
6
7
|
from ..window import PixelScale, Window
|
|
7
8
|
from .rasters import RasterLayer, YirgacheffeLayer
|
|
@@ -56,7 +57,7 @@ class RescaledRasterLayer(YirgacheffeLayer):
|
|
|
56
57
|
self._src._unpark()
|
|
57
58
|
|
|
58
59
|
@property
|
|
59
|
-
def datatype(self) ->
|
|
60
|
+
def datatype(self) -> DataType:
|
|
60
61
|
return self._src.datatype
|
|
61
62
|
|
|
62
63
|
def read_array_with_window(self, xoffset: int, yoffset: int, xsize: int, ysize: int, window: Window) -> Any:
|
yirgacheffe/layers/vectors.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing_extensions import NotRequired
|
|
|
5
5
|
|
|
6
6
|
from osgeo import gdal, ogr
|
|
7
7
|
|
|
8
|
+
from ..operators import DataType
|
|
8
9
|
from ..window import Area, PixelScale
|
|
9
10
|
from .base import YirgacheffeLayer
|
|
10
11
|
from .rasters import RasterLayer
|
|
@@ -64,7 +65,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
64
65
|
where_filter: Optional[str],
|
|
65
66
|
scale: PixelScale,
|
|
66
67
|
projection: str,
|
|
67
|
-
datatype: Optional[int] = None,
|
|
68
|
+
datatype: Optional[Union[int, DataType]] = None,
|
|
68
69
|
burn_value: Union[int,float,str] = 1,
|
|
69
70
|
): # pylint: disable=W0221
|
|
70
71
|
vectors = ogr.Open(filename)
|
|
@@ -78,6 +79,9 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
78
79
|
if datatype is None:
|
|
79
80
|
datatype = estimated_datatype
|
|
80
81
|
|
|
82
|
+
if isinstance(datatype, int):
|
|
83
|
+
datatype = DataType.of_gdal(datatype)
|
|
84
|
+
|
|
81
85
|
vector_layer = RasteredVectorLayer(
|
|
82
86
|
layer,
|
|
83
87
|
scale,
|
|
@@ -97,7 +101,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
97
101
|
layer: ogr.Layer,
|
|
98
102
|
scale: PixelScale,
|
|
99
103
|
projection: str,
|
|
100
|
-
datatype: int =
|
|
104
|
+
datatype: Union[int, DataType] = DataType.Byte,
|
|
101
105
|
burn_value: Union[int,float,str] = 1,
|
|
102
106
|
):
|
|
103
107
|
if layer is None:
|
|
@@ -106,6 +110,9 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
106
110
|
|
|
107
111
|
self._original = None
|
|
108
112
|
|
|
113
|
+
if isinstance(datatype, int):
|
|
114
|
+
datatype = DataType.of_gdal(datatype)
|
|
115
|
+
|
|
109
116
|
# work out region for mask
|
|
110
117
|
envelopes = []
|
|
111
118
|
layer.ResetReading()
|
|
@@ -135,7 +142,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
135
142
|
round((area.right - area.left) / abs_xstep),
|
|
136
143
|
round((area.top - area.bottom) / abs_ystep),
|
|
137
144
|
1,
|
|
138
|
-
datatype,
|
|
145
|
+
datatype.to_gdal(),
|
|
139
146
|
[]
|
|
140
147
|
)
|
|
141
148
|
if not dataset:
|
|
@@ -164,7 +171,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
164
171
|
filename: str,
|
|
165
172
|
other_layer: YirgacheffeLayer,
|
|
166
173
|
where_filter: Optional[str]=None,
|
|
167
|
-
datatype: Optional[int] = None,
|
|
174
|
+
datatype: Optional[Union[int, DataType]] = None,
|
|
168
175
|
burn_value: Union[int,float,str] = 1,
|
|
169
176
|
):
|
|
170
177
|
if other_layer is None:
|
|
@@ -179,6 +186,10 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
179
186
|
if where_filter is not None:
|
|
180
187
|
layer.SetAttributeFilter(where_filter)
|
|
181
188
|
|
|
189
|
+
if datatype is not None:
|
|
190
|
+
if isinstance(datatype, int):
|
|
191
|
+
datatype = DataType.of_gdal(datatype)
|
|
192
|
+
|
|
182
193
|
vector_layer = VectorLayer(
|
|
183
194
|
layer,
|
|
184
195
|
other_layer.pixel_scale,
|
|
@@ -205,7 +216,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
205
216
|
where_filter: Optional[str],
|
|
206
217
|
scale: PixelScale,
|
|
207
218
|
projection: str,
|
|
208
|
-
datatype: Optional[int] = None,
|
|
219
|
+
datatype: Optional[Union[int, DataType]] = None,
|
|
209
220
|
burn_value: Union[int,float,str] = 1,
|
|
210
221
|
anchor: Tuple[float,float] = (0.0, 0.0)
|
|
211
222
|
):
|
|
@@ -220,6 +231,9 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
220
231
|
if datatype is None:
|
|
221
232
|
datatype = estimated_datatype
|
|
222
233
|
|
|
234
|
+
if isinstance(datatype, int):
|
|
235
|
+
datatype = DataType.of_gdal(datatype)
|
|
236
|
+
|
|
223
237
|
vector_layer = VectorLayer(
|
|
224
238
|
layer,
|
|
225
239
|
scale,
|
|
@@ -244,7 +258,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
244
258
|
scale: PixelScale,
|
|
245
259
|
projection: str,
|
|
246
260
|
name: Optional[str] = None,
|
|
247
|
-
datatype: int =
|
|
261
|
+
datatype: Union[int,DataType] = DataType.Byte,
|
|
248
262
|
burn_value: Union[int,float,str] = 1,
|
|
249
263
|
anchor: Tuple[float,float] = (0.0, 0.0)
|
|
250
264
|
):
|
|
@@ -253,7 +267,10 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
253
267
|
self.layer = layer
|
|
254
268
|
self.name = name
|
|
255
269
|
|
|
256
|
-
|
|
270
|
+
if isinstance(datatype, int):
|
|
271
|
+
self._datatype = DataType.of_gdal(datatype)
|
|
272
|
+
else:
|
|
273
|
+
self._datatype = datatype
|
|
257
274
|
|
|
258
275
|
# If the burn value is a number, use it directly, if it's a string
|
|
259
276
|
# then assume it is a column name in the dataset
|
|
@@ -332,7 +349,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
332
349
|
self.layer.SetAttributeFilter(self._filter)
|
|
333
350
|
|
|
334
351
|
@property
|
|
335
|
-
def datatype(self) ->
|
|
352
|
+
def datatype(self) -> DataType:
|
|
336
353
|
return self._datatype
|
|
337
354
|
|
|
338
355
|
def read_array_for_area(self, target_area: Area, x: int, y: int, width: int, height: int) -> Any:
|
|
@@ -348,7 +365,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
348
365
|
width,
|
|
349
366
|
height,
|
|
350
367
|
1,
|
|
351
|
-
self.datatype,
|
|
368
|
+
self.datatype.to_gdal(),
|
|
352
369
|
[]
|
|
353
370
|
)
|
|
354
371
|
if not dataset:
|
yirgacheffe/operators.py
CHANGED
|
@@ -17,6 +17,7 @@ from .rounding import are_pixel_scales_equal_enough, round_up_pixels, round_down
|
|
|
17
17
|
from .window import Area, PixelScale, Window
|
|
18
18
|
from .backends import backend
|
|
19
19
|
from .backends.enumeration import operators as op
|
|
20
|
+
from .backends.enumeration import dtype as DataType
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger(__name__)
|
|
22
23
|
logger.setLevel(logging.WARNING)
|
|
@@ -208,6 +209,14 @@ class LayerMathMixin:
|
|
|
208
209
|
def max(self):
|
|
209
210
|
return LayerOperation(self).max()
|
|
210
211
|
|
|
212
|
+
def astype(self, datatype):
|
|
213
|
+
return LayerOperation(
|
|
214
|
+
self,
|
|
215
|
+
op.ASTYPE,
|
|
216
|
+
window_op=WindowOperation.NONE,
|
|
217
|
+
datatype=datatype
|
|
218
|
+
)
|
|
219
|
+
|
|
211
220
|
|
|
212
221
|
class LayerOperation(LayerMathMixin):
|
|
213
222
|
|
|
@@ -392,7 +401,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
392
401
|
)
|
|
393
402
|
|
|
394
403
|
@property
|
|
395
|
-
def datatype(self):
|
|
404
|
+
def datatype(self) -> DataType:
|
|
396
405
|
# TODO: Work out how to indicate type promotion via numpy
|
|
397
406
|
return self.lhs.datatype
|
|
398
407
|
|
|
@@ -520,7 +529,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
520
529
|
|
|
521
530
|
return total if and_sum else None
|
|
522
531
|
|
|
523
|
-
def _parallel_worker(self, index, shared_mem, sem, np_dtype, width, input_queue, output_queue):
|
|
532
|
+
def _parallel_worker(self, index, shared_mem, sem, np_dtype, width, input_queue, output_queue, computation_window):
|
|
524
533
|
arr = np.ndarray((self.ystep, width), dtype=np_dtype, buffer=shared_mem.buf)
|
|
525
534
|
|
|
526
535
|
try:
|
|
@@ -540,7 +549,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
540
549
|
break
|
|
541
550
|
yoffset, step = task
|
|
542
551
|
|
|
543
|
-
result = self._eval(self.area, yoffset, step)
|
|
552
|
+
result = self._eval(self.area, yoffset, step, computation_window)
|
|
544
553
|
backend.eval_op(result)
|
|
545
554
|
|
|
546
555
|
arr[:step] = backend.demote_array(result)
|
|
@@ -641,7 +650,8 @@ class LayerOperation(LayerMathMixin):
|
|
|
641
650
|
np_dtype,
|
|
642
651
|
computation_window.xsize,
|
|
643
652
|
source_queue,
|
|
644
|
-
result_queue
|
|
653
|
+
result_queue,
|
|
654
|
+
computation_window
|
|
645
655
|
)) for i in range(worker_count)]
|
|
646
656
|
for worker in workers:
|
|
647
657
|
worker.start()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yirgacheffe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -35,6 +35,14 @@ Example common use-cases:
|
|
|
35
35
|
* Do the raster layers get big and take up large amounts of memory? Yirgacheffe will let you do simple numerical operations with layers directly and then worry about the memory management behind the scenes for you.
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
Yirgacheffe is available via pypi, so can be installed with pip for example:
|
|
41
|
+
|
|
42
|
+
```SystemShell
|
|
43
|
+
$ pip install yirgacheffe
|
|
44
|
+
```
|
|
45
|
+
|
|
38
46
|
## Basic usage
|
|
39
47
|
|
|
40
48
|
They main unit of data in Yirgacheffe is a "layer", which wraps either a raster dataset or polygon data, and then you can do work on layers without having to worry (unless you choose to) about how they align - Yirgacheffe will work out all the details around overlapping
|
|
@@ -339,6 +347,18 @@ with RasterLayer.layer_from_file('original.tif') as layer1:
|
|
|
339
347
|
calc.save(result)
|
|
340
348
|
```
|
|
341
349
|
|
|
350
|
+
### Type conversion
|
|
351
|
+
|
|
352
|
+
Similar to numpy and other Python numerical libraries, Yirgacheffe will automatically deal with simple type conversion where possible, however sometimes explicit conversion is either necessary or desired. Similar to numpy, there is an `astype` operator that lets you set the conversion:
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
from yirgacheffe.operations import DataType
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
with RasterLayer.layer_from_file('float_data.tif') as float_layer:
|
|
359
|
+
int_layer = float_layer.astype(DataType.Int32)
|
|
360
|
+
```
|
|
361
|
+
|
|
342
362
|
### Apply
|
|
343
363
|
|
|
344
364
|
You can specify a function that takes either data from one layer or from two layers, and returns the processed data. There's two version of this: one that lets you specify a numpy function that'll be applied to the layer data as an array, or one that is more shader like that lets you do pixel wise processing.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
yirgacheffe/__init__.py,sha256=U5AoPk_iWreSCexG2ID-tmSXiJz4_9Lvzbf42DMvT7k,658
|
|
2
|
+
yirgacheffe/constants.py,sha256=9ZcFLcir4GhPBBDG2rzLhDtJ0pMzpZYuzE9f-CFeA44,12
|
|
3
|
+
yirgacheffe/h3layer.py,sha256=MT2hm6n64hzHSeRPvjn-CwErru937ntKXbEU7CIlPSU,91
|
|
4
|
+
yirgacheffe/operators.py,sha256=g_QdvaUs5ddaLg2rFIz8otGidTHGktZfBjBV6g7vyBo,27278
|
|
5
|
+
yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
|
|
6
|
+
yirgacheffe/window.py,sha256=0XZdwD4mz0bRU9eBhFY1Xk1hQt6FqCKp3BnUgxZup3c,5224
|
|
7
|
+
yirgacheffe/backends/__init__.py,sha256=149-fg1PVXC36cgyuSZsU8SYOm65fzUmYN_MHZtEyrY,313
|
|
8
|
+
yirgacheffe/backends/enumeration.py,sha256=v1CsWSq97LNS4QXgUc59OyaBQWF5dAG5cDrMY2NWx1o,960
|
|
9
|
+
yirgacheffe/backends/mlx.py,sha256=Bt0Jlt96ECHZmBwI7kqJ6kSVsLDU-6rq0E7oUt7EzOg,5969
|
|
10
|
+
yirgacheffe/backends/numpy.py,sha256=t8rPDqkghE5UfkJi8r6ZUg14f1nL2lsPp61FGqUJwCg,3887
|
|
11
|
+
yirgacheffe/layers/__init__.py,sha256=GR_TJlhPKDK1212CG2T99X2FdBlNo_G8q2zQ6nJbiO4,1534
|
|
12
|
+
yirgacheffe/layers/area.py,sha256=yIRXzeeLi3MMyuh4LG_VgZrKNWe5xwZgDGdgaoYRpP0,3805
|
|
13
|
+
yirgacheffe/layers/base.py,sha256=vVxumZgFLTYXFtVxJEiBVV1QqtQWa5kwL10ckUF-ykE,11617
|
|
14
|
+
yirgacheffe/layers/constant.py,sha256=5YWSdr48Cw3DhryLBx45PNnPi4NzcVuQVin_YmOSWTg,1426
|
|
15
|
+
yirgacheffe/layers/group.py,sha256=2hRta24Mn5JwfDOB4-gJfroa_lVJSUFgSZ8FMeWy_FM,15127
|
|
16
|
+
yirgacheffe/layers/h3layer.py,sha256=Cyrw_6nXc1a_Twsb0FfexKhHAbegKXStL3J5LLk2AX8,9687
|
|
17
|
+
yirgacheffe/layers/rasters.py,sha256=8mAbH49RtKIoA3h9mxWNbPzo8NJWDSfoRPT7fpkTJ4I,12328
|
|
18
|
+
yirgacheffe/layers/rescaled.py,sha256=kWJlu7DuUB3nRDt3VtbJKiqBDQb2Ba8xzIIXTvOGdK8,2945
|
|
19
|
+
yirgacheffe/layers/vectors.py,sha256=JOqM7Ym53ZdxWKpBJac-opPp2N_ynMfet1Xtsi85dpM,15087
|
|
20
|
+
yirgacheffe-1.3.1.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
|
|
21
|
+
yirgacheffe-1.3.1.dist-info/METADATA,sha256=Z6-RV1V3MjUKE_pKLJlP4H14WAZIDqpB17uV94THEAc,20473
|
|
22
|
+
yirgacheffe-1.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
yirgacheffe-1.3.1.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
|
|
24
|
+
yirgacheffe-1.3.1.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
|
|
25
|
+
yirgacheffe-1.3.1.dist-info/RECORD,,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
yirgacheffe/__init__.py,sha256=U5AoPk_iWreSCexG2ID-tmSXiJz4_9Lvzbf42DMvT7k,658
|
|
2
|
-
yirgacheffe/constants.py,sha256=9ZcFLcir4GhPBBDG2rzLhDtJ0pMzpZYuzE9f-CFeA44,12
|
|
3
|
-
yirgacheffe/h3layer.py,sha256=MT2hm6n64hzHSeRPvjn-CwErru937ntKXbEU7CIlPSU,91
|
|
4
|
-
yirgacheffe/operators.py,sha256=eGa_y5fXXaEb4DkQ7b899bbhzl639yyIVLfVRbkD7vE,26945
|
|
5
|
-
yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
|
|
6
|
-
yirgacheffe/window.py,sha256=0XZdwD4mz0bRU9eBhFY1Xk1hQt6FqCKp3BnUgxZup3c,5224
|
|
7
|
-
yirgacheffe/backends/__init__.py,sha256=149-fg1PVXC36cgyuSZsU8SYOm65fzUmYN_MHZtEyrY,313
|
|
8
|
-
yirgacheffe/backends/enumeration.py,sha256=lddqmD7Z2z2g2SIPkmgNOiNSSZer3rIuBG3qHwy7t_g,474
|
|
9
|
-
yirgacheffe/backends/mlx.py,sha256=wJ5kUNWdhpE-DLrgsvxpLeiXm7fUlKvrqik976jM9kc,4558
|
|
10
|
-
yirgacheffe/backends/numpy.py,sha256=-y3oLi3BOUuS5l9IJJ3orl08YrPbo9mideW9M1Re6lA,2745
|
|
11
|
-
yirgacheffe/layers/__init__.py,sha256=TrKSHpd-TF7wgC371hka6paFXBnqvDtjJYblproNKZs,1535
|
|
12
|
-
yirgacheffe/layers/area.py,sha256=yIRXzeeLi3MMyuh4LG_VgZrKNWe5xwZgDGdgaoYRpP0,3805
|
|
13
|
-
yirgacheffe/layers/base.py,sha256=pWnmmohGqI4rtH_CruDWfEfOiNcyns-sU2FcNw55ng4,11602
|
|
14
|
-
yirgacheffe/layers/constant.py,sha256=Fm76YLZobSlNJjbpJOX8VDDkifYPVtg55zdUc8kt7xc,1412
|
|
15
|
-
yirgacheffe/layers/group.py,sha256=RXl6sGa4OagudIb8seveLfnvCMC9_wm-5hrGq6LYgnw,15054
|
|
16
|
-
yirgacheffe/layers/h3layer.py,sha256=O4u-tGO32SQaEsgNLlgGCOFd4bjm1mt2coZDL23F_HI,9662
|
|
17
|
-
yirgacheffe/layers/rasters.py,sha256=8kT2ETplWTJNb7F9HsmqRMz7APolByvIkZuBB0mRduk,11907
|
|
18
|
-
yirgacheffe/layers/rescaled.py,sha256=hEj6BnrJm8o7dMVND5KMpVfg-HVVExovcKRnUl64dRI,2897
|
|
19
|
-
yirgacheffe/layers/vectors.py,sha256=OxXxnV5pss9vSmeiqvmx68ZGmC7iX6Iet0y4b4ZEMcc,14436
|
|
20
|
-
yirgacheffe-1.2.1.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
|
|
21
|
-
yirgacheffe-1.2.1.dist-info/METADATA,sha256=bmztQnEJWScy1ig9svcz_vyy6-I8XIvRESPuf5WgEHc,19844
|
|
22
|
-
yirgacheffe-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
-
yirgacheffe-1.2.1.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
|
|
24
|
-
yirgacheffe-1.2.1.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
|
|
25
|
-
yirgacheffe-1.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|