rio-tiler 8.0.4__py3-none-any.whl → 9.0.0a1__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 +6 -6
- rio_tiler/experimental/vsifile.py +1 -3
- rio_tiler/experimental/zarr.py +29 -28
- rio_tiler/expression.py +4 -4
- rio_tiler/io/base.py +222 -347
- rio_tiler/io/rasterio.py +89 -81
- rio_tiler/io/stac.py +50 -41
- rio_tiler/io/xarray.py +35 -27
- rio_tiler/models.py +70 -53
- rio_tiler/mosaic/backend.py +2 -2
- rio_tiler/mosaic/methods/base.py +3 -4
- rio_tiler/mosaic/methods/defaults.py +18 -19
- rio_tiler/mosaic/reader.py +20 -19
- rio_tiler/reader.py +44 -44
- rio_tiler/tasks.py +9 -8
- rio_tiler/types.py +20 -21
- rio_tiler/utils.py +33 -42
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/METADATA +1 -1
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/RECORD +23 -23
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/WHEEL +0 -0
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/licenses/AUTHORS.txt +0 -0
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/licenses/LICENSE +0 -0
rio_tiler/io/base.py
CHANGED
|
@@ -4,8 +4,9 @@ import abc
|
|
|
4
4
|
import contextlib
|
|
5
5
|
import re
|
|
6
6
|
import warnings
|
|
7
|
+
from collections.abc import Sequence
|
|
7
8
|
from functools import cached_property
|
|
8
|
-
from typing import Any,
|
|
9
|
+
from typing import Any, cast
|
|
9
10
|
|
|
10
11
|
import attr
|
|
11
12
|
import numpy
|
|
@@ -44,9 +45,9 @@ class SpatialMixin:
|
|
|
44
45
|
bounds: BBox = attr.ib(init=False)
|
|
45
46
|
crs: CRS = attr.ib(init=False)
|
|
46
47
|
|
|
47
|
-
transform:
|
|
48
|
-
height:
|
|
49
|
-
width:
|
|
48
|
+
transform: Affine | None = attr.ib(default=None, init=False)
|
|
49
|
+
height: int | None = attr.ib(default=None, init=False)
|
|
50
|
+
width: int | None = attr.ib(default=None, init=False)
|
|
50
51
|
|
|
51
52
|
def get_geographic_bounds(self, crs: CRS) -> BBox:
|
|
52
53
|
"""Return Geographic Bounds for a Geographic CRS."""
|
|
@@ -238,11 +239,11 @@ class BaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
238
239
|
...
|
|
239
240
|
|
|
240
241
|
@abc.abstractmethod
|
|
241
|
-
def statistics(self) ->
|
|
242
|
+
def statistics(self) -> dict[str, BandStatistics]:
|
|
242
243
|
"""Return bands statistics from a dataset.
|
|
243
244
|
|
|
244
245
|
Returns:
|
|
245
|
-
|
|
246
|
+
dict[str, rio_tiler.models.BandStatistics]: bands statistics.
|
|
246
247
|
|
|
247
248
|
"""
|
|
248
249
|
...
|
|
@@ -300,7 +301,7 @@ class BaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
300
301
|
...
|
|
301
302
|
|
|
302
303
|
@abc.abstractmethod
|
|
303
|
-
def feature(self, shape:
|
|
304
|
+
def feature(self, shape: dict) -> ImageData:
|
|
304
305
|
"""Read a Dataset for a GeoJSON feature.
|
|
305
306
|
|
|
306
307
|
Args:
|
|
@@ -331,16 +332,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
331
332
|
input: Any = attr.ib()
|
|
332
333
|
tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
|
|
333
334
|
|
|
334
|
-
minzoom: int = attr.ib(default=None)
|
|
335
|
-
maxzoom: int = attr.ib(default=None)
|
|
335
|
+
minzoom: int | None = attr.ib(default=None)
|
|
336
|
+
maxzoom: int | None = attr.ib(default=None)
|
|
336
337
|
|
|
337
|
-
reader:
|
|
338
|
-
reader_options:
|
|
338
|
+
reader: type[BaseReader] = attr.ib(init=False)
|
|
339
|
+
reader_options: dict = attr.ib(factory=dict)
|
|
339
340
|
|
|
340
341
|
assets: Sequence[str] = attr.ib(init=False)
|
|
341
|
-
default_assets:
|
|
342
|
+
default_assets: Sequence[str] | None = attr.ib(init=False, default=None)
|
|
342
343
|
|
|
343
|
-
ctx:
|
|
344
|
+
ctx: type[contextlib.AbstractContextManager] = attr.ib(
|
|
344
345
|
init=False, default=contextlib.nullcontext
|
|
345
346
|
)
|
|
346
347
|
|
|
@@ -357,34 +358,15 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
357
358
|
"""Validate asset name and construct url."""
|
|
358
359
|
...
|
|
359
360
|
|
|
360
|
-
def _get_reader(self, asset_info: AssetInfo) ->
|
|
361
|
+
def _get_reader(self, asset_info: AssetInfo) -> tuple[type[BaseReader], dict]:
|
|
361
362
|
"""Get Asset Reader and options."""
|
|
362
363
|
return self.reader, {}
|
|
363
364
|
|
|
364
|
-
def parse_expression(self, expression: str, asset_as_band: bool = False) -> Tuple:
|
|
365
|
-
"""Parse rio-tiler band math expression."""
|
|
366
|
-
input_assets = "|".join(self.assets)
|
|
367
|
-
|
|
368
|
-
if asset_as_band:
|
|
369
|
-
_re = re.compile(rf"\b({input_assets})\b")
|
|
370
|
-
else:
|
|
371
|
-
_re = re.compile(rf"\b({input_assets})_b\d+\b")
|
|
372
|
-
|
|
373
|
-
assets = tuple(set(re.findall(_re, expression)))
|
|
374
|
-
if not assets:
|
|
375
|
-
raise InvalidExpression(
|
|
376
|
-
f"Could not find any valid assets in '{expression}' expression. Assets are: {self.assets}"
|
|
377
|
-
if asset_as_band
|
|
378
|
-
else f"Could not find any valid assets in '{expression}' expression, maybe try with `asset_as_band=True`. Assets are: {self.assets}"
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
return assets
|
|
382
|
-
|
|
383
365
|
def _update_statistics(
|
|
384
366
|
self,
|
|
385
367
|
img: ImageData,
|
|
386
|
-
indexes:
|
|
387
|
-
statistics:
|
|
368
|
+
indexes: Indexes | None = None,
|
|
369
|
+
statistics: Sequence[tuple[float, float]] | None = None,
|
|
388
370
|
):
|
|
389
371
|
"""Update ImageData Statistics from AssetInfo."""
|
|
390
372
|
indexes = cast_to_sequence(indexes)
|
|
@@ -400,9 +382,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
400
382
|
|
|
401
383
|
def info(
|
|
402
384
|
self,
|
|
403
|
-
assets:
|
|
385
|
+
assets: Sequence[str] | str | None = None,
|
|
404
386
|
**kwargs: Any,
|
|
405
|
-
) ->
|
|
387
|
+
) -> dict[str, Info]:
|
|
406
388
|
"""Return metadata from multiple assets.
|
|
407
389
|
|
|
408
390
|
Args:
|
|
@@ -419,33 +401,26 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
419
401
|
)
|
|
420
402
|
assets = cast_to_sequence(assets or self.assets)
|
|
421
403
|
|
|
422
|
-
def _reader(asset: str, **kwargs: Any) ->
|
|
404
|
+
def _reader(asset: str, **kwargs: Any) -> dict:
|
|
423
405
|
asset_info = self._get_asset_info(asset)
|
|
424
|
-
reader,
|
|
406
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
425
407
|
|
|
408
|
+
options = {**self.reader_options, **reader_options}
|
|
426
409
|
with self.ctx(**asset_info.get("env", {})):
|
|
427
|
-
with reader(
|
|
428
|
-
asset_info["
|
|
429
|
-
tms=self.tms,
|
|
430
|
-
**{**self.reader_options, **options},
|
|
431
|
-
) as src:
|
|
432
|
-
return src.info()
|
|
410
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
411
|
+
return src.info(**asset_info["method_options"])
|
|
433
412
|
|
|
434
413
|
return multi_values(assets, _reader, **kwargs)
|
|
435
414
|
|
|
436
415
|
def statistics(
|
|
437
416
|
self,
|
|
438
|
-
assets:
|
|
439
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
440
|
-
asset_expression: Optional[Dict[str, str]] = None,
|
|
417
|
+
assets: Sequence[str] | str | None = None,
|
|
441
418
|
**kwargs: Any,
|
|
442
|
-
) ->
|
|
419
|
+
) -> dict[str, dict[str, BandStatistics]]:
|
|
443
420
|
"""Return array statistics for multiple assets.
|
|
444
421
|
|
|
445
422
|
Args:
|
|
446
423
|
assets (sequence of str or str): assets to fetch info from.
|
|
447
|
-
asset_indexes (dict, optional): Band indexes for each asset (e.g {"asset1": 1, "asset2": (1, 2,)}).
|
|
448
|
-
asset_expression (dict, optional): rio-tiler expression for each asset (e.g. {"asset1": "b1/b2+b3", "asset2": ...}).
|
|
449
424
|
kwargs (optional): Options to forward to the `self.reader.statistics` method.
|
|
450
425
|
|
|
451
426
|
Returns:
|
|
@@ -459,46 +434,35 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
459
434
|
)
|
|
460
435
|
|
|
461
436
|
assets = cast_to_sequence(assets or self.assets)
|
|
462
|
-
asset_indexes = asset_indexes or {}
|
|
463
|
-
asset_expression = asset_expression or {}
|
|
464
437
|
|
|
465
|
-
def _reader(asset: str, *args: Any, **kwargs: Any) ->
|
|
438
|
+
def _reader(asset: str, *args: Any, **kwargs: Any) -> dict:
|
|
466
439
|
asset_info = self._get_asset_info(asset)
|
|
467
|
-
reader,
|
|
440
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
468
441
|
|
|
442
|
+
options = {**self.reader_options, **reader_options}
|
|
469
443
|
with self.ctx(**asset_info.get("env", {})):
|
|
470
|
-
with reader(
|
|
471
|
-
asset_info["
|
|
472
|
-
|
|
473
|
-
**{**self.reader_options, **options},
|
|
474
|
-
) as src:
|
|
475
|
-
return src.statistics(
|
|
476
|
-
*args,
|
|
477
|
-
indexes=asset_indexes.get(asset, kwargs.pop("indexes", None)),
|
|
478
|
-
expression=asset_expression.get(asset),
|
|
479
|
-
**kwargs,
|
|
480
|
-
)
|
|
444
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
445
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
446
|
+
return src.statistics(*args, **method_options)
|
|
481
447
|
|
|
482
448
|
return multi_values(assets, _reader, **kwargs)
|
|
483
449
|
|
|
484
450
|
def merged_statistics(
|
|
485
451
|
self,
|
|
486
|
-
assets:
|
|
487
|
-
expression:
|
|
488
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
452
|
+
assets: Sequence[str] | str | None = None,
|
|
453
|
+
expression: str | None = None,
|
|
489
454
|
categorical: bool = False,
|
|
490
|
-
categories:
|
|
491
|
-
percentiles:
|
|
492
|
-
hist_options:
|
|
455
|
+
categories: list[float] | None = None,
|
|
456
|
+
percentiles: list[int] | None = None,
|
|
457
|
+
hist_options: dict | None = None,
|
|
493
458
|
max_size: int = 1024,
|
|
494
459
|
**kwargs: Any,
|
|
495
|
-
) ->
|
|
460
|
+
) -> dict[str, BandStatistics]:
|
|
496
461
|
"""Return array statistics for multiple assets.
|
|
497
462
|
|
|
498
463
|
Args:
|
|
499
464
|
assets (sequence of str or str): assets to fetch info from.
|
|
500
|
-
expression (str, optional): rio-tiler expression
|
|
501
|
-
asset_indexes (dict, optional): Band indexes for each asset (e.g {"asset1": 1, "asset2": (1, 2,)}).
|
|
465
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
502
466
|
categorical (bool): treat input data as categorical data. Defaults to False.
|
|
503
467
|
categories (list of numbers, optional): list of categories to return value for.
|
|
504
468
|
percentiles (list of numbers, optional): list of percentile values to calculate. Defaults to `[2, 98]`.
|
|
@@ -511,18 +475,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
511
475
|
Dict[str, rio_tiler.models.BandStatistics]: bands statistics.
|
|
512
476
|
|
|
513
477
|
"""
|
|
514
|
-
if not
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
assets = cast_to_sequence(assets or self.assets)
|
|
478
|
+
if not assets:
|
|
479
|
+
warnings.warn(
|
|
480
|
+
"No `assets` option passed, will fetch statistics for all available assets.",
|
|
481
|
+
UserWarning,
|
|
482
|
+
)
|
|
483
|
+
assets = cast_to_sequence(assets or self.assets)
|
|
521
484
|
|
|
522
485
|
data = self.preview(
|
|
523
486
|
assets=assets,
|
|
524
487
|
expression=expression,
|
|
525
|
-
asset_indexes=asset_indexes,
|
|
526
488
|
max_size=max_size,
|
|
527
489
|
**kwargs,
|
|
528
490
|
)
|
|
@@ -538,9 +500,8 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
538
500
|
tile_x: int,
|
|
539
501
|
tile_y: int,
|
|
540
502
|
tile_z: int,
|
|
541
|
-
assets:
|
|
542
|
-
expression:
|
|
543
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
503
|
+
assets: Sequence[str] | str | None = None,
|
|
504
|
+
expression: str | None = None,
|
|
544
505
|
asset_as_band: bool = False,
|
|
545
506
|
**kwargs: Any,
|
|
546
507
|
) -> ImageData:
|
|
@@ -551,87 +512,73 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
551
512
|
tile_y (int): Tile's vertical index.
|
|
552
513
|
tile_z (int): Tile's zoom level index.
|
|
553
514
|
assets (sequence of str or str, optional): assets to fetch info from.
|
|
554
|
-
expression (str, optional): rio-tiler expression
|
|
555
|
-
|
|
515
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
516
|
+
asset_as_band (bool, optional): treat each asset as a separate band. Defaults to False.
|
|
556
517
|
kwargs (optional): Options to forward to the `self.reader.tile` method.
|
|
557
518
|
|
|
558
519
|
Returns:
|
|
559
520
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
560
521
|
|
|
561
522
|
"""
|
|
523
|
+
if kwargs.pop("asset_indexes", None):
|
|
524
|
+
warnings.warn(
|
|
525
|
+
"`asset_indexes` parameter is deprecated in `tile` method and will be ignored.",
|
|
526
|
+
DeprecationWarning,
|
|
527
|
+
)
|
|
528
|
+
|
|
562
529
|
if not self.tile_exists(tile_x, tile_y, tile_z):
|
|
563
530
|
raise TileOutsideBounds(
|
|
564
531
|
f"Tile(x={tile_x}, y={tile_y}, z={tile_z}) is outside bounds"
|
|
565
532
|
)
|
|
566
533
|
|
|
567
534
|
assets = cast_to_sequence(assets)
|
|
568
|
-
if assets and expression:
|
|
569
|
-
warnings.warn(
|
|
570
|
-
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
571
|
-
ExpressionMixingWarning,
|
|
572
|
-
)
|
|
573
|
-
|
|
574
|
-
if expression:
|
|
575
|
-
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
576
|
-
|
|
577
535
|
if not assets and self.default_assets:
|
|
578
536
|
warnings.warn(
|
|
579
|
-
f"No assets
|
|
537
|
+
f"No assets passed, defaults to {self.default_assets}",
|
|
580
538
|
UserWarning,
|
|
581
539
|
)
|
|
582
540
|
assets = self.default_assets
|
|
583
541
|
|
|
584
542
|
if not assets:
|
|
585
543
|
raise MissingAssets(
|
|
586
|
-
"
|
|
544
|
+
"No Asset defined by `assets` option or class-level `default_assets`."
|
|
587
545
|
)
|
|
588
546
|
|
|
589
|
-
asset_indexes = asset_indexes or {}
|
|
590
|
-
|
|
591
|
-
# We fall back to `indexes` if provided
|
|
592
|
-
indexes = kwargs.pop("indexes", None)
|
|
593
|
-
|
|
594
547
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
595
|
-
idx = asset_indexes.get(asset) or indexes
|
|
596
|
-
|
|
597
548
|
asset_info = self._get_asset_info(asset)
|
|
598
|
-
|
|
549
|
+
asset_name = asset_info["name"]
|
|
550
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
599
551
|
|
|
552
|
+
options = {**self.reader_options, **reader_options}
|
|
600
553
|
with self.ctx(**asset_info.get("env", {})):
|
|
601
|
-
with reader(
|
|
602
|
-
asset_info["
|
|
603
|
-
|
|
604
|
-
**{**self.reader_options, **options},
|
|
605
|
-
) as src:
|
|
606
|
-
data = src.tile(*args, indexes=idx, **kwargs)
|
|
554
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
555
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
556
|
+
data = src.tile(*args, **method_options)
|
|
607
557
|
|
|
608
558
|
self._update_statistics(
|
|
609
|
-
data,
|
|
610
|
-
indexes=idx,
|
|
611
|
-
statistics=asset_info.get("dataset_statistics"),
|
|
559
|
+
data, statistics=asset_info.get("dataset_statistics")
|
|
612
560
|
)
|
|
613
561
|
|
|
614
562
|
metadata = data.metadata or {}
|
|
615
563
|
if m := asset_info.get("metadata"):
|
|
616
564
|
metadata.update(m)
|
|
565
|
+
data.metadata = {asset_name: metadata}
|
|
617
566
|
data.metadata = {asset: metadata}
|
|
618
567
|
|
|
568
|
+
data.band_descriptions = [
|
|
569
|
+
f"{asset_name}_{n}" for n in data.band_descriptions
|
|
570
|
+
]
|
|
619
571
|
if asset_as_band:
|
|
620
572
|
if len(data.band_names) > 1:
|
|
621
573
|
raise AssetAsBandError(
|
|
622
574
|
"Can't use `asset_as_band` for multibands asset"
|
|
623
575
|
)
|
|
624
|
-
data.
|
|
625
|
-
data.band_descriptions = [asset]
|
|
626
|
-
else:
|
|
627
|
-
data.band_names = [f"{asset}_{n}" for n in data.band_names]
|
|
628
|
-
data.band_descriptions = [
|
|
629
|
-
f"{asset}_{n}" for n in data.band_descriptions
|
|
630
|
-
]
|
|
576
|
+
data.band_descriptions = [asset_name]
|
|
631
577
|
|
|
632
578
|
return data
|
|
633
579
|
|
|
634
580
|
img = multi_arrays(assets, _reader, tile_x, tile_y, tile_z, **kwargs)
|
|
581
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
635
582
|
if expression:
|
|
636
583
|
return img.apply_expression(expression)
|
|
637
584
|
|
|
@@ -640,9 +587,8 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
640
587
|
def part(
|
|
641
588
|
self,
|
|
642
589
|
bbox: BBox,
|
|
643
|
-
assets:
|
|
644
|
-
expression:
|
|
645
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
590
|
+
assets: Sequence[str] | str | None = None,
|
|
591
|
+
expression: str | None = None,
|
|
646
592
|
asset_as_band: bool = False,
|
|
647
593
|
**kwargs: Any,
|
|
648
594
|
) -> ImageData:
|
|
@@ -651,24 +597,21 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
651
597
|
Args:
|
|
652
598
|
bbox (tuple): Output bounds (left, bottom, right, top) in target crs.
|
|
653
599
|
assets (sequence of str or str, optional): assets to fetch info from.
|
|
654
|
-
expression (str, optional): rio-tiler expression
|
|
655
|
-
|
|
600
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
601
|
+
asset_as_band (bool, optional): treat each asset as a separate band. Defaults to False.
|
|
656
602
|
kwargs (optional): Options to forward to the `self.reader.part` method.
|
|
657
603
|
|
|
658
604
|
Returns:
|
|
659
605
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
660
606
|
|
|
661
607
|
"""
|
|
662
|
-
|
|
663
|
-
if assets and expression:
|
|
608
|
+
if kwargs.pop("asset_indexes", None):
|
|
664
609
|
warnings.warn(
|
|
665
|
-
"
|
|
666
|
-
|
|
610
|
+
"`asset_indexes` parameter is deprecated in `tile` method and will be ignored.",
|
|
611
|
+
DeprecationWarning,
|
|
667
612
|
)
|
|
668
613
|
|
|
669
|
-
|
|
670
|
-
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
671
|
-
|
|
614
|
+
assets = cast_to_sequence(assets)
|
|
672
615
|
if not assets and self.default_assets:
|
|
673
616
|
warnings.warn(
|
|
674
617
|
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
@@ -678,55 +621,44 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
678
621
|
|
|
679
622
|
if not assets:
|
|
680
623
|
raise MissingAssets(
|
|
681
|
-
"
|
|
624
|
+
"No Asset defined by `assets` option or class-level `default_assets`."
|
|
682
625
|
)
|
|
683
626
|
|
|
684
|
-
asset_indexes = asset_indexes or {}
|
|
685
|
-
|
|
686
|
-
# We fall back to `indexes` if provided
|
|
687
|
-
indexes = kwargs.pop("indexes", None)
|
|
688
|
-
|
|
689
627
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
690
|
-
idx = asset_indexes.get(asset) or indexes
|
|
691
|
-
|
|
692
628
|
asset_info = self._get_asset_info(asset)
|
|
693
|
-
|
|
629
|
+
asset_name = asset_info["name"]
|
|
630
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
694
631
|
|
|
632
|
+
options = {**self.reader_options, **reader_options}
|
|
695
633
|
with self.ctx(**asset_info.get("env", {})):
|
|
696
|
-
with reader(
|
|
697
|
-
asset_info["
|
|
698
|
-
|
|
699
|
-
**{**self.reader_options, **options},
|
|
700
|
-
) as src:
|
|
701
|
-
data = src.part(*args, indexes=idx, **kwargs)
|
|
634
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
635
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
636
|
+
data = src.part(*args, **method_options)
|
|
702
637
|
|
|
703
638
|
self._update_statistics(
|
|
704
639
|
data,
|
|
705
|
-
indexes=idx,
|
|
706
640
|
statistics=asset_info.get("dataset_statistics"),
|
|
707
641
|
)
|
|
708
642
|
|
|
709
643
|
metadata = data.metadata or {}
|
|
710
644
|
if m := asset_info.get("metadata"):
|
|
711
645
|
metadata.update(m)
|
|
712
|
-
data.metadata = {
|
|
646
|
+
data.metadata = {asset_name: metadata}
|
|
713
647
|
|
|
648
|
+
data.band_descriptions = [
|
|
649
|
+
f"{asset_name}_{n}" for n in data.band_descriptions
|
|
650
|
+
]
|
|
714
651
|
if asset_as_band:
|
|
715
652
|
if len(data.band_names) > 1:
|
|
716
653
|
raise AssetAsBandError(
|
|
717
654
|
"Can't use `asset_as_band` for multibands asset"
|
|
718
655
|
)
|
|
719
|
-
data.
|
|
720
|
-
data.band_descriptions = [asset]
|
|
721
|
-
else:
|
|
722
|
-
data.band_names = [f"{asset}_{n}" for n in data.band_names]
|
|
723
|
-
data.band_descriptions = [
|
|
724
|
-
f"{asset}_{n}" for n in data.band_descriptions
|
|
725
|
-
]
|
|
656
|
+
data.band_descriptions = [asset_name]
|
|
726
657
|
|
|
727
658
|
return data
|
|
728
659
|
|
|
729
660
|
img = multi_arrays(assets, _reader, bbox, **kwargs)
|
|
661
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
730
662
|
if expression:
|
|
731
663
|
return img.apply_expression(expression)
|
|
732
664
|
|
|
@@ -734,9 +666,8 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
734
666
|
|
|
735
667
|
def preview(
|
|
736
668
|
self,
|
|
737
|
-
assets:
|
|
738
|
-
expression:
|
|
739
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
669
|
+
assets: Sequence[str] | str | None = None,
|
|
670
|
+
expression: str | None = None,
|
|
740
671
|
asset_as_band: bool = False,
|
|
741
672
|
**kwargs: Any,
|
|
742
673
|
) -> ImageData:
|
|
@@ -744,82 +675,68 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
744
675
|
|
|
745
676
|
Args:
|
|
746
677
|
assets (sequence of str or str, optional): assets to fetch info from.
|
|
747
|
-
expression (str, optional): rio-tiler expression
|
|
748
|
-
|
|
678
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
679
|
+
asset_as_band (bool, optional): treat each asset as a separate band. Defaults to False.
|
|
749
680
|
kwargs (optional): Options to forward to the `self.reader.preview` method.
|
|
750
681
|
|
|
751
682
|
Returns:
|
|
752
683
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
753
684
|
|
|
754
685
|
"""
|
|
755
|
-
|
|
756
|
-
if assets and expression:
|
|
686
|
+
if kwargs.pop("asset_indexes", None):
|
|
757
687
|
warnings.warn(
|
|
758
|
-
"
|
|
759
|
-
|
|
688
|
+
"`asset_indexes` parameter is deprecated in `tile` method and will be ignored.",
|
|
689
|
+
DeprecationWarning,
|
|
760
690
|
)
|
|
761
691
|
|
|
762
|
-
|
|
763
|
-
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
764
|
-
|
|
692
|
+
assets = cast_to_sequence(assets)
|
|
765
693
|
if not assets and self.default_assets:
|
|
766
694
|
warnings.warn(
|
|
767
|
-
f"No assets
|
|
695
|
+
f"No assets passed, defaults to {self.default_assets}",
|
|
768
696
|
UserWarning,
|
|
769
697
|
)
|
|
770
698
|
assets = self.default_assets
|
|
771
699
|
|
|
772
700
|
if not assets:
|
|
773
701
|
raise MissingAssets(
|
|
774
|
-
"
|
|
702
|
+
"No Asset defined by `assets` option or class-level `default_assets`."
|
|
775
703
|
)
|
|
776
704
|
|
|
777
|
-
asset_indexes = asset_indexes or {}
|
|
778
|
-
|
|
779
|
-
# We fall back to `indexes` if provided
|
|
780
|
-
indexes = kwargs.pop("indexes", None)
|
|
781
|
-
|
|
782
705
|
def _reader(asset: str, **kwargs: Any) -> ImageData:
|
|
783
|
-
idx = asset_indexes.get(asset) or indexes
|
|
784
|
-
|
|
785
706
|
asset_info = self._get_asset_info(asset)
|
|
786
|
-
|
|
707
|
+
asset_name = asset_info["name"]
|
|
708
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
787
709
|
|
|
710
|
+
options = {**self.reader_options, **reader_options}
|
|
788
711
|
with self.ctx(**asset_info.get("env", {})):
|
|
789
|
-
with reader(
|
|
790
|
-
asset_info["
|
|
791
|
-
|
|
792
|
-
**{**self.reader_options, **options},
|
|
793
|
-
) as src:
|
|
794
|
-
data = src.preview(indexes=idx, **kwargs)
|
|
712
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
713
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
714
|
+
data = src.preview(**method_options)
|
|
795
715
|
|
|
796
716
|
self._update_statistics(
|
|
797
717
|
data,
|
|
798
|
-
indexes=idx,
|
|
799
718
|
statistics=asset_info.get("dataset_statistics"),
|
|
800
719
|
)
|
|
801
720
|
|
|
802
721
|
metadata = data.metadata or {}
|
|
803
722
|
if m := asset_info.get("metadata"):
|
|
804
723
|
metadata.update(m)
|
|
805
|
-
data.metadata = {
|
|
724
|
+
data.metadata = {asset_name: metadata}
|
|
806
725
|
|
|
726
|
+
data.band_descriptions = [
|
|
727
|
+
f"{asset_name}_{n}" for n in data.band_descriptions
|
|
728
|
+
]
|
|
807
729
|
if asset_as_band:
|
|
808
730
|
if len(data.band_names) > 1:
|
|
809
731
|
raise AssetAsBandError(
|
|
810
732
|
"Can't use `asset_as_band` for multibands asset"
|
|
811
733
|
)
|
|
812
|
-
data.
|
|
813
|
-
data.band_descriptions = [asset]
|
|
814
|
-
else:
|
|
815
|
-
data.band_names = [f"{asset}_{n}" for n in data.band_names]
|
|
816
|
-
data.band_descriptions = [
|
|
817
|
-
f"{asset}_{n}" for n in data.band_descriptions
|
|
818
|
-
]
|
|
734
|
+
data.band_descriptions = [asset_name]
|
|
819
735
|
|
|
820
736
|
return data
|
|
821
737
|
|
|
822
738
|
img = multi_arrays(assets, _reader, **kwargs)
|
|
739
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
823
740
|
if expression:
|
|
824
741
|
return img.apply_expression(expression)
|
|
825
742
|
|
|
@@ -829,9 +746,8 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
829
746
|
self,
|
|
830
747
|
lon: float,
|
|
831
748
|
lat: float,
|
|
832
|
-
assets:
|
|
833
|
-
expression:
|
|
834
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
749
|
+
assets: Sequence[str] | str | None = None,
|
|
750
|
+
expression: str | None = None,
|
|
835
751
|
asset_as_band: bool = False,
|
|
836
752
|
**kwargs: Any,
|
|
837
753
|
) -> PointData:
|
|
@@ -841,76 +757,63 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
841
757
|
lon (float): Longitude.
|
|
842
758
|
lat (float): Latitude.
|
|
843
759
|
assets (sequence of str or str, optional): assets to fetch info from.
|
|
844
|
-
expression (str, optional): rio-tiler expression
|
|
845
|
-
|
|
760
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
761
|
+
asset_as_band (bool, optional): treat each asset as a separate band. Defaults to False.
|
|
846
762
|
kwargs (optional): Options to forward to the `self.reader.point` method.
|
|
847
763
|
|
|
848
764
|
Returns:
|
|
849
765
|
PointData
|
|
850
766
|
|
|
851
767
|
"""
|
|
852
|
-
|
|
853
|
-
if assets and expression:
|
|
768
|
+
if kwargs.pop("asset_indexes", None):
|
|
854
769
|
warnings.warn(
|
|
855
|
-
"
|
|
856
|
-
|
|
770
|
+
"`asset_indexes` parameter is deprecated in `tile` method and will be ignored.",
|
|
771
|
+
DeprecationWarning,
|
|
857
772
|
)
|
|
858
773
|
|
|
859
|
-
|
|
860
|
-
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
861
|
-
|
|
774
|
+
assets = cast_to_sequence(assets)
|
|
862
775
|
if not assets and self.default_assets:
|
|
863
776
|
warnings.warn(
|
|
864
|
-
f"No assets
|
|
777
|
+
f"No assets passed, defaults to {self.default_assets}",
|
|
865
778
|
UserWarning,
|
|
866
779
|
)
|
|
867
780
|
assets = self.default_assets
|
|
868
781
|
|
|
869
782
|
if not assets:
|
|
870
783
|
raise MissingAssets(
|
|
871
|
-
"
|
|
784
|
+
"No Asset defined by `assets` option or class-level `default_assets`."
|
|
872
785
|
)
|
|
873
786
|
|
|
874
|
-
asset_indexes = asset_indexes or {}
|
|
875
|
-
|
|
876
|
-
# We fall back to `indexes` if provided
|
|
877
|
-
indexes = kwargs.pop("indexes", None)
|
|
878
|
-
|
|
879
787
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> PointData:
|
|
880
|
-
idx = asset_indexes.get(asset) or indexes
|
|
881
|
-
|
|
882
788
|
asset_info = self._get_asset_info(asset)
|
|
883
|
-
|
|
789
|
+
asset_name = asset_info["name"]
|
|
790
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
884
791
|
|
|
792
|
+
options = {**self.reader_options, **reader_options}
|
|
885
793
|
with self.ctx(**asset_info.get("env", {})):
|
|
886
|
-
with reader(
|
|
887
|
-
asset_info["
|
|
888
|
-
|
|
889
|
-
**{**self.reader_options, **options},
|
|
890
|
-
) as src:
|
|
891
|
-
data = src.point(*args, indexes=idx, **kwargs)
|
|
794
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
795
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
796
|
+
data = src.point(*args, **method_options)
|
|
892
797
|
|
|
893
798
|
metadata = data.metadata or {}
|
|
894
799
|
if m := asset_info.get("metadata"):
|
|
895
800
|
metadata.update(m)
|
|
896
|
-
data.metadata = {
|
|
801
|
+
data.metadata = {asset_name: metadata}
|
|
897
802
|
|
|
803
|
+
data.band_descriptions = [
|
|
804
|
+
f"{asset_name}_{n}" for n in data.band_descriptions
|
|
805
|
+
]
|
|
898
806
|
if asset_as_band:
|
|
899
807
|
if len(data.band_names) > 1:
|
|
900
808
|
raise AssetAsBandError(
|
|
901
809
|
"Can't use `asset_as_band` for multibands asset"
|
|
902
810
|
)
|
|
903
|
-
data.
|
|
904
|
-
data.band_descriptions = [asset]
|
|
905
|
-
else:
|
|
906
|
-
data.band_names = [f"{asset}_{n}" for n in data.band_names]
|
|
907
|
-
data.band_descriptions = [
|
|
908
|
-
f"{asset}_{n}" for n in data.band_descriptions
|
|
909
|
-
]
|
|
811
|
+
data.band_descriptions = [asset_name]
|
|
910
812
|
|
|
911
813
|
return data
|
|
912
814
|
|
|
913
815
|
data = multi_points(assets, _reader, lon, lat, **kwargs)
|
|
816
|
+
data.band_names = [f"b{ix + 1}" for ix in range(data.count)]
|
|
914
817
|
if expression:
|
|
915
818
|
return data.apply_expression(expression)
|
|
916
819
|
|
|
@@ -918,10 +821,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
918
821
|
|
|
919
822
|
def feature(
|
|
920
823
|
self,
|
|
921
|
-
shape:
|
|
922
|
-
assets:
|
|
923
|
-
expression:
|
|
924
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
824
|
+
shape: dict,
|
|
825
|
+
assets: Sequence[str] | str | None = None,
|
|
826
|
+
expression: str | None = None,
|
|
925
827
|
asset_as_band: bool = False,
|
|
926
828
|
**kwargs: Any,
|
|
927
829
|
) -> ImageData:
|
|
@@ -930,24 +832,21 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
930
832
|
Args:
|
|
931
833
|
shape (dict): Valid GeoJSON feature.
|
|
932
834
|
assets (sequence of str or str, optional): assets to fetch info from.
|
|
933
|
-
expression (str, optional): rio-tiler expression
|
|
934
|
-
|
|
835
|
+
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
836
|
+
asset_as_band (bool, optional): treat each asset as a separate band. Defaults to False.
|
|
935
837
|
kwargs (optional): Options to forward to the `self.reader.feature` method.
|
|
936
838
|
|
|
937
839
|
Returns:
|
|
938
840
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
939
841
|
|
|
940
842
|
"""
|
|
941
|
-
|
|
942
|
-
if assets and expression:
|
|
843
|
+
if kwargs.pop("asset_indexes", None):
|
|
943
844
|
warnings.warn(
|
|
944
|
-
"
|
|
945
|
-
|
|
845
|
+
"`asset_indexes` parameter is deprecated in `tile` method and will be ignored.",
|
|
846
|
+
DeprecationWarning,
|
|
946
847
|
)
|
|
947
848
|
|
|
948
|
-
|
|
949
|
-
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
950
|
-
|
|
849
|
+
assets = cast_to_sequence(assets)
|
|
951
850
|
if not assets and self.default_assets:
|
|
952
851
|
warnings.warn(
|
|
953
852
|
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
@@ -957,55 +856,44 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
957
856
|
|
|
958
857
|
if not assets:
|
|
959
858
|
raise MissingAssets(
|
|
960
|
-
"
|
|
859
|
+
"No Asset defined by `assets` option or class-level `default_assets`."
|
|
961
860
|
)
|
|
962
861
|
|
|
963
|
-
asset_indexes = asset_indexes or {}
|
|
964
|
-
|
|
965
|
-
# We fall back to `indexes` if provided
|
|
966
|
-
indexes = kwargs.pop("indexes", None)
|
|
967
|
-
|
|
968
862
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
969
|
-
idx = asset_indexes.get(asset) or indexes
|
|
970
|
-
|
|
971
863
|
asset_info = self._get_asset_info(asset)
|
|
972
|
-
|
|
864
|
+
asset_name = asset_info["name"]
|
|
865
|
+
reader, reader_options = self._get_reader(asset_info)
|
|
973
866
|
|
|
867
|
+
options = {**self.reader_options, **reader_options}
|
|
974
868
|
with self.ctx(**asset_info.get("env", {})):
|
|
975
|
-
with reader(
|
|
976
|
-
asset_info["
|
|
977
|
-
|
|
978
|
-
**{**self.reader_options, **options},
|
|
979
|
-
) as src:
|
|
980
|
-
data = src.feature(*args, indexes=idx, **kwargs)
|
|
869
|
+
with reader(asset_info["url"], tms=self.tms, **options) as src:
|
|
870
|
+
method_options = {**asset_info["method_options"], **kwargs}
|
|
871
|
+
data = src.feature(*args, **method_options)
|
|
981
872
|
|
|
982
873
|
self._update_statistics(
|
|
983
874
|
data,
|
|
984
|
-
indexes=idx,
|
|
985
875
|
statistics=asset_info.get("dataset_statistics"),
|
|
986
876
|
)
|
|
987
877
|
|
|
988
878
|
metadata = data.metadata or {}
|
|
989
879
|
if m := asset_info.get("metadata"):
|
|
990
880
|
metadata.update(m)
|
|
991
|
-
data.metadata = {
|
|
881
|
+
data.metadata = {asset_name: metadata}
|
|
992
882
|
|
|
883
|
+
data.band_descriptions = [
|
|
884
|
+
f"{asset_name}_{n}" for n in data.band_descriptions
|
|
885
|
+
]
|
|
993
886
|
if asset_as_band:
|
|
994
887
|
if len(data.band_names) > 1:
|
|
995
888
|
raise AssetAsBandError(
|
|
996
889
|
"Can't use `asset_as_band` for multibands asset"
|
|
997
890
|
)
|
|
998
|
-
data.
|
|
999
|
-
data.band_descriptions = [asset]
|
|
1000
|
-
else:
|
|
1001
|
-
data.band_names = [f"{asset}_{n}" for n in data.band_names]
|
|
1002
|
-
data.band_descriptions = [
|
|
1003
|
-
f"{asset}_{n}" for n in data.band_descriptions
|
|
1004
|
-
]
|
|
891
|
+
data.band_descriptions = [asset_name]
|
|
1005
892
|
|
|
1006
893
|
return data
|
|
1007
894
|
|
|
1008
895
|
img = multi_arrays(assets, _reader, shape, **kwargs)
|
|
896
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
1009
897
|
if expression:
|
|
1010
898
|
return img.apply_expression(expression)
|
|
1011
899
|
|
|
@@ -1030,14 +918,22 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1030
918
|
input: Any = attr.ib()
|
|
1031
919
|
tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
|
|
1032
920
|
|
|
1033
|
-
minzoom: int = attr.ib(default=None)
|
|
1034
|
-
maxzoom: int = attr.ib(default=None)
|
|
921
|
+
minzoom: int | None = attr.ib(default=None)
|
|
922
|
+
maxzoom: int | None = attr.ib(default=None)
|
|
1035
923
|
|
|
1036
|
-
reader:
|
|
1037
|
-
reader_options:
|
|
924
|
+
reader: type[BaseReader] = attr.ib(init=False)
|
|
925
|
+
reader_options: dict = attr.ib(factory=dict)
|
|
1038
926
|
|
|
1039
927
|
bands: Sequence[str] = attr.ib(init=False)
|
|
1040
|
-
default_bands:
|
|
928
|
+
default_bands: Sequence[str] | None = attr.ib(init=False, default=None)
|
|
929
|
+
|
|
930
|
+
def __attrs_post_init__(self):
|
|
931
|
+
"""deprecation warning."""
|
|
932
|
+
warnings.warn(
|
|
933
|
+
"MultiBandReader is deprecated and will be removed in a future release. "
|
|
934
|
+
"Please use MultiBaseReader instead.",
|
|
935
|
+
DeprecationWarning,
|
|
936
|
+
)
|
|
1041
937
|
|
|
1042
938
|
def __enter__(self):
|
|
1043
939
|
"""Support using with Context Managers."""
|
|
@@ -1052,7 +948,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1052
948
|
"""Validate band name and construct url."""
|
|
1053
949
|
...
|
|
1054
950
|
|
|
1055
|
-
def parse_expression(self, expression: str) ->
|
|
951
|
+
def parse_expression(self, expression: str) -> tuple:
|
|
1056
952
|
"""Parse rio-tiler band math expression."""
|
|
1057
953
|
input_bands = "|".join([rf"\b{band}\b" for band in self.bands])
|
|
1058
954
|
_re = re.compile(input_bands.replace("\\\\", "\\"))
|
|
@@ -1065,9 +961,16 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1065
961
|
|
|
1066
962
|
return bands
|
|
1067
963
|
|
|
964
|
+
def _expression_to_bidx(self, bands: Sequence[str], expression: str) -> str:
|
|
965
|
+
mapexpr = {b: f"b{idx + 1}" for idx, b in enumerate(bands)}
|
|
966
|
+
for b in bands:
|
|
967
|
+
_re = re.compile(rf"\b{b}\b")
|
|
968
|
+
expression = _re.sub(mapexpr[b], expression)
|
|
969
|
+
return expression
|
|
970
|
+
|
|
1068
971
|
def info(
|
|
1069
972
|
self,
|
|
1070
|
-
bands:
|
|
973
|
+
bands: Sequence[str] | str | None = None,
|
|
1071
974
|
**kwargs: Any,
|
|
1072
975
|
) -> Info:
|
|
1073
976
|
"""Return metadata from multiple bands.
|
|
@@ -1089,11 +992,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1089
992
|
|
|
1090
993
|
def _reader(band: str, **kwargs: Any) -> Info:
|
|
1091
994
|
url = self._get_band_url(band)
|
|
1092
|
-
with self.reader(
|
|
1093
|
-
url,
|
|
1094
|
-
tms=self.tms,
|
|
1095
|
-
**self.reader_options,
|
|
1096
|
-
) as src:
|
|
995
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1097
996
|
return src.info()
|
|
1098
997
|
|
|
1099
998
|
bands_metadata = multi_values(bands, _reader, **kwargs)
|
|
@@ -1121,15 +1020,15 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1121
1020
|
|
|
1122
1021
|
def statistics(
|
|
1123
1022
|
self,
|
|
1124
|
-
bands:
|
|
1125
|
-
expression:
|
|
1023
|
+
bands: Sequence[str] | str | None = None,
|
|
1024
|
+
expression: str | None = None,
|
|
1126
1025
|
categorical: bool = False,
|
|
1127
|
-
categories:
|
|
1128
|
-
percentiles:
|
|
1129
|
-
hist_options:
|
|
1026
|
+
categories: list[float] | None = None,
|
|
1027
|
+
percentiles: list[int] | None = None,
|
|
1028
|
+
hist_options: dict | None = None,
|
|
1130
1029
|
max_size: int = 1024,
|
|
1131
1030
|
**kwargs: Any,
|
|
1132
|
-
) ->
|
|
1031
|
+
) -> dict[str, BandStatistics]:
|
|
1133
1032
|
"""Return array statistics for multiple assets.
|
|
1134
1033
|
|
|
1135
1034
|
Args:
|
|
@@ -1172,8 +1071,8 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1172
1071
|
tile_x: int,
|
|
1173
1072
|
tile_y: int,
|
|
1174
1073
|
tile_z: int,
|
|
1175
|
-
bands:
|
|
1176
|
-
expression:
|
|
1074
|
+
bands: Sequence[str] | str | None = None,
|
|
1075
|
+
expression: str | None = None,
|
|
1177
1076
|
**kwargs: Any,
|
|
1178
1077
|
) -> ImageData:
|
|
1179
1078
|
"""Read and merge Web Map tiles multiple bands.
|
|
@@ -1219,24 +1118,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1219
1118
|
|
|
1220
1119
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1221
1120
|
url = self._get_band_url(band)
|
|
1222
|
-
with self.reader(
|
|
1223
|
-
url,
|
|
1224
|
-
tms=self.tms,
|
|
1225
|
-
**self.reader_options,
|
|
1226
|
-
) as src:
|
|
1121
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1227
1122
|
data = src.tile(*args, **kwargs)
|
|
1228
|
-
|
|
1229
1123
|
if data.metadata:
|
|
1230
1124
|
data.metadata = {band: data.metadata}
|
|
1231
1125
|
|
|
1232
|
-
# use `band` as name instead of band index
|
|
1233
|
-
data.
|
|
1234
|
-
|
|
1126
|
+
# use `band` as name/description instead of band index
|
|
1127
|
+
data.band_descriptions = [band]
|
|
1235
1128
|
return data
|
|
1236
1129
|
|
|
1237
1130
|
img = multi_arrays(bands, _reader, tile_x, tile_y, tile_z, **kwargs)
|
|
1238
|
-
|
|
1131
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
1239
1132
|
if expression:
|
|
1133
|
+
expression = self._expression_to_bidx(img.band_descriptions, expression)
|
|
1240
1134
|
return img.apply_expression(expression)
|
|
1241
1135
|
|
|
1242
1136
|
return img
|
|
@@ -1244,8 +1138,8 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1244
1138
|
def part(
|
|
1245
1139
|
self,
|
|
1246
1140
|
bbox: BBox,
|
|
1247
|
-
bands:
|
|
1248
|
-
expression:
|
|
1141
|
+
bands: Sequence[str] | str | None = None,
|
|
1142
|
+
expression: str | None = None,
|
|
1249
1143
|
**kwargs: Any,
|
|
1250
1144
|
) -> ImageData:
|
|
1251
1145
|
"""Read and merge parts from multiple bands.
|
|
@@ -1284,32 +1178,27 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1284
1178
|
|
|
1285
1179
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1286
1180
|
url = self._get_band_url(band)
|
|
1287
|
-
with self.reader(
|
|
1288
|
-
url,
|
|
1289
|
-
tms=self.tms,
|
|
1290
|
-
**self.reader_options,
|
|
1291
|
-
) as src:
|
|
1181
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1292
1182
|
data = src.part(*args, **kwargs)
|
|
1293
|
-
|
|
1294
1183
|
if data.metadata:
|
|
1295
1184
|
data.metadata = {band: data.metadata}
|
|
1296
1185
|
|
|
1297
|
-
# use `band` as name instead of band index
|
|
1298
|
-
data.
|
|
1299
|
-
|
|
1186
|
+
# use `band` as name/description instead of band index
|
|
1187
|
+
data.band_descriptions = [band]
|
|
1300
1188
|
return data
|
|
1301
1189
|
|
|
1302
1190
|
img = multi_arrays(bands, _reader, bbox, **kwargs)
|
|
1303
|
-
|
|
1191
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
1304
1192
|
if expression:
|
|
1193
|
+
expression = self._expression_to_bidx(img.band_descriptions, expression)
|
|
1305
1194
|
return img.apply_expression(expression)
|
|
1306
1195
|
|
|
1307
1196
|
return img
|
|
1308
1197
|
|
|
1309
1198
|
def preview(
|
|
1310
1199
|
self,
|
|
1311
|
-
bands:
|
|
1312
|
-
expression:
|
|
1200
|
+
bands: Sequence[str] | str | None = None,
|
|
1201
|
+
expression: str | None = None,
|
|
1313
1202
|
**kwargs: Any,
|
|
1314
1203
|
) -> ImageData:
|
|
1315
1204
|
"""Read and merge previews from multiple bands.
|
|
@@ -1347,24 +1236,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1347
1236
|
|
|
1348
1237
|
def _reader(band: str, **kwargs: Any) -> ImageData:
|
|
1349
1238
|
url = self._get_band_url(band)
|
|
1350
|
-
with self.reader(
|
|
1351
|
-
url,
|
|
1352
|
-
tms=self.tms,
|
|
1353
|
-
**self.reader_options,
|
|
1354
|
-
) as src:
|
|
1239
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1355
1240
|
data = src.preview(**kwargs)
|
|
1356
|
-
|
|
1357
1241
|
if data.metadata:
|
|
1358
1242
|
data.metadata = {band: data.metadata}
|
|
1359
1243
|
|
|
1360
|
-
# use `band` as name instead of band index
|
|
1361
|
-
data.
|
|
1362
|
-
|
|
1244
|
+
# use `band` as name/description instead of band index
|
|
1245
|
+
data.band_descriptions = [band]
|
|
1363
1246
|
return data
|
|
1364
1247
|
|
|
1365
1248
|
img = multi_arrays(bands, _reader, **kwargs)
|
|
1366
|
-
|
|
1249
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
1367
1250
|
if expression:
|
|
1251
|
+
expression = self._expression_to_bidx(img.band_descriptions, expression)
|
|
1368
1252
|
return img.apply_expression(expression)
|
|
1369
1253
|
|
|
1370
1254
|
return img
|
|
@@ -1373,8 +1257,8 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1373
1257
|
self,
|
|
1374
1258
|
lon: float,
|
|
1375
1259
|
lat: float,
|
|
1376
|
-
bands:
|
|
1377
|
-
expression:
|
|
1260
|
+
bands: Sequence[str] | str | None = None,
|
|
1261
|
+
expression: str | None = None,
|
|
1378
1262
|
**kwargs: Any,
|
|
1379
1263
|
) -> PointData:
|
|
1380
1264
|
"""Read a pixel values from multiple bands.
|
|
@@ -1414,32 +1298,28 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1414
1298
|
|
|
1415
1299
|
def _reader(band: str, *args: Any, **kwargs: Any) -> PointData:
|
|
1416
1300
|
url = self._get_band_url(band)
|
|
1417
|
-
with self.reader(
|
|
1418
|
-
url,
|
|
1419
|
-
tms=self.tms,
|
|
1420
|
-
**self.reader_options,
|
|
1421
|
-
) as src:
|
|
1301
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1422
1302
|
data = src.point(*args, **kwargs)
|
|
1423
|
-
|
|
1424
1303
|
if data.metadata:
|
|
1425
1304
|
data.metadata = {band: data.metadata}
|
|
1426
1305
|
|
|
1427
|
-
# use `band` as name instead of band index
|
|
1428
|
-
data.
|
|
1429
|
-
|
|
1306
|
+
# use `band` as name/description instead of band index
|
|
1307
|
+
data.band_descriptions = [band]
|
|
1430
1308
|
return data
|
|
1431
1309
|
|
|
1432
1310
|
data = multi_points(bands, _reader, lon, lat, **kwargs)
|
|
1311
|
+
data.band_names = [f"b{ix + 1}" for ix in range(data.count)]
|
|
1433
1312
|
if expression:
|
|
1313
|
+
expression = self._expression_to_bidx(data.band_descriptions, expression)
|
|
1434
1314
|
return data.apply_expression(expression)
|
|
1435
1315
|
|
|
1436
1316
|
return data
|
|
1437
1317
|
|
|
1438
1318
|
def feature(
|
|
1439
1319
|
self,
|
|
1440
|
-
shape:
|
|
1441
|
-
bands:
|
|
1442
|
-
expression:
|
|
1320
|
+
shape: dict,
|
|
1321
|
+
bands: Sequence[str] | str | None = None,
|
|
1322
|
+
expression: str | None = None,
|
|
1443
1323
|
**kwargs: Any,
|
|
1444
1324
|
) -> ImageData:
|
|
1445
1325
|
"""Read and merge parts defined by geojson feature from multiple bands.
|
|
@@ -1478,24 +1358,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1478
1358
|
|
|
1479
1359
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1480
1360
|
url = self._get_band_url(band)
|
|
1481
|
-
with self.reader(
|
|
1482
|
-
url,
|
|
1483
|
-
tms=self.tms,
|
|
1484
|
-
**self.reader_options,
|
|
1485
|
-
) as src:
|
|
1361
|
+
with self.reader(url, tms=self.tms, **self.reader_options) as src:
|
|
1486
1362
|
data = src.feature(*args, **kwargs)
|
|
1487
|
-
|
|
1488
1363
|
if data.metadata:
|
|
1489
1364
|
data.metadata = {band: data.metadata}
|
|
1490
1365
|
|
|
1491
|
-
# use `band` as name instead of band index
|
|
1492
|
-
data.
|
|
1493
|
-
|
|
1366
|
+
# use `band` as name/description instead of band index
|
|
1367
|
+
data.band_descriptions = [band]
|
|
1494
1368
|
return data
|
|
1495
1369
|
|
|
1496
1370
|
img = multi_arrays(bands, _reader, shape, **kwargs)
|
|
1497
|
-
|
|
1371
|
+
img.band_names = [f"b{ix + 1}" for ix in range(img.count)]
|
|
1498
1372
|
if expression:
|
|
1373
|
+
expression = self._expression_to_bidx(img.band_descriptions, expression)
|
|
1499
1374
|
return img.apply_expression(expression)
|
|
1500
1375
|
|
|
1501
1376
|
return img
|