rio-tiler 7.9.2__py3-none-any.whl → 8.0.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.
- rio_tiler/__init__.py +1 -1
- rio_tiler/colormap.py +7 -4
- rio_tiler/errors.py +8 -0
- rio_tiler/experimental/zarr.py +366 -0
- rio_tiler/expression.py +6 -6
- rio_tiler/io/base.py +20 -0
- rio_tiler/io/rasterio.py +1 -8
- rio_tiler/io/xarray.py +70 -58
- rio_tiler/models.py +223 -66
- rio_tiler/mosaic/backend.py +242 -0
- rio_tiler/mosaic/reader.py +6 -0
- rio_tiler/reader.py +31 -32
- rio_tiler/tasks.py +16 -0
- rio_tiler/utils.py +29 -1
- {rio_tiler-7.9.2.dist-info → rio_tiler-8.0.0.dist-info}/METADATA +12 -36
- {rio_tiler-7.9.2.dist-info → rio_tiler-8.0.0.dist-info}/RECORD +19 -17
- {rio_tiler-7.9.2.dist-info → rio_tiler-8.0.0.dist-info}/WHEEL +0 -0
- {rio_tiler-7.9.2.dist-info → rio_tiler-8.0.0.dist-info}/licenses/AUTHORS.txt +0 -0
- {rio_tiler-7.9.2.dist-info → rio_tiler-8.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""rio_tiler.mosaic.backend: base Backend class."""
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Any, Type
|
|
6
|
+
|
|
7
|
+
import attr
|
|
8
|
+
from morecantile import TileMatrixSet
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
+
from rasterio.crs import CRS
|
|
11
|
+
from rasterio.features import bounds as featureBounds
|
|
12
|
+
from rasterio.features import geometry_mask
|
|
13
|
+
|
|
14
|
+
from rio_tiler.constants import WEB_MERCATOR_TMS, WGS84_CRS
|
|
15
|
+
from rio_tiler.errors import NoAssetFoundError, PointOutsideBounds
|
|
16
|
+
from rio_tiler.io import BaseReader, MultiBandReader, MultiBaseReader, Reader
|
|
17
|
+
from rio_tiler.models import ImageData, PointData
|
|
18
|
+
from rio_tiler.mosaic import mosaic_reader
|
|
19
|
+
from rio_tiler.tasks import multi_values_list
|
|
20
|
+
from rio_tiler.types import BBox
|
|
21
|
+
from rio_tiler.utils import CRS_to_uri, Timer, _validate_shape_input
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MosaicInfo(BaseModel):
|
|
27
|
+
"""Mosaic info responses."""
|
|
28
|
+
|
|
29
|
+
bounds: BBox = Field(default=(-180, -90, 180, 90))
|
|
30
|
+
crs: str
|
|
31
|
+
|
|
32
|
+
model_config = ConfigDict(extra="allow")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@attr.s
|
|
36
|
+
class BaseBackend(BaseReader):
|
|
37
|
+
"""Base Class for mosaic backend.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
input (str): mosaic path.
|
|
41
|
+
tms (morecantile.TileMatrixSet, optional): TileMatrixSet grid definition. Defaults to `WebMercatorQuad`.
|
|
42
|
+
reader (rio_tiler.io.BaseReader): Dataset reader. Defaults to `rio_tiler.io.Reader`.
|
|
43
|
+
reader_options (dict): Options to forward to the reader config.
|
|
44
|
+
bounds (tuple): mosaic bounds (left, bottom, right, top). **READ ONLY attribute**.
|
|
45
|
+
crs (rasterio.crs.CRS): mosaic crs in which its bounds is defined. **READ ONLY attribute**.
|
|
46
|
+
minzoom (int): mosaic minimum zoom level. **READ ONLY attribute**.
|
|
47
|
+
maxzoom (int): mosaic maximum zoom level. **READ ONLY attribute**.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
input: str = attr.ib()
|
|
52
|
+
tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
|
|
53
|
+
|
|
54
|
+
reader: Type[BaseReader] | Type[MultiBaseReader] | Type[MultiBandReader] = attr.ib(
|
|
55
|
+
default=Reader
|
|
56
|
+
)
|
|
57
|
+
reader_options: dict = attr.ib(factory=dict)
|
|
58
|
+
|
|
59
|
+
bounds: BBox = attr.ib(init=False)
|
|
60
|
+
crs: CRS = attr.ib(init=False)
|
|
61
|
+
|
|
62
|
+
minzoom: int = attr.ib(init=False)
|
|
63
|
+
maxzoom: int = attr.ib(init=False)
|
|
64
|
+
|
|
65
|
+
@abc.abstractmethod
|
|
66
|
+
def assets_for_tile(self, x: int, y: int, z: int, **kwargs: Any) -> list[Any]:
|
|
67
|
+
"""Retrieve assets for tile."""
|
|
68
|
+
|
|
69
|
+
@abc.abstractmethod
|
|
70
|
+
def assets_for_point(
|
|
71
|
+
self,
|
|
72
|
+
lng: float,
|
|
73
|
+
lat: float,
|
|
74
|
+
coord_crs: CRS | None = None,
|
|
75
|
+
**kwargs: Any,
|
|
76
|
+
) -> list[Any]:
|
|
77
|
+
"""Retrieve assets for point."""
|
|
78
|
+
|
|
79
|
+
@abc.abstractmethod
|
|
80
|
+
def assets_for_bbox(
|
|
81
|
+
self,
|
|
82
|
+
xmin: float,
|
|
83
|
+
ymin: float,
|
|
84
|
+
xmax: float,
|
|
85
|
+
ymax: float,
|
|
86
|
+
coord_crs: CRS | None = None,
|
|
87
|
+
**kwargs,
|
|
88
|
+
) -> list[Any]:
|
|
89
|
+
"""Retrieve assets for bbox."""
|
|
90
|
+
|
|
91
|
+
def asset_name(self, asset: Any) -> str:
|
|
92
|
+
"""Get asset name."""
|
|
93
|
+
return str(asset)
|
|
94
|
+
|
|
95
|
+
def info(self) -> MosaicInfo: # type: ignore
|
|
96
|
+
"""Mosaic info."""
|
|
97
|
+
return MosaicInfo(
|
|
98
|
+
bounds=self.bounds,
|
|
99
|
+
crs=CRS_to_uri(self.crs) or self.crs.to_wkt(),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def point( # type: ignore
|
|
103
|
+
self,
|
|
104
|
+
lon: float,
|
|
105
|
+
lat: float,
|
|
106
|
+
coord_crs: CRS = WGS84_CRS,
|
|
107
|
+
search_options: dict | None = None,
|
|
108
|
+
**kwargs: Any,
|
|
109
|
+
) -> list[tuple[str, PointData]]:
|
|
110
|
+
"""Get Point value from multiple assets."""
|
|
111
|
+
search_options = search_options or {}
|
|
112
|
+
mosaic_assets = self.assets_for_point(
|
|
113
|
+
lon, lat, coord_crs=coord_crs, **search_options
|
|
114
|
+
)
|
|
115
|
+
if not mosaic_assets:
|
|
116
|
+
raise NoAssetFoundError(f"No assets found for point ({lon},{lat})")
|
|
117
|
+
|
|
118
|
+
def _reader(
|
|
119
|
+
asset: Any, lon: float, lat: float, coord_crs: CRS, **kwargs
|
|
120
|
+
) -> PointData:
|
|
121
|
+
with self.reader(asset, **self.reader_options) as src_dst:
|
|
122
|
+
return src_dst.point(lon, lat, coord_crs=coord_crs, **kwargs)
|
|
123
|
+
|
|
124
|
+
if "allowed_exceptions" not in kwargs:
|
|
125
|
+
kwargs.update({"allowed_exceptions": (PointOutsideBounds,)})
|
|
126
|
+
|
|
127
|
+
logger.info(
|
|
128
|
+
f"reading Point for {len(mosaic_assets)} assets with reader: {self.reader}"
|
|
129
|
+
)
|
|
130
|
+
return [
|
|
131
|
+
(self.asset_name(asset), pt)
|
|
132
|
+
for asset, pt in multi_values_list(
|
|
133
|
+
mosaic_assets, _reader, lon, lat, coord_crs, **kwargs
|
|
134
|
+
)
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
def tile( # type: ignore
|
|
138
|
+
self,
|
|
139
|
+
x: int,
|
|
140
|
+
y: int,
|
|
141
|
+
z: int,
|
|
142
|
+
search_options: dict | None = None,
|
|
143
|
+
**kwargs: Any,
|
|
144
|
+
) -> tuple[ImageData, list[str]]:
|
|
145
|
+
"""Get Tile from multiple assets."""
|
|
146
|
+
timings = []
|
|
147
|
+
with Timer() as t:
|
|
148
|
+
search_options = search_options or {}
|
|
149
|
+
mosaic_assets = self.assets_for_tile(x, y, z, **search_options)
|
|
150
|
+
timings.append(("search", round(t.elapsed * 1000, 2)))
|
|
151
|
+
|
|
152
|
+
if not mosaic_assets:
|
|
153
|
+
raise NoAssetFoundError(f"No assets found for tile {z}-{x}-{y}")
|
|
154
|
+
|
|
155
|
+
def _reader(asset: Any, x: int, y: int, z: int, **kwargs: Any) -> ImageData:
|
|
156
|
+
with self.reader(asset, tms=self.tms, **self.reader_options) as src_dst:
|
|
157
|
+
return src_dst.tile(x, y, z, **kwargs)
|
|
158
|
+
|
|
159
|
+
logger.info(
|
|
160
|
+
f"reading Tile for {len(mosaic_assets)} assets with reader: {self.reader}"
|
|
161
|
+
)
|
|
162
|
+
with Timer() as t:
|
|
163
|
+
img, asset_used = mosaic_reader(mosaic_assets, _reader, x, y, z, **kwargs)
|
|
164
|
+
timings.append(("mosaicking", round(t.elapsed * 1000, 2)))
|
|
165
|
+
img.metadata = {**img.metadata, "timings": timings}
|
|
166
|
+
|
|
167
|
+
asset_used = [self.asset_name(asset) for asset in asset_used]
|
|
168
|
+
return img, asset_used
|
|
169
|
+
|
|
170
|
+
def part( # type: ignore
|
|
171
|
+
self,
|
|
172
|
+
bbox: BBox,
|
|
173
|
+
bounds_crs: CRS = WGS84_CRS,
|
|
174
|
+
search_options: dict | None = None,
|
|
175
|
+
**kwargs: Any,
|
|
176
|
+
) -> tuple[ImageData, list[str]]:
|
|
177
|
+
"""Create an Image from multiple assets for a bbox."""
|
|
178
|
+
xmin, ymin, xmax, ymax = bbox
|
|
179
|
+
timings = []
|
|
180
|
+
|
|
181
|
+
with Timer() as t:
|
|
182
|
+
search_options = search_options or {}
|
|
183
|
+
mosaic_assets = self.assets_for_bbox(
|
|
184
|
+
xmin,
|
|
185
|
+
ymin,
|
|
186
|
+
xmax,
|
|
187
|
+
ymax,
|
|
188
|
+
coord_crs=bounds_crs,
|
|
189
|
+
**search_options,
|
|
190
|
+
)
|
|
191
|
+
timings.append(("search", round(t.elapsed * 1000, 2)))
|
|
192
|
+
|
|
193
|
+
if not mosaic_assets:
|
|
194
|
+
raise NoAssetFoundError("No assets found for bbox input")
|
|
195
|
+
|
|
196
|
+
def _reader(asset: Any, bbox: BBox, bounds_crs: CRS, **kwargs: Any) -> ImageData:
|
|
197
|
+
with self.reader(asset, **self.reader_options) as src_dst:
|
|
198
|
+
return src_dst.part(bbox, bounds_crs=bounds_crs, **kwargs)
|
|
199
|
+
|
|
200
|
+
logger.info(
|
|
201
|
+
f"reading Part for {len(mosaic_assets)} assets with reader: {self.reader}"
|
|
202
|
+
)
|
|
203
|
+
with Timer() as t:
|
|
204
|
+
img, asset_used = mosaic_reader(
|
|
205
|
+
mosaic_assets, _reader, bbox, bounds_crs, **kwargs
|
|
206
|
+
)
|
|
207
|
+
timings.append(("mosaicking", round(t.elapsed * 1000, 2)))
|
|
208
|
+
img.metadata = {**img.metadata, "timings": timings}
|
|
209
|
+
|
|
210
|
+
asset_used = [self.asset_name(asset) for asset in asset_used]
|
|
211
|
+
return img, asset_used
|
|
212
|
+
|
|
213
|
+
def feature( # type: ignore
|
|
214
|
+
self,
|
|
215
|
+
shape: dict,
|
|
216
|
+
shape_crs: CRS = WGS84_CRS,
|
|
217
|
+
search_options: dict | None = None,
|
|
218
|
+
**kwargs: Any,
|
|
219
|
+
) -> tuple[ImageData, list[str]]:
|
|
220
|
+
"""Create an Image from multiple assets for a GeoJSON feature."""
|
|
221
|
+
shape = _validate_shape_input(shape)
|
|
222
|
+
bbox = featureBounds(shape)
|
|
223
|
+
|
|
224
|
+
img, asset_used = self.part(
|
|
225
|
+
bbox,
|
|
226
|
+
bounds_crs=shape_crs,
|
|
227
|
+
search_options=search_options,
|
|
228
|
+
**kwargs,
|
|
229
|
+
)
|
|
230
|
+
img.array.mask = geometry_mask([shape], (img.height, img.width), img.transform)
|
|
231
|
+
return img, asset_used
|
|
232
|
+
|
|
233
|
+
############################################################################
|
|
234
|
+
# Not Implemented methods
|
|
235
|
+
# BaseReader required those method to be implemented
|
|
236
|
+
def statistics(self):
|
|
237
|
+
"""PlaceHolder for statistics."""
|
|
238
|
+
raise NotImplementedError
|
|
239
|
+
|
|
240
|
+
def preview(self):
|
|
241
|
+
"""PlaceHolder for preview."""
|
|
242
|
+
raise NotImplementedError
|
rio_tiler/mosaic/reader.py
CHANGED
|
@@ -95,6 +95,7 @@ def mosaic_reader( # noqa: C901
|
|
|
95
95
|
crs = img.crs
|
|
96
96
|
bounds = img.bounds
|
|
97
97
|
band_names = img.band_names
|
|
98
|
+
band_descriptions = img.band_descriptions
|
|
98
99
|
pixel_selection.cutline_mask = img.cutline_mask
|
|
99
100
|
pixel_selection.width = img.width
|
|
100
101
|
pixel_selection.height = img.height
|
|
@@ -135,6 +136,7 @@ def mosaic_reader( # noqa: C901
|
|
|
135
136
|
crs=crs,
|
|
136
137
|
bounds=bounds,
|
|
137
138
|
band_names=band_names,
|
|
139
|
+
band_descriptions=band_descriptions,
|
|
138
140
|
metadata={
|
|
139
141
|
"mosaic_method": pixel_selection.__class__.__name__,
|
|
140
142
|
"mosaic_assets_count": len(mosaic_assets),
|
|
@@ -154,6 +156,7 @@ def mosaic_reader( # noqa: C901
|
|
|
154
156
|
crs=crs,
|
|
155
157
|
bounds=bounds,
|
|
156
158
|
band_names=band_names,
|
|
159
|
+
band_descriptions=band_descriptions,
|
|
157
160
|
metadata={
|
|
158
161
|
"mosaic_method": pixel_selection.__class__.__name__,
|
|
159
162
|
"mosaic_assets_count": len(mosaic_assets),
|
|
@@ -229,6 +232,7 @@ def mosaic_point_reader(
|
|
|
229
232
|
crs = pt.crs
|
|
230
233
|
coordinates = pt.coordinates
|
|
231
234
|
band_names = pt.band_names
|
|
235
|
+
band_descriptions = pt.band_descriptions
|
|
232
236
|
pixel_selection.width = 1
|
|
233
237
|
pixel_selection.height = 1
|
|
234
238
|
pixel_selection.count = pt.count
|
|
@@ -248,6 +252,7 @@ def mosaic_point_reader(
|
|
|
248
252
|
crs=crs,
|
|
249
253
|
coordinates=coordinates,
|
|
250
254
|
band_names=band_names,
|
|
255
|
+
band_descriptions=band_descriptions,
|
|
251
256
|
metadata={
|
|
252
257
|
"mosaic_method": pixel_selection.__class__.__name__,
|
|
253
258
|
"mosaic_assets_count": len(mosaic_assets),
|
|
@@ -267,6 +272,7 @@ def mosaic_point_reader(
|
|
|
267
272
|
crs=crs,
|
|
268
273
|
coordinates=coordinates,
|
|
269
274
|
band_names=band_names,
|
|
275
|
+
band_descriptions=band_descriptions,
|
|
270
276
|
metadata={
|
|
271
277
|
"mosaic_method": pixel_selection.__class__.__name__,
|
|
272
278
|
"mosaic_assets_count": len(mosaic_assets),
|
rio_tiler/reader.py
CHANGED
|
@@ -34,7 +34,6 @@ from rio_tiler.utils import (
|
|
|
34
34
|
class Options(TypedDict, total=False):
|
|
35
35
|
"""Reader Options."""
|
|
36
36
|
|
|
37
|
-
force_binary_mask: Optional[bool]
|
|
38
37
|
nodata: Optional[NoData]
|
|
39
38
|
vrt_options: Optional[Dict]
|
|
40
39
|
resampling_method: Optional[RIOResampling]
|
|
@@ -76,7 +75,6 @@ def read(
|
|
|
76
75
|
max_size: Optional[int] = None,
|
|
77
76
|
indexes: Optional[Indexes] = None,
|
|
78
77
|
window: Optional[windows.Window] = None,
|
|
79
|
-
force_binary_mask: bool = True,
|
|
80
78
|
nodata: Optional[NoData] = None,
|
|
81
79
|
vrt_options: Optional[Dict] = None,
|
|
82
80
|
out_dtype: Optional[Union[str, numpy.dtype]] = None,
|
|
@@ -99,7 +97,6 @@ def read(
|
|
|
99
97
|
vrt_options (dict, optional): Options to be passed to the rasterio.warp.WarpedVRT class.
|
|
100
98
|
resampling_method (RIOResampling, optional): RasterIO resampling algorithm. Defaults to `nearest`.
|
|
101
99
|
reproject_method (WarpResampling, optional): WarpKernel resampling algorithm. Defaults to `nearest`.
|
|
102
|
-
force_binary_mask (bool, optional): Cast returned mask to binary values (0 or 255). Defaults to `True`.
|
|
103
100
|
unscale (bool, optional): Apply 'scales' and 'offsets' on output data value. Defaults to `False`.
|
|
104
101
|
post_process (callable, optional): Function to apply on output data and mask values.
|
|
105
102
|
|
|
@@ -258,37 +255,33 @@ def read(
|
|
|
258
255
|
# We only add dataset statistics if we have them for all the indexes
|
|
259
256
|
dataset_statistics = stats if len(stats) == len(indexes) else None
|
|
260
257
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
pass
|
|
264
|
-
|
|
258
|
+
scales = numpy.array(dataset.scales)[numpy.array(indexes) - 1]
|
|
259
|
+
offsets = numpy.array(dataset.offsets)[numpy.array(indexes) - 1]
|
|
265
260
|
if unscale:
|
|
266
261
|
data = data.astype("float32", casting="unsafe")
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
scales = numpy.array(dataset.scales)[numpy.array(indexes) - 1].reshape(
|
|
270
|
-
(-1, 1, 1)
|
|
271
|
-
)
|
|
272
|
-
offsets = numpy.array(dataset.offsets)[numpy.array(indexes) - 1].reshape(
|
|
273
|
-
(-1, 1, 1)
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
numpy.multiply(data, scales, out=data, casting="unsafe")
|
|
277
|
-
numpy.add(data, offsets, out=data, casting="unsafe")
|
|
262
|
+
numpy.multiply(data, scales.reshape((-1, 1, 1)), out=data, casting="unsafe")
|
|
263
|
+
numpy.add(data, offsets.reshape((-1, 1, 1)), out=data, casting="unsafe")
|
|
278
264
|
|
|
279
265
|
# apply scale/offsets to stats
|
|
280
266
|
if dataset_statistics:
|
|
281
|
-
|
|
282
|
-
|
|
267
|
+
stats_array = numpy.array(dataset_statistics)
|
|
268
|
+
numpy.multiply(
|
|
269
|
+
stats_array,
|
|
270
|
+
scales.reshape((-1, 1)),
|
|
271
|
+
out=stats_array,
|
|
272
|
+
casting="unsafe",
|
|
283
273
|
)
|
|
284
|
-
|
|
285
|
-
|
|
274
|
+
numpy.add(
|
|
275
|
+
stats_array,
|
|
276
|
+
offsets.reshape((-1, 1)),
|
|
277
|
+
out=stats_array,
|
|
278
|
+
casting="unsafe",
|
|
286
279
|
)
|
|
287
|
-
stats_array = numpy.array(dataset_statistics)
|
|
288
|
-
numpy.multiply(stats_array, scales, out=stats_array, casting="unsafe")
|
|
289
|
-
numpy.add(stats_array, offsets, out=stats_array, casting="unsafe")
|
|
290
280
|
dataset_statistics = [tuple(s) for s in stats_array.tolist()]
|
|
291
281
|
|
|
282
|
+
scales = numpy.zeros(len(indexes)) + 1.0
|
|
283
|
+
offsets = numpy.zeros(len(indexes))
|
|
284
|
+
|
|
292
285
|
if post_process:
|
|
293
286
|
data = post_process(data)
|
|
294
287
|
|
|
@@ -301,8 +294,12 @@ def read(
|
|
|
301
294
|
bounds=out_bounds,
|
|
302
295
|
crs=dataset.crs,
|
|
303
296
|
band_names=[f"b{idx}" for idx in indexes],
|
|
297
|
+
band_descriptions=[dataset.descriptions[ix - 1] or "" for idx in indexes],
|
|
304
298
|
dataset_statistics=dataset_statistics,
|
|
305
299
|
metadata=dataset.tags(),
|
|
300
|
+
nodata=nodata,
|
|
301
|
+
scales=scales.tolist(),
|
|
302
|
+
offsets=offsets.tolist(),
|
|
306
303
|
)
|
|
307
304
|
|
|
308
305
|
|
|
@@ -319,7 +316,6 @@ def part(
|
|
|
319
316
|
minimum_overlap: Optional[float] = None,
|
|
320
317
|
padding: Optional[int] = None,
|
|
321
318
|
buffer: Optional[float] = None,
|
|
322
|
-
force_binary_mask: bool = True,
|
|
323
319
|
nodata: Optional[NoData] = None,
|
|
324
320
|
vrt_options: Optional[Dict] = None,
|
|
325
321
|
out_dtype: Optional[Union[str, numpy.dtype]] = None,
|
|
@@ -456,7 +452,6 @@ def part(
|
|
|
456
452
|
out_dtype=out_dtype,
|
|
457
453
|
resampling_method=resampling_method,
|
|
458
454
|
reproject_method=reproject_method,
|
|
459
|
-
force_binary_mask=force_binary_mask,
|
|
460
455
|
unscale=unscale,
|
|
461
456
|
post_process=post_process,
|
|
462
457
|
)
|
|
@@ -501,7 +496,6 @@ def part(
|
|
|
501
496
|
out_dtype=out_dtype,
|
|
502
497
|
resampling_method=resampling_method,
|
|
503
498
|
reproject_method=reproject_method,
|
|
504
|
-
force_binary_mask=force_binary_mask,
|
|
505
499
|
unscale=unscale,
|
|
506
500
|
post_process=post_process,
|
|
507
501
|
)
|
|
@@ -511,6 +505,10 @@ def part(
|
|
|
511
505
|
bounds=bounds,
|
|
512
506
|
crs=img.crs,
|
|
513
507
|
band_names=img.band_names,
|
|
508
|
+
band_descriptions=img.band_descriptions,
|
|
509
|
+
nodata=img.nodata,
|
|
510
|
+
scales=img.scales,
|
|
511
|
+
offsets=img.offsets,
|
|
514
512
|
dataset_statistics=img.dataset_statistics,
|
|
515
513
|
metadata=img.metadata,
|
|
516
514
|
)
|
|
@@ -525,7 +523,6 @@ def part(
|
|
|
525
523
|
out_dtype=out_dtype,
|
|
526
524
|
resampling_method=resampling_method,
|
|
527
525
|
reproject_method=reproject_method,
|
|
528
|
-
force_binary_mask=force_binary_mask,
|
|
529
526
|
unscale=unscale,
|
|
530
527
|
post_process=post_process,
|
|
531
528
|
)
|
|
@@ -536,7 +533,6 @@ def point(
|
|
|
536
533
|
coordinates: Tuple[float, float],
|
|
537
534
|
indexes: Optional[Indexes] = None,
|
|
538
535
|
coord_crs: CRS = WGS84_CRS,
|
|
539
|
-
force_binary_mask: bool = True,
|
|
540
536
|
nodata: Optional[NoData] = None,
|
|
541
537
|
vrt_options: Optional[Dict] = None,
|
|
542
538
|
out_dtype: Optional[Union[str, numpy.dtype]] = None,
|
|
@@ -642,7 +638,6 @@ def point(
|
|
|
642
638
|
window=window,
|
|
643
639
|
out_dtype=out_dtype,
|
|
644
640
|
resampling_method=resampling_method,
|
|
645
|
-
force_binary_mask=force_binary_mask,
|
|
646
641
|
unscale=unscale,
|
|
647
642
|
post_process=post_process,
|
|
648
643
|
)
|
|
@@ -650,8 +645,12 @@ def point(
|
|
|
650
645
|
return PointData(
|
|
651
646
|
img.array[:, 0, 0],
|
|
652
647
|
band_names=img.band_names,
|
|
648
|
+
band_descriptions=img.band_descriptions,
|
|
653
649
|
coordinates=coordinates,
|
|
654
650
|
crs=coord_crs,
|
|
655
|
-
metadata=dataset.tags(),
|
|
656
651
|
pixel_location=(col, row),
|
|
652
|
+
nodata=img.nodata,
|
|
653
|
+
scales=img.scales,
|
|
654
|
+
offsets=img.offsets,
|
|
655
|
+
metadata=img.metadata,
|
|
657
656
|
)
|
rio_tiler/tasks.py
CHANGED
|
@@ -99,3 +99,19 @@ def multi_values(
|
|
|
99
99
|
asset: val
|
|
100
100
|
for val, asset in filter_tasks(tasks, allowed_exceptions=allowed_exceptions)
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def multi_values_list(
|
|
105
|
+
asset_list: Sequence,
|
|
106
|
+
reader: Callable,
|
|
107
|
+
*args: Any,
|
|
108
|
+
threads: int = MAX_THREADS,
|
|
109
|
+
allowed_exceptions: Optional[Tuple] = None,
|
|
110
|
+
**kwargs: Any,
|
|
111
|
+
) -> list[tuple[Any, Any]]:
|
|
112
|
+
"""Merge values returned from tasks."""
|
|
113
|
+
tasks = create_tasks(reader, asset_list, threads, *args, **kwargs)
|
|
114
|
+
return [
|
|
115
|
+
(asset, val)
|
|
116
|
+
for val, asset in filter_tasks(tasks, allowed_exceptions=allowed_exceptions)
|
|
117
|
+
]
|
rio_tiler/utils.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""rio_tiler.utils: utility functions."""
|
|
2
2
|
|
|
3
3
|
import math
|
|
4
|
+
import time
|
|
4
5
|
import warnings
|
|
5
6
|
from io import BytesIO
|
|
6
7
|
from typing import (
|
|
@@ -517,7 +518,7 @@ def linear_rescale(
|
|
|
517
518
|
"""
|
|
518
519
|
imin, imax = in_range
|
|
519
520
|
omin, omax = out_range
|
|
520
|
-
im = numpy.clip(image, imin, imax) - imin
|
|
521
|
+
im = numpy.clip(image, imin, imax, dtype=numpy.float64) - imin
|
|
521
522
|
im = im / numpy.float64(imax - imin)
|
|
522
523
|
return im * (omax - omin) + omin
|
|
523
524
|
|
|
@@ -893,3 +894,30 @@ def CRS_to_urn(crs: CRS) -> Optional[str]:
|
|
|
893
894
|
return f"urn:ogc:def:crs:{authority}:{version}:{code}"
|
|
894
895
|
|
|
895
896
|
return None
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
# This code is copied from marblecutter
|
|
900
|
+
# https://github.com/mojodna/marblecutter/blob/master/marblecutter/stats.py
|
|
901
|
+
# License:
|
|
902
|
+
# Original work Copyright 2016 Stamen Design
|
|
903
|
+
# Modified work Copyright 2016-2017 Seth Fitzsimmons
|
|
904
|
+
# Modified work Copyright 2016 American Red Cross
|
|
905
|
+
# Modified work Copyright 2016-2017 Humanitarian OpenStreetMap Team
|
|
906
|
+
# Modified work Copyright 2017 Mapzen
|
|
907
|
+
class Timer(object):
|
|
908
|
+
"""Time a code block."""
|
|
909
|
+
|
|
910
|
+
def __enter__(self):
|
|
911
|
+
"""Starts timer."""
|
|
912
|
+
self.start = time.time()
|
|
913
|
+
return self
|
|
914
|
+
|
|
915
|
+
def __exit__(self, ty, val, tb):
|
|
916
|
+
"""Stops timer."""
|
|
917
|
+
self.end = time.time()
|
|
918
|
+
self.elapsed = self.end - self.start
|
|
919
|
+
|
|
920
|
+
@property
|
|
921
|
+
def from_start(self):
|
|
922
|
+
"""Return time elapsed from start."""
|
|
923
|
+
return time.time() - self.start
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rio-tiler
|
|
3
|
-
Version:
|
|
3
|
+
Version: 8.0.0
|
|
4
4
|
Summary: User friendly Rasterio plugin to read raster datasets.
|
|
5
5
|
Project-URL: Homepage, https://cogeotiff.github.io/rio-tiler/
|
|
6
6
|
Project-URL: Documentation, https://cogeotiff.github.io/rio-tiler/
|
|
@@ -43,54 +43,30 @@ Keywords: COGEO,Cloud Optimized Geotiff,STAC,rasterio,slippy-map
|
|
|
43
43
|
Classifier: Intended Audience :: Information Technology
|
|
44
44
|
Classifier: Intended Audience :: Science/Research
|
|
45
45
|
Classifier: License :: OSI Approved :: BSD License
|
|
46
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
47
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
48
46
|
Classifier: Programming Language :: Python :: 3.11
|
|
49
47
|
Classifier: Programming Language :: Python :: 3.12
|
|
50
48
|
Classifier: Programming Language :: Python :: 3.13
|
|
51
49
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
52
|
-
Requires-Python: >=3.
|
|
50
|
+
Requires-Python: >=3.11
|
|
53
51
|
Requires-Dist: attrs
|
|
54
52
|
Requires-Dist: cachetools
|
|
55
53
|
Requires-Dist: color-operations
|
|
56
54
|
Requires-Dist: httpx
|
|
57
|
-
Requires-Dist: morecantile<
|
|
55
|
+
Requires-Dist: morecantile<8.0,>=5.0
|
|
58
56
|
Requires-Dist: numexpr
|
|
59
57
|
Requires-Dist: numpy
|
|
60
58
|
Requires-Dist: pydantic~=2.0
|
|
61
59
|
Requires-Dist: pystac<2.0,>=1.9
|
|
62
60
|
Requires-Dist: rasterio>=1.4.0
|
|
63
61
|
Requires-Dist: typing-extensions
|
|
64
|
-
Provides-Extra: benchmark
|
|
65
|
-
Requires-Dist: pytest; extra == 'benchmark'
|
|
66
|
-
Requires-Dist: pytest-benchmark; extra == 'benchmark'
|
|
67
|
-
Provides-Extra: dev
|
|
68
|
-
Requires-Dist: bump-my-version; extra == 'dev'
|
|
69
|
-
Requires-Dist: pre-commit; extra == 'dev'
|
|
70
|
-
Provides-Extra: docs
|
|
71
|
-
Requires-Dist: griffe-inherited-docstrings>=1.0.0; extra == 'docs'
|
|
72
|
-
Requires-Dist: mkdocs-jupyter>=0.24.5; extra == 'docs'
|
|
73
|
-
Requires-Dist: mkdocs-material[imaging]>=9.5; extra == 'docs'
|
|
74
|
-
Requires-Dist: mkdocs>=1.4.3; extra == 'docs'
|
|
75
|
-
Requires-Dist: mkdocstrings[python]>=0.25.1; extra == 'docs'
|
|
76
|
-
Requires-Dist: pygments; extra == 'docs'
|
|
77
62
|
Provides-Extra: s3
|
|
78
63
|
Requires-Dist: boto3; extra == 's3'
|
|
79
|
-
Provides-Extra: test
|
|
80
|
-
Requires-Dist: boto3; extra == 'test'
|
|
81
|
-
Requires-Dist: h5netcdf; extra == 'test'
|
|
82
|
-
Requires-Dist: morecantile<7.0,>=6.0; extra == 'test'
|
|
83
|
-
Requires-Dist: pytest; extra == 'test'
|
|
84
|
-
Requires-Dist: pytest-cov; extra == 'test'
|
|
85
|
-
Requires-Dist: rioxarray; extra == 'test'
|
|
86
|
-
Requires-Dist: vsifile>=0.2; extra == 'test'
|
|
87
|
-
Requires-Dist: xarray; extra == 'test'
|
|
88
|
-
Provides-Extra: tilebench
|
|
89
|
-
Requires-Dist: pytest; extra == 'tilebench'
|
|
90
|
-
Requires-Dist: tilebench; extra == 'tilebench'
|
|
91
64
|
Provides-Extra: xarray
|
|
92
65
|
Requires-Dist: rioxarray; extra == 'xarray'
|
|
93
66
|
Requires-Dist: xarray; extra == 'xarray'
|
|
67
|
+
Provides-Extra: zarr
|
|
68
|
+
Requires-Dist: obstore; extra == 'zarr'
|
|
69
|
+
Requires-Dist: zarr~=3.0; extra == 'zarr'
|
|
94
70
|
Description-Content-Type: text/markdown
|
|
95
71
|
|
|
96
72
|
# rio-tiler
|
|
@@ -264,17 +240,17 @@ At the low level, `rio-tiler` is *just* a wrapper around the [rasterio](https://
|
|
|
264
240
|
You can install `rio-tiler` using pip
|
|
265
241
|
|
|
266
242
|
```bash
|
|
267
|
-
|
|
268
|
-
|
|
243
|
+
python -m pip install -U pip
|
|
244
|
+
python -m pip install -U rio-tiler
|
|
269
245
|
```
|
|
270
246
|
|
|
271
247
|
or install from source:
|
|
272
248
|
|
|
273
249
|
```bash
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
250
|
+
git clone https://github.com/cogeotiff/rio-tiler.git
|
|
251
|
+
cd rio-tiler
|
|
252
|
+
python -m pip install -U pip
|
|
253
|
+
python -m pip install -e .
|
|
278
254
|
```
|
|
279
255
|
|
|
280
256
|
## Plugins
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
rio_tiler/__init__.py,sha256=
|
|
2
|
-
rio_tiler/colormap.py,sha256=
|
|
1
|
+
rio_tiler/__init__.py,sha256=lKZDEOYy6ewX4dX9hskgOUWtXPSxhBHJ4fzw3Yvf6Zc,192
|
|
2
|
+
rio_tiler/colormap.py,sha256=4sG9VIfDAHI-ckQgmci0-U-wL9ZU9exZJszgsrt8wBA,11310
|
|
3
3
|
rio_tiler/constants.py,sha256=55i-7JZDupTXZdLgxL03KsgM4lAzuGuIVP1zZKktzp0,426
|
|
4
|
-
rio_tiler/errors.py,sha256=
|
|
5
|
-
rio_tiler/expression.py,sha256=
|
|
4
|
+
rio_tiler/errors.py,sha256=GFAuE1AaSvx6dd0z5um9n3y1wVzUyQ5S8qY7_tXdrR8,2178
|
|
5
|
+
rio_tiler/expression.py,sha256=8StB3kqW0EqsW48mu8tlnFNgq48Cyuaj0I-ahmg27Uc,2305
|
|
6
6
|
rio_tiler/logger.py,sha256=RR8lnW3uVXkFkPa3nNJS_tTndmdiNNDVXpCDGDxGf0A,81
|
|
7
|
-
rio_tiler/models.py,sha256=
|
|
7
|
+
rio_tiler/models.py,sha256=ABXuGNTtVI1bBZ90AdyXigwug2P7kg9lrDbLss0h61w,34921
|
|
8
8
|
rio_tiler/profiles.py,sha256=EAx2JdcaOcMw5PZjxbCqQBXXWMac9mjtpHoVFPJEDNQ,1562
|
|
9
9
|
rio_tiler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
rio_tiler/reader.py,sha256=
|
|
11
|
-
rio_tiler/tasks.py,sha256=
|
|
10
|
+
rio_tiler/reader.py,sha256=5JVlhJS8Ra8jPPVkjkRw2UuXOnG7mPtKxYlDC9vF6qI,25047
|
|
11
|
+
rio_tiler/tasks.py,sha256=7MwIicDMSCScsbds6crWRa7lRwvvt2cbGQAxybkrRvk,3613
|
|
12
12
|
rio_tiler/types.py,sha256=R9XOL-EEb_cwbD4SFNVmViXC84D2p4BEVNCXg0nlh7I,1684
|
|
13
|
-
rio_tiler/utils.py,sha256=
|
|
13
|
+
rio_tiler/utils.py,sha256=BwTHM_qmwRl0QEHwf7qQa22zdQPWeuhUHzCDqlUDkU8,32156
|
|
14
14
|
rio_tiler/cmap_data/__init__.py,sha256=8FtVmfpTjXlvhxQ5QesN0UC1m_B3MuF3LbGbhMC5Rw4,1039
|
|
15
15
|
rio_tiler/cmap_data/accent.npy,sha256=Qde1ldOoXghe4L05v1QbVvnMA1ldwNjKWPf5xCBbmI4,1152
|
|
16
16
|
rio_tiler/cmap_data/accent_r.npy,sha256=ba-GWSMSPRAcm9CGzlXJeNG4ABbBHDCV602hAWV2idc,1152
|
|
@@ -225,18 +225,20 @@ rio_tiler/cmap_data/ylorrd.npy,sha256=9ImXljw40oe60w8uV4EMDPY4aFFVkGbyCBi6SlTX83
|
|
|
225
225
|
rio_tiler/cmap_data/ylorrd_r.npy,sha256=K5uiHNHbLxV5SizyT09cSVAxldE-BW5GpOXxUp7UsTE,1152
|
|
226
226
|
rio_tiler/experimental/__init__.py,sha256=dgW817h5U9OQt4V68L912g3DivPfhoWKvS-mI83sqio,328
|
|
227
227
|
rio_tiler/experimental/vsifile.py,sha256=t1tJviPmFkjWIbr86BEnsK7pU4iiqLh1pKYZyNNb1AY,960
|
|
228
|
+
rio_tiler/experimental/zarr.py,sha256=S9PJcv1JwoMI3sBRg0z2uEj5rk8KvwlR0-k7kA27rJ4,11775
|
|
228
229
|
rio_tiler/io/__init__.py,sha256=_L4iILm6vSiJ14GEDDOvkuUHRtbWC9oqx6Bu8PxHhvA,270
|
|
229
|
-
rio_tiler/io/base.py,sha256=
|
|
230
|
-
rio_tiler/io/rasterio.py,sha256=
|
|
230
|
+
rio_tiler/io/base.py,sha256=3aKWc_1eGe_6Gzn5v8XOmZqUodfYsgytVLvNISqi5-g,53199
|
|
231
|
+
rio_tiler/io/rasterio.py,sha256=JcjHJYmntBx4yyLOnTOJsZ3631TNsXFHbVGwK2MPnS8,29190
|
|
231
232
|
rio_tiler/io/stac.py,sha256=kIEW4F71PouXF-Ubpz-VVXujnp8LqftptPKDo_J3BTw,12831
|
|
232
|
-
rio_tiler/io/xarray.py,sha256=
|
|
233
|
+
rio_tiler/io/xarray.py,sha256=jISNXCV2lBjs5qOYSLvSfrD7v6fO69sdsb7KC3fatUQ,26915
|
|
233
234
|
rio_tiler/mosaic/__init__.py,sha256=Yj6CKpnFl8PJhLSp-a55wo33hKZ8-6OOBJtWA1HZVy8,118
|
|
234
|
-
rio_tiler/mosaic/
|
|
235
|
+
rio_tiler/mosaic/backend.py,sha256=OI4hOM2No30gQVSIyAAwgx6ntEvw0Rk9neTeOmwstrw,8200
|
|
236
|
+
rio_tiler/mosaic/reader.py,sha256=4sgl8IlV7zOtcfCt6XWw5UZLMCP0EgNbR2vRXObEGDA,11029
|
|
235
237
|
rio_tiler/mosaic/methods/__init__.py,sha256=tgkXM9skaTLXIm5QFoheOEznQXM97KGflcAWHfkrt1g,612
|
|
236
238
|
rio_tiler/mosaic/methods/base.py,sha256=9YZJWVRwH5Fk9KO9q5CW52Q8Mf60tAJ21oM4ixEDXBo,1424
|
|
237
239
|
rio_tiler/mosaic/methods/defaults.py,sha256=P-zSVVgvQ2oRiMchC3bMqIYLTX7H3743jsD_VmqStxM,7642
|
|
238
|
-
rio_tiler-
|
|
239
|
-
rio_tiler-
|
|
240
|
-
rio_tiler-
|
|
241
|
-
rio_tiler-
|
|
242
|
-
rio_tiler-
|
|
240
|
+
rio_tiler-8.0.0.dist-info/METADATA,sha256=wIZwjY9mXGOW3o3KvcLq-UreK9LX433GBkdvbhFv6yM,11159
|
|
241
|
+
rio_tiler-8.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
242
|
+
rio_tiler-8.0.0.dist-info/licenses/AUTHORS.txt,sha256=FCVd4Tjg-8syl0ZugCunpXER8X2-XonW2ZfllyTnRvE,158
|
|
243
|
+
rio_tiler-8.0.0.dist-info/licenses/LICENSE,sha256=vq8Tt4KoYQT9JxAjQ4yXMmmhFYRTsBRgrOj-ao-bC5o,1517
|
|
244
|
+
rio_tiler-8.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|