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
rio_tiler/io/xarray.py
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import math
|
|
6
|
+
import os
|
|
6
7
|
import warnings
|
|
7
|
-
from typing import Any, Dict, List,
|
|
8
|
+
from typing import Any, Dict, List, Tuple
|
|
8
9
|
|
|
9
10
|
import attr
|
|
10
11
|
import numpy
|
|
@@ -23,6 +24,7 @@ from rasterio.warp import transform_bounds, transform_geom
|
|
|
23
24
|
from rio_tiler.constants import WEB_MERCATOR_CRS, WEB_MERCATOR_TMS, WGS84_CRS
|
|
24
25
|
from rio_tiler.errors import (
|
|
25
26
|
InvalidGeographicBounds,
|
|
27
|
+
MaxArraySizeError,
|
|
26
28
|
MissingCRS,
|
|
27
29
|
PointOutsideBounds,
|
|
28
30
|
TileOutsideBounds,
|
|
@@ -50,6 +52,9 @@ except ImportError: # pragma: nocover
|
|
|
50
52
|
rioxarray = None # type: ignore
|
|
51
53
|
|
|
52
54
|
|
|
55
|
+
MAX_ARRAY_SIZE = os.environ.get("RIO_TILER_MAX_ARRAY_SIZE", 1_000_000_000) # 1Gb
|
|
56
|
+
|
|
57
|
+
|
|
53
58
|
@attr.s
|
|
54
59
|
class XarrayReader(BaseReader):
|
|
55
60
|
"""Xarray Reader.
|
|
@@ -133,7 +138,7 @@ class XarrayReader(BaseReader):
|
|
|
133
138
|
return self._maxzoom
|
|
134
139
|
|
|
135
140
|
@property
|
|
136
|
-
def
|
|
141
|
+
def band_descriptions(self) -> List[str]:
|
|
137
142
|
"""
|
|
138
143
|
Return list of `band descriptions` in DataArray.
|
|
139
144
|
|
|
@@ -155,7 +160,7 @@ class XarrayReader(BaseReader):
|
|
|
155
160
|
if coords_name:
|
|
156
161
|
return [str(self.input.coords[coords_name[0]].data)]
|
|
157
162
|
|
|
158
|
-
return [self.input.name or "
|
|
163
|
+
return [self.input.name or ""]
|
|
159
164
|
|
|
160
165
|
return [str(band) for d in self._dims for band in self.input[d].values]
|
|
161
166
|
|
|
@@ -168,7 +173,7 @@ class XarrayReader(BaseReader):
|
|
|
168
173
|
"crs": CRS_to_uri(self.crs) or self.crs.to_wkt(),
|
|
169
174
|
"band_metadata": [(f"b{ix}", v) for ix, v in enumerate(metadata, 1)],
|
|
170
175
|
"band_descriptions": [
|
|
171
|
-
(f"b{ix}", v) for ix, v in enumerate(self.
|
|
176
|
+
(f"b{ix}", v) for ix, v in enumerate(self.band_descriptions, 1)
|
|
172
177
|
],
|
|
173
178
|
"dtype": str(self.input.dtype),
|
|
174
179
|
"nodata_type": "Nodata" if self.input.rio.nodata is not None else "None",
|
|
@@ -186,11 +191,14 @@ class XarrayReader(BaseReader):
|
|
|
186
191
|
return Info(**meta)
|
|
187
192
|
|
|
188
193
|
def _sel_indexes(
|
|
189
|
-
self,
|
|
190
|
-
|
|
194
|
+
self,
|
|
195
|
+
indexes: Indexes | None = None,
|
|
196
|
+
) -> Tuple[xarray.DataArray, List[str], List[str]]:
|
|
191
197
|
"""Select `band` indexes in DataArray."""
|
|
192
198
|
da = self.input
|
|
193
|
-
|
|
199
|
+
band_descriptions = self.band_descriptions
|
|
200
|
+
band_names = [f"b{ix + 1}" for ix in range(self.input.rio.count)]
|
|
201
|
+
|
|
194
202
|
if indexes := cast_to_sequence(indexes):
|
|
195
203
|
assert all(v > 0 for v in indexes), "Indexes value must be >= 1"
|
|
196
204
|
if da.ndim == 2:
|
|
@@ -199,28 +207,30 @@ class XarrayReader(BaseReader):
|
|
|
199
207
|
f"Invalid indexes {indexes} for array of shape {da.shape}"
|
|
200
208
|
)
|
|
201
209
|
|
|
202
|
-
return da, band_names
|
|
210
|
+
return da, band_names, band_descriptions
|
|
203
211
|
|
|
204
212
|
indexes = [idx - 1 for idx in indexes]
|
|
213
|
+
|
|
205
214
|
da = da[indexes]
|
|
206
|
-
|
|
215
|
+
band_descriptions = [band_descriptions[idx] for idx in indexes]
|
|
216
|
+
band_names = [band_names[idx] for idx in indexes]
|
|
207
217
|
|
|
208
|
-
return da, band_names
|
|
218
|
+
return da, band_names, band_descriptions
|
|
209
219
|
|
|
210
220
|
def statistics(
|
|
211
221
|
self,
|
|
212
222
|
categorical: bool = False,
|
|
213
|
-
categories:
|
|
214
|
-
percentiles:
|
|
215
|
-
hist_options:
|
|
216
|
-
nodata:
|
|
217
|
-
indexes:
|
|
223
|
+
categories: List[float] | None = None,
|
|
224
|
+
percentiles: List[int] | None = None,
|
|
225
|
+
hist_options: Dict | None = None,
|
|
226
|
+
nodata: NoData | None = None,
|
|
227
|
+
indexes: Indexes | None = None,
|
|
218
228
|
**kwargs: Any,
|
|
219
229
|
) -> Dict[str, BandStatistics]:
|
|
220
230
|
"""Return statistics from a dataset."""
|
|
221
231
|
hist_options = hist_options or {}
|
|
222
232
|
|
|
223
|
-
da, band_names = self._sel_indexes(indexes)
|
|
233
|
+
da, band_names, _ = self._sel_indexes(indexes)
|
|
224
234
|
|
|
225
235
|
if nodata is not None:
|
|
226
236
|
da = da.rio.write_nodata(nodata)
|
|
@@ -246,8 +256,8 @@ class XarrayReader(BaseReader):
|
|
|
246
256
|
tilesize: int = 256,
|
|
247
257
|
reproject_method: WarpResampling = "nearest",
|
|
248
258
|
auto_expand: bool = True,
|
|
249
|
-
nodata:
|
|
250
|
-
indexes:
|
|
259
|
+
nodata: NoData | None = None,
|
|
260
|
+
indexes: Indexes | None = None,
|
|
251
261
|
out_dtype: str | numpy.dtype | None = None,
|
|
252
262
|
**kwargs: Any,
|
|
253
263
|
) -> ImageData:
|
|
@@ -291,15 +301,15 @@ class XarrayReader(BaseReader):
|
|
|
291
301
|
def part( # noqa: C901
|
|
292
302
|
self,
|
|
293
303
|
bbox: BBox,
|
|
294
|
-
dst_crs:
|
|
304
|
+
dst_crs: CRS | None = None,
|
|
295
305
|
bounds_crs: CRS = WGS84_CRS,
|
|
296
306
|
reproject_method: WarpResampling = "nearest",
|
|
297
307
|
auto_expand: bool = True,
|
|
298
|
-
nodata:
|
|
299
|
-
indexes:
|
|
300
|
-
max_size:
|
|
301
|
-
height:
|
|
302
|
-
width:
|
|
308
|
+
nodata: NoData | None = None,
|
|
309
|
+
indexes: Indexes | None = None,
|
|
310
|
+
max_size: int | None = None,
|
|
311
|
+
height: int | None = None,
|
|
312
|
+
width: int | None = None,
|
|
303
313
|
resampling_method: RIOResampling = "nearest",
|
|
304
314
|
out_dtype: str | numpy.dtype | None = None,
|
|
305
315
|
**kwargs: Any,
|
|
@@ -331,7 +341,7 @@ class XarrayReader(BaseReader):
|
|
|
331
341
|
|
|
332
342
|
dst_crs = dst_crs or bounds_crs
|
|
333
343
|
|
|
334
|
-
da, band_names = self._sel_indexes(indexes)
|
|
344
|
+
da, band_names, band_descriptions = self._sel_indexes(indexes)
|
|
335
345
|
|
|
336
346
|
if nodata is not None:
|
|
337
347
|
da = da.rio.write_nodata(nodata)
|
|
@@ -348,6 +358,11 @@ class XarrayReader(BaseReader):
|
|
|
348
358
|
auto_expand=auto_expand,
|
|
349
359
|
)
|
|
350
360
|
|
|
361
|
+
if da.nbytes > MAX_ARRAY_SIZE:
|
|
362
|
+
raise MaxArraySizeError(
|
|
363
|
+
f"Maximum array limit {MAX_ARRAY_SIZE} reached, trying to put DataArray of {da.shape} in memory."
|
|
364
|
+
)
|
|
365
|
+
|
|
351
366
|
src_width = da.rio.width
|
|
352
367
|
src_height = da.rio.height
|
|
353
368
|
src_bounds = list(da.rio.bounds())
|
|
@@ -374,7 +389,7 @@ class XarrayReader(BaseReader):
|
|
|
374
389
|
src_bounds[1] = max(src_bounds[1], -85.06)
|
|
375
390
|
src_bounds[3] = min(src_bounds[3], 85.06)
|
|
376
391
|
|
|
377
|
-
# South
|
|
392
|
+
# North->South
|
|
378
393
|
if src_transform.e > 0:
|
|
379
394
|
src_bounds = [src_bounds[0], src_bounds[3], src_bounds[2], src_bounds[1]]
|
|
380
395
|
# West->East
|
|
@@ -422,45 +437,33 @@ class XarrayReader(BaseReader):
|
|
|
422
437
|
)
|
|
423
438
|
|
|
424
439
|
arr = da.to_masked_array()
|
|
440
|
+
arr.mask |= arr.data == da.rio.nodata
|
|
425
441
|
if out_dtype:
|
|
426
442
|
arr = arr.astype(out_dtype)
|
|
427
|
-
arr.mask |= arr.data == da.rio.nodata
|
|
428
443
|
|
|
429
444
|
output_bounds = da.rio._unordered_bounds()
|
|
430
445
|
if output_bounds[1] > output_bounds[3] and da.rio.transform().e > 0:
|
|
431
446
|
yaxis = self.input.dims.index(self.input.rio.y_dim)
|
|
432
447
|
arr = numpy.flip(arr, axis=yaxis)
|
|
433
448
|
|
|
434
|
-
|
|
449
|
+
return ImageData(
|
|
435
450
|
arr,
|
|
436
451
|
bounds=bbox,
|
|
437
452
|
crs=da.rio.crs,
|
|
438
453
|
dataset_statistics=stats,
|
|
439
454
|
band_names=band_names,
|
|
455
|
+
band_descriptions=band_descriptions,
|
|
456
|
+
nodata=da.rio.nodata,
|
|
440
457
|
)
|
|
441
458
|
|
|
442
|
-
|
|
443
|
-
output_width = width or img.width
|
|
444
|
-
if max_size and not (width and height):
|
|
445
|
-
output_height, output_width = _get_width_height(
|
|
446
|
-
max_size, img.height, img.width
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
if output_height != img.height or output_width != img.width:
|
|
450
|
-
img = img.resize(
|
|
451
|
-
output_height, output_width, resampling_method=resampling_method
|
|
452
|
-
)
|
|
453
|
-
|
|
454
|
-
return img
|
|
455
|
-
|
|
456
|
-
def preview(
|
|
459
|
+
def preview( # noqa: C901
|
|
457
460
|
self,
|
|
458
461
|
max_size: int = 1024,
|
|
459
|
-
height:
|
|
460
|
-
width:
|
|
461
|
-
nodata:
|
|
462
|
-
indexes:
|
|
463
|
-
dst_crs:
|
|
462
|
+
height: int | None = None,
|
|
463
|
+
width: int | None = None,
|
|
464
|
+
nodata: NoData | None = None,
|
|
465
|
+
indexes: Indexes | None = None,
|
|
466
|
+
dst_crs: CRS | None = None,
|
|
464
467
|
reproject_method: WarpResampling = "nearest",
|
|
465
468
|
resampling_method: RIOResampling = "nearest",
|
|
466
469
|
out_dtype: str | numpy.dtype | None = None,
|
|
@@ -488,7 +491,12 @@ class XarrayReader(BaseReader):
|
|
|
488
491
|
)
|
|
489
492
|
max_size = None
|
|
490
493
|
|
|
491
|
-
da, band_names = self._sel_indexes(indexes)
|
|
494
|
+
da, band_names, band_descriptions = self._sel_indexes(indexes)
|
|
495
|
+
|
|
496
|
+
if da.nbytes > MAX_ARRAY_SIZE:
|
|
497
|
+
raise MaxArraySizeError(
|
|
498
|
+
f"Maximum array limit {MAX_ARRAY_SIZE} reached, trying to put DataArray of {da.shape} in memory."
|
|
499
|
+
)
|
|
492
500
|
|
|
493
501
|
if nodata is not None:
|
|
494
502
|
da = da.rio.write_nodata(nodata)
|
|
@@ -574,6 +582,8 @@ class XarrayReader(BaseReader):
|
|
|
574
582
|
crs=da.rio.crs,
|
|
575
583
|
dataset_statistics=stats,
|
|
576
584
|
band_names=band_names,
|
|
585
|
+
band_descriptions=band_descriptions,
|
|
586
|
+
nodata=da.rio.nodata,
|
|
577
587
|
)
|
|
578
588
|
|
|
579
589
|
if max_size:
|
|
@@ -596,8 +606,8 @@ class XarrayReader(BaseReader):
|
|
|
596
606
|
lon: float,
|
|
597
607
|
lat: float,
|
|
598
608
|
coord_crs: CRS = WGS84_CRS,
|
|
599
|
-
nodata:
|
|
600
|
-
indexes:
|
|
609
|
+
nodata: NoData | None = None,
|
|
610
|
+
indexes: Indexes | None = None,
|
|
601
611
|
out_dtype: str | numpy.dtype | None = None,
|
|
602
612
|
**kwargs: Any,
|
|
603
613
|
) -> PointData:
|
|
@@ -621,7 +631,7 @@ class XarrayReader(BaseReader):
|
|
|
621
631
|
):
|
|
622
632
|
raise PointOutsideBounds("Point is outside dataset bounds")
|
|
623
633
|
|
|
624
|
-
da, band_names = self._sel_indexes(indexes)
|
|
634
|
+
da, band_names, band_descriptions = self._sel_indexes(indexes)
|
|
625
635
|
|
|
626
636
|
if nodata is not None:
|
|
627
637
|
da = da.rio.write_nodata(nodata)
|
|
@@ -642,21 +652,23 @@ class XarrayReader(BaseReader):
|
|
|
642
652
|
coordinates=(lon, lat),
|
|
643
653
|
crs=coord_crs,
|
|
644
654
|
band_names=band_names,
|
|
655
|
+
band_descriptions=band_descriptions,
|
|
645
656
|
pixel_location=(x, y),
|
|
657
|
+
nodata=da.rio.nodata,
|
|
646
658
|
)
|
|
647
659
|
|
|
648
660
|
def feature(
|
|
649
661
|
self,
|
|
650
662
|
shape: Dict,
|
|
651
|
-
dst_crs:
|
|
663
|
+
dst_crs: CRS | None = None,
|
|
652
664
|
shape_crs: CRS = WGS84_CRS,
|
|
653
665
|
reproject_method: WarpResampling = "nearest",
|
|
654
666
|
auto_expand: bool = True,
|
|
655
|
-
nodata:
|
|
656
|
-
indexes:
|
|
657
|
-
max_size:
|
|
658
|
-
height:
|
|
659
|
-
width:
|
|
667
|
+
nodata: NoData | None = None,
|
|
668
|
+
indexes: Indexes | None = None,
|
|
669
|
+
max_size: int | None = None,
|
|
670
|
+
height: int | None = None,
|
|
671
|
+
width: int | None = None,
|
|
660
672
|
resampling_method: RIOResampling = "nearest",
|
|
661
673
|
out_dtype: str | numpy.dtype | None = None,
|
|
662
674
|
**kwargs: Any,
|