rio-tiler 6.8.0__py3-none-any.whl → 7.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 +54 -18
- rio_tiler/io/base.py +330 -131
- rio_tiler/io/rasterio.py +36 -102
- rio_tiler/io/stac.py +35 -19
- rio_tiler/io/xarray.py +14 -115
- rio_tiler/models.py +16 -65
- rio_tiler/reader.py +3 -4
- rio_tiler/types.py +3 -2
- rio_tiler/utils.py +36 -12
- {rio_tiler-6.8.0.dist-info → rio_tiler-7.0.0.dist-info}/METADATA +13 -10
- {rio_tiler-6.8.0.dist-info → rio_tiler-7.0.0.dist-info}/RECORD +15 -15
- {rio_tiler-6.8.0.dist-info → rio_tiler-7.0.0.dist-info}/WHEEL +0 -0
- {rio_tiler-6.8.0.dist-info → rio_tiler-7.0.0.dist-info}/licenses/AUTHORS.txt +0 -0
- {rio_tiler-6.8.0.dist-info → rio_tiler-7.0.0.dist-info}/licenses/LICENSE +0 -0
rio_tiler/io/base.py
CHANGED
|
@@ -9,11 +9,13 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, Union
|
|
|
9
9
|
|
|
10
10
|
import attr
|
|
11
11
|
import numpy
|
|
12
|
+
from affine import Affine
|
|
12
13
|
from morecantile import Tile, TileMatrixSet
|
|
13
14
|
from rasterio.crs import CRS
|
|
14
|
-
from rasterio.
|
|
15
|
+
from rasterio.rio.overview import get_maximum_overview_level
|
|
16
|
+
from rasterio.warp import calculate_default_transform, transform_bounds
|
|
15
17
|
|
|
16
|
-
from rio_tiler.constants import WEB_MERCATOR_TMS
|
|
18
|
+
from rio_tiler.constants import WEB_MERCATOR_TMS
|
|
17
19
|
from rio_tiler.errors import (
|
|
18
20
|
AssetAsBandError,
|
|
19
21
|
ExpressionMixingWarning,
|
|
@@ -25,7 +27,7 @@ from rio_tiler.errors import (
|
|
|
25
27
|
from rio_tiler.models import BandStatistics, ImageData, Info, PointData
|
|
26
28
|
from rio_tiler.tasks import multi_arrays, multi_points, multi_values
|
|
27
29
|
from rio_tiler.types import AssetInfo, BBox, Indexes
|
|
28
|
-
from rio_tiler.utils import normalize_bounds
|
|
30
|
+
from rio_tiler.utils import CRS_to_uri, cast_to_sequence, normalize_bounds
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
@attr.s
|
|
@@ -42,12 +44,13 @@ class SpatialMixin:
|
|
|
42
44
|
bounds: BBox = attr.ib(init=False)
|
|
43
45
|
crs: CRS = attr.ib(init=False)
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
transform: Optional[Affine] = attr.ib(default=None, init=False)
|
|
48
|
+
height: Optional[int] = attr.ib(default=None, init=False)
|
|
49
|
+
width: Optional[int] = attr.ib(default=None, init=False)
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if self.crs == self.geographic_crs:
|
|
51
|
+
def get_geographic_bounds(self, crs: CRS) -> BBox:
|
|
52
|
+
"""Return Geographic Bounds for a Geographic CRS."""
|
|
53
|
+
if self.crs == crs:
|
|
51
54
|
if self.bounds[1] > self.bounds[3]:
|
|
52
55
|
warnings.warn(
|
|
53
56
|
"BoundingBox of the dataset is inverted (minLat > maxLat).",
|
|
@@ -63,12 +66,7 @@ class SpatialMixin:
|
|
|
63
66
|
return self.bounds
|
|
64
67
|
|
|
65
68
|
try:
|
|
66
|
-
bounds = transform_bounds(
|
|
67
|
-
self.crs,
|
|
68
|
-
self.geographic_crs,
|
|
69
|
-
*self.bounds,
|
|
70
|
-
densify_pts=21,
|
|
71
|
-
)
|
|
69
|
+
bounds = transform_bounds(self.crs, crs, *self.bounds, densify_pts=21)
|
|
72
70
|
except: # noqa
|
|
73
71
|
warnings.warn(
|
|
74
72
|
"Cannot determine bounds in geographic CRS, will default to (-180.0, -90.0, 180.0, 90.0).",
|
|
@@ -85,6 +83,77 @@ class SpatialMixin:
|
|
|
85
83
|
|
|
86
84
|
return bounds
|
|
87
85
|
|
|
86
|
+
@cached_property
|
|
87
|
+
def _dst_geom_in_tms_crs(self):
|
|
88
|
+
"""Return dataset geom info in TMS projection."""
|
|
89
|
+
tms_crs = self.tms.rasterio_crs
|
|
90
|
+
if self.crs != tms_crs:
|
|
91
|
+
dst_affine, w, h = calculate_default_transform(
|
|
92
|
+
self.crs,
|
|
93
|
+
tms_crs,
|
|
94
|
+
self.width,
|
|
95
|
+
self.height,
|
|
96
|
+
*self.bounds,
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
dst_affine = list(self.transform)
|
|
100
|
+
w = self.width
|
|
101
|
+
h = self.height
|
|
102
|
+
|
|
103
|
+
return dst_affine, w, h
|
|
104
|
+
|
|
105
|
+
@cached_property
|
|
106
|
+
def _minzoom(self) -> int:
|
|
107
|
+
"""Calculate dataset minimum zoom level."""
|
|
108
|
+
# We assume the TMS tilesize to be constant over all matrices
|
|
109
|
+
# ref: https://github.com/OSGeo/gdal/blob/dc38aa64d779ecc45e3cd15b1817b83216cf96b8/gdal/frmts/gtiff/cogdriver.cpp#L274
|
|
110
|
+
tilesize = self.tms.tileMatrices[0].tileWidth
|
|
111
|
+
|
|
112
|
+
if all([self.transform, self.height, self.width]):
|
|
113
|
+
try:
|
|
114
|
+
dst_affine, w, h = self._dst_geom_in_tms_crs
|
|
115
|
+
|
|
116
|
+
# The minzoom is defined by the resolution of the maximum theoretical overview level
|
|
117
|
+
# We assume `tilesize`` is the smallest overview size
|
|
118
|
+
overview_level = get_maximum_overview_level(w, h, minsize=tilesize)
|
|
119
|
+
|
|
120
|
+
# Get the resolution of the overview
|
|
121
|
+
resolution = max(abs(dst_affine[0]), abs(dst_affine[4]))
|
|
122
|
+
ovr_resolution = resolution * (2**overview_level)
|
|
123
|
+
|
|
124
|
+
# Find what TMS matrix match the overview resolution
|
|
125
|
+
return self.tms.zoom_for_res(ovr_resolution)
|
|
126
|
+
|
|
127
|
+
except: # noqa
|
|
128
|
+
# if we can't get max zoom from the dataset we default to TMS maxzoom
|
|
129
|
+
warnings.warn(
|
|
130
|
+
"Cannot determine minzoom based on dataset information, will default to TMS minzoom.",
|
|
131
|
+
UserWarning,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
return self.tms.minzoom
|
|
135
|
+
|
|
136
|
+
@cached_property
|
|
137
|
+
def _maxzoom(self) -> int:
|
|
138
|
+
"""Calculate dataset maximum zoom level."""
|
|
139
|
+
if all([self.transform, self.height, self.width]):
|
|
140
|
+
try:
|
|
141
|
+
dst_affine, _, _ = self._dst_geom_in_tms_crs
|
|
142
|
+
|
|
143
|
+
# The maxzoom is defined by finding the minimum difference between
|
|
144
|
+
# the raster resolution and the zoom level resolution
|
|
145
|
+
resolution = max(abs(dst_affine[0]), abs(dst_affine[4]))
|
|
146
|
+
return self.tms.zoom_for_res(resolution)
|
|
147
|
+
|
|
148
|
+
except: # noqa
|
|
149
|
+
# if we can't get min/max zoom from the dataset we default to TMS maxzoom
|
|
150
|
+
warnings.warn(
|
|
151
|
+
"Cannot determine maxzoom based on dataset information, will default to TMS maxzoom.",
|
|
152
|
+
UserWarning,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return self.tms.maxzoom
|
|
156
|
+
|
|
88
157
|
def tile_exists(self, tile_x: int, tile_y: int, tile_z: int) -> bool:
|
|
89
158
|
"""Check if a tile intersects the dataset bounds.
|
|
90
159
|
|
|
@@ -98,7 +167,7 @@ class SpatialMixin:
|
|
|
98
167
|
|
|
99
168
|
"""
|
|
100
169
|
# bounds in TileMatrixSet's CRS
|
|
101
|
-
tile_bounds = self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z))
|
|
170
|
+
tile_bounds = tuple(self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z)))
|
|
102
171
|
|
|
103
172
|
if not self.tms.rasterio_crs == self.crs:
|
|
104
173
|
# Transform the bounds to the dataset's CRS
|
|
@@ -267,8 +336,11 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
267
336
|
reader_options: Dict = attr.ib(factory=dict)
|
|
268
337
|
|
|
269
338
|
assets: Sequence[str] = attr.ib(init=False)
|
|
339
|
+
default_assets: Optional[Sequence[str]] = attr.ib(init=False, default=None)
|
|
270
340
|
|
|
271
|
-
ctx:
|
|
341
|
+
ctx: Type[contextlib.AbstractContextManager] = attr.ib(
|
|
342
|
+
init=False, default=contextlib.nullcontext
|
|
343
|
+
)
|
|
272
344
|
|
|
273
345
|
def __enter__(self):
|
|
274
346
|
"""Support using with Context Managers."""
|
|
@@ -283,6 +355,10 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
283
355
|
"""Validate asset name and construct url."""
|
|
284
356
|
...
|
|
285
357
|
|
|
358
|
+
def _get_reader(self, asset_info: AssetInfo) -> Tuple[Type[BaseReader], Dict]:
|
|
359
|
+
"""Get Asset Reader and options."""
|
|
360
|
+
return self.reader, {}
|
|
361
|
+
|
|
286
362
|
def parse_expression(self, expression: str, asset_as_band: bool = False) -> Tuple:
|
|
287
363
|
"""Parse rio-tiler band math expression."""
|
|
288
364
|
input_assets = "|".join(self.assets)
|
|
@@ -309,8 +385,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
309
385
|
statistics: Optional[Sequence[Tuple[float, float]]] = None,
|
|
310
386
|
):
|
|
311
387
|
"""Update ImageData Statistics from AssetInfo."""
|
|
312
|
-
|
|
313
|
-
indexes = (indexes,)
|
|
388
|
+
indexes = cast_to_sequence(indexes)
|
|
314
389
|
|
|
315
390
|
if indexes is None:
|
|
316
391
|
indexes = tuple(range(1, img.count + 1))
|
|
@@ -322,7 +397,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
322
397
|
img.dataset_statistics = [statistics[bidx - 1] for bidx in indexes]
|
|
323
398
|
|
|
324
399
|
def info(
|
|
325
|
-
self,
|
|
400
|
+
self,
|
|
401
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
402
|
+
**kwargs: Any,
|
|
326
403
|
) -> Dict[str, Info]:
|
|
327
404
|
"""Return metadata from multiple assets.
|
|
328
405
|
|
|
@@ -338,26 +415,27 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
338
415
|
"No `assets` option passed, will fetch info for all available assets.",
|
|
339
416
|
UserWarning,
|
|
340
417
|
)
|
|
341
|
-
|
|
342
|
-
assets = assets or self.assets
|
|
343
|
-
|
|
344
|
-
if isinstance(assets, str):
|
|
345
|
-
assets = (assets,)
|
|
418
|
+
assets = cast_to_sequence(assets or self.assets)
|
|
346
419
|
|
|
347
420
|
def _reader(asset: str, **kwargs: Any) -> Dict:
|
|
348
421
|
asset_info = self._get_asset_info(asset)
|
|
349
|
-
|
|
422
|
+
reader, options = self._get_reader(asset_info)
|
|
423
|
+
|
|
350
424
|
with self.ctx(**asset_info.get("env", {})):
|
|
351
|
-
with
|
|
425
|
+
with reader(
|
|
426
|
+
asset_info["url"],
|
|
427
|
+
tms=self.tms,
|
|
428
|
+
**{**self.reader_options, **options},
|
|
429
|
+
) as src:
|
|
352
430
|
return src.info()
|
|
353
431
|
|
|
354
432
|
return multi_values(assets, _reader, **kwargs)
|
|
355
433
|
|
|
356
434
|
def statistics(
|
|
357
435
|
self,
|
|
358
|
-
assets: Union[Sequence[str], str] = None,
|
|
359
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
360
|
-
asset_expression: Optional[Dict[str, str]] = None,
|
|
436
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
437
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
438
|
+
asset_expression: Optional[Dict[str, str]] = None,
|
|
361
439
|
**kwargs: Any,
|
|
362
440
|
) -> Dict[str, Dict[str, BandStatistics]]:
|
|
363
441
|
"""Return array statistics for multiple assets.
|
|
@@ -378,23 +456,24 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
378
456
|
UserWarning,
|
|
379
457
|
)
|
|
380
458
|
|
|
381
|
-
assets = assets or self.assets
|
|
382
|
-
|
|
383
|
-
if isinstance(assets, str):
|
|
384
|
-
assets = (assets,)
|
|
385
|
-
|
|
459
|
+
assets = cast_to_sequence(assets or self.assets)
|
|
386
460
|
asset_indexes = asset_indexes or {}
|
|
387
461
|
asset_expression = asset_expression or {}
|
|
388
462
|
|
|
389
|
-
def _reader(asset: str, *args, **kwargs) -> Dict:
|
|
463
|
+
def _reader(asset: str, *args: Any, **kwargs: Any) -> Dict:
|
|
390
464
|
asset_info = self._get_asset_info(asset)
|
|
391
|
-
|
|
465
|
+
reader, options = self._get_reader(asset_info)
|
|
466
|
+
|
|
392
467
|
with self.ctx(**asset_info.get("env", {})):
|
|
393
|
-
with
|
|
468
|
+
with reader(
|
|
469
|
+
asset_info["url"],
|
|
470
|
+
tms=self.tms,
|
|
471
|
+
**{**self.reader_options, **options},
|
|
472
|
+
) as src:
|
|
394
473
|
return src.statistics(
|
|
395
474
|
*args,
|
|
396
|
-
indexes=asset_indexes.get(asset, kwargs.pop("indexes", None)),
|
|
397
|
-
expression=asset_expression.get(asset),
|
|
475
|
+
indexes=asset_indexes.get(asset, kwargs.pop("indexes", None)),
|
|
476
|
+
expression=asset_expression.get(asset),
|
|
398
477
|
**kwargs,
|
|
399
478
|
)
|
|
400
479
|
|
|
@@ -402,9 +481,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
402
481
|
|
|
403
482
|
def merged_statistics(
|
|
404
483
|
self,
|
|
405
|
-
assets: Union[Sequence[str], str] = None,
|
|
484
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
406
485
|
expression: Optional[str] = None,
|
|
407
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
486
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
408
487
|
categorical: bool = False,
|
|
409
488
|
categories: Optional[List[float]] = None,
|
|
410
489
|
percentiles: Optional[List[int]] = None,
|
|
@@ -436,7 +515,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
436
515
|
"No `assets` option passed, will fetch statistics for all available assets.",
|
|
437
516
|
UserWarning,
|
|
438
517
|
)
|
|
439
|
-
assets = assets or self.assets
|
|
518
|
+
assets = cast_to_sequence(assets or self.assets)
|
|
440
519
|
|
|
441
520
|
data = self.preview(
|
|
442
521
|
assets=assets,
|
|
@@ -457,9 +536,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
457
536
|
tile_x: int,
|
|
458
537
|
tile_y: int,
|
|
459
538
|
tile_z: int,
|
|
460
|
-
assets: Union[Sequence[str], str] = None,
|
|
539
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
461
540
|
expression: Optional[str] = None,
|
|
462
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
541
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
463
542
|
asset_as_band: bool = False,
|
|
464
543
|
**kwargs: Any,
|
|
465
544
|
) -> ImageData:
|
|
@@ -483,9 +562,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
483
562
|
f"Tile(x={tile_x}, y={tile_y}, z={tile_z}) is outside bounds"
|
|
484
563
|
)
|
|
485
564
|
|
|
486
|
-
|
|
487
|
-
assets = (assets,)
|
|
488
|
-
|
|
565
|
+
assets = cast_to_sequence(assets)
|
|
489
566
|
if assets and expression:
|
|
490
567
|
warnings.warn(
|
|
491
568
|
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
@@ -495,9 +572,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
495
572
|
if expression:
|
|
496
573
|
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
497
574
|
|
|
575
|
+
if not assets and self.default_assets:
|
|
576
|
+
warnings.warn(
|
|
577
|
+
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
578
|
+
UserWarning,
|
|
579
|
+
)
|
|
580
|
+
assets = self.default_assets
|
|
581
|
+
|
|
498
582
|
if not assets:
|
|
499
583
|
raise MissingAssets(
|
|
500
|
-
"assets must be passed
|
|
584
|
+
"assets must be passed via `expression` or `assets` options, or via class-level `default_assets`."
|
|
501
585
|
)
|
|
502
586
|
|
|
503
587
|
asset_indexes = asset_indexes or {}
|
|
@@ -506,12 +590,17 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
506
590
|
indexes = kwargs.pop("indexes", None)
|
|
507
591
|
|
|
508
592
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
509
|
-
idx = asset_indexes.get(asset) or indexes
|
|
593
|
+
idx = asset_indexes.get(asset) or indexes
|
|
510
594
|
|
|
511
595
|
asset_info = self._get_asset_info(asset)
|
|
512
|
-
|
|
596
|
+
reader, options = self._get_reader(asset_info)
|
|
597
|
+
|
|
513
598
|
with self.ctx(**asset_info.get("env", {})):
|
|
514
|
-
with
|
|
599
|
+
with reader(
|
|
600
|
+
asset_info["url"],
|
|
601
|
+
tms=self.tms,
|
|
602
|
+
**{**self.reader_options, **options},
|
|
603
|
+
) as src:
|
|
515
604
|
data = src.tile(*args, indexes=idx, **kwargs)
|
|
516
605
|
|
|
517
606
|
self._update_statistics(
|
|
@@ -545,9 +634,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
545
634
|
def part(
|
|
546
635
|
self,
|
|
547
636
|
bbox: BBox,
|
|
548
|
-
assets: Union[Sequence[str], str] = None,
|
|
637
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
549
638
|
expression: Optional[str] = None,
|
|
550
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
639
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
551
640
|
asset_as_band: bool = False,
|
|
552
641
|
**kwargs: Any,
|
|
553
642
|
) -> ImageData:
|
|
@@ -564,9 +653,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
564
653
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
565
654
|
|
|
566
655
|
"""
|
|
567
|
-
|
|
568
|
-
assets = (assets,)
|
|
569
|
-
|
|
656
|
+
assets = cast_to_sequence(assets)
|
|
570
657
|
if assets and expression:
|
|
571
658
|
warnings.warn(
|
|
572
659
|
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
@@ -576,9 +663,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
576
663
|
if expression:
|
|
577
664
|
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
578
665
|
|
|
666
|
+
if not assets and self.default_assets:
|
|
667
|
+
warnings.warn(
|
|
668
|
+
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
669
|
+
UserWarning,
|
|
670
|
+
)
|
|
671
|
+
assets = self.default_assets
|
|
672
|
+
|
|
579
673
|
if not assets:
|
|
580
674
|
raise MissingAssets(
|
|
581
|
-
"assets must be passed
|
|
675
|
+
"assets must be passed via `expression` or `assets` options, or via class-level `default_assets`."
|
|
582
676
|
)
|
|
583
677
|
|
|
584
678
|
asset_indexes = asset_indexes or {}
|
|
@@ -587,12 +681,17 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
587
681
|
indexes = kwargs.pop("indexes", None)
|
|
588
682
|
|
|
589
683
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
590
|
-
idx = asset_indexes.get(asset) or indexes
|
|
684
|
+
idx = asset_indexes.get(asset) or indexes
|
|
591
685
|
|
|
592
686
|
asset_info = self._get_asset_info(asset)
|
|
593
|
-
|
|
687
|
+
reader, options = self._get_reader(asset_info)
|
|
688
|
+
|
|
594
689
|
with self.ctx(**asset_info.get("env", {})):
|
|
595
|
-
with
|
|
690
|
+
with reader(
|
|
691
|
+
asset_info["url"],
|
|
692
|
+
tms=self.tms,
|
|
693
|
+
**{**self.reader_options, **options},
|
|
694
|
+
) as src:
|
|
596
695
|
data = src.part(*args, indexes=idx, **kwargs)
|
|
597
696
|
|
|
598
697
|
self._update_statistics(
|
|
@@ -625,9 +724,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
625
724
|
|
|
626
725
|
def preview(
|
|
627
726
|
self,
|
|
628
|
-
assets: Union[Sequence[str], str] = None,
|
|
727
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
629
728
|
expression: Optional[str] = None,
|
|
630
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
729
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
631
730
|
asset_as_band: bool = False,
|
|
632
731
|
**kwargs: Any,
|
|
633
732
|
) -> ImageData:
|
|
@@ -643,9 +742,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
643
742
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
644
743
|
|
|
645
744
|
"""
|
|
646
|
-
|
|
647
|
-
assets = (assets,)
|
|
648
|
-
|
|
745
|
+
assets = cast_to_sequence(assets)
|
|
649
746
|
if assets and expression:
|
|
650
747
|
warnings.warn(
|
|
651
748
|
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
@@ -655,9 +752,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
655
752
|
if expression:
|
|
656
753
|
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
657
754
|
|
|
755
|
+
if not assets and self.default_assets:
|
|
756
|
+
warnings.warn(
|
|
757
|
+
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
758
|
+
UserWarning,
|
|
759
|
+
)
|
|
760
|
+
assets = self.default_assets
|
|
761
|
+
|
|
658
762
|
if not assets:
|
|
659
763
|
raise MissingAssets(
|
|
660
|
-
"assets must be passed
|
|
764
|
+
"assets must be passed via `expression` or `assets` options, or via class-level `default_assets`."
|
|
661
765
|
)
|
|
662
766
|
|
|
663
767
|
asset_indexes = asset_indexes or {}
|
|
@@ -666,12 +770,17 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
666
770
|
indexes = kwargs.pop("indexes", None)
|
|
667
771
|
|
|
668
772
|
def _reader(asset: str, **kwargs: Any) -> ImageData:
|
|
669
|
-
idx = asset_indexes.get(asset) or indexes
|
|
773
|
+
idx = asset_indexes.get(asset) or indexes
|
|
670
774
|
|
|
671
775
|
asset_info = self._get_asset_info(asset)
|
|
672
|
-
|
|
776
|
+
reader, options = self._get_reader(asset_info)
|
|
777
|
+
|
|
673
778
|
with self.ctx(**asset_info.get("env", {})):
|
|
674
|
-
with
|
|
779
|
+
with reader(
|
|
780
|
+
asset_info["url"],
|
|
781
|
+
tms=self.tms,
|
|
782
|
+
**{**self.reader_options, **options},
|
|
783
|
+
) as src:
|
|
675
784
|
data = src.preview(indexes=idx, **kwargs)
|
|
676
785
|
|
|
677
786
|
self._update_statistics(
|
|
@@ -706,9 +815,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
706
815
|
self,
|
|
707
816
|
lon: float,
|
|
708
817
|
lat: float,
|
|
709
|
-
assets: Union[Sequence[str], str] = None,
|
|
818
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
710
819
|
expression: Optional[str] = None,
|
|
711
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
820
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
712
821
|
asset_as_band: bool = False,
|
|
713
822
|
**kwargs: Any,
|
|
714
823
|
) -> PointData:
|
|
@@ -726,9 +835,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
726
835
|
PointData
|
|
727
836
|
|
|
728
837
|
"""
|
|
729
|
-
|
|
730
|
-
assets = (assets,)
|
|
731
|
-
|
|
838
|
+
assets = cast_to_sequence(assets)
|
|
732
839
|
if assets and expression:
|
|
733
840
|
warnings.warn(
|
|
734
841
|
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
@@ -738,9 +845,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
738
845
|
if expression:
|
|
739
846
|
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
740
847
|
|
|
848
|
+
if not assets and self.default_assets:
|
|
849
|
+
warnings.warn(
|
|
850
|
+
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
851
|
+
UserWarning,
|
|
852
|
+
)
|
|
853
|
+
assets = self.default_assets
|
|
854
|
+
|
|
741
855
|
if not assets:
|
|
742
856
|
raise MissingAssets(
|
|
743
|
-
"assets must be passed
|
|
857
|
+
"assets must be passed via `expression` or `assets` options, or via class-level `default_assets`."
|
|
744
858
|
)
|
|
745
859
|
|
|
746
860
|
asset_indexes = asset_indexes or {}
|
|
@@ -748,13 +862,18 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
748
862
|
# We fall back to `indexes` if provided
|
|
749
863
|
indexes = kwargs.pop("indexes", None)
|
|
750
864
|
|
|
751
|
-
def _reader(asset: str, *args, **kwargs: Any) -> PointData:
|
|
752
|
-
idx = asset_indexes.get(asset) or indexes
|
|
865
|
+
def _reader(asset: str, *args: Any, **kwargs: Any) -> PointData:
|
|
866
|
+
idx = asset_indexes.get(asset) or indexes
|
|
753
867
|
|
|
754
868
|
asset_info = self._get_asset_info(asset)
|
|
755
|
-
|
|
869
|
+
reader, options = self._get_reader(asset_info)
|
|
870
|
+
|
|
756
871
|
with self.ctx(**asset_info.get("env", {})):
|
|
757
|
-
with
|
|
872
|
+
with reader(
|
|
873
|
+
asset_info["url"],
|
|
874
|
+
tms=self.tms,
|
|
875
|
+
**{**self.reader_options, **options},
|
|
876
|
+
) as src:
|
|
758
877
|
data = src.point(*args, indexes=idx, **kwargs)
|
|
759
878
|
|
|
760
879
|
metadata = data.metadata or {}
|
|
@@ -782,9 +901,9 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
782
901
|
def feature(
|
|
783
902
|
self,
|
|
784
903
|
shape: Dict,
|
|
785
|
-
assets: Union[Sequence[str], str] = None,
|
|
904
|
+
assets: Optional[Union[Sequence[str], str]] = None,
|
|
786
905
|
expression: Optional[str] = None,
|
|
787
|
-
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
906
|
+
asset_indexes: Optional[Dict[str, Indexes]] = None,
|
|
788
907
|
asset_as_band: bool = False,
|
|
789
908
|
**kwargs: Any,
|
|
790
909
|
) -> ImageData:
|
|
@@ -801,9 +920,7 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
801
920
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
802
921
|
|
|
803
922
|
"""
|
|
804
|
-
|
|
805
|
-
assets = (assets,)
|
|
806
|
-
|
|
923
|
+
assets = cast_to_sequence(assets)
|
|
807
924
|
if assets and expression:
|
|
808
925
|
warnings.warn(
|
|
809
926
|
"Both expression and assets passed; expression will overwrite assets parameter.",
|
|
@@ -813,9 +930,16 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
813
930
|
if expression:
|
|
814
931
|
assets = self.parse_expression(expression, asset_as_band=asset_as_band)
|
|
815
932
|
|
|
933
|
+
if not assets and self.default_assets:
|
|
934
|
+
warnings.warn(
|
|
935
|
+
f"No assets/expression passed, defaults to {self.default_assets}",
|
|
936
|
+
UserWarning,
|
|
937
|
+
)
|
|
938
|
+
assets = self.default_assets
|
|
939
|
+
|
|
816
940
|
if not assets:
|
|
817
941
|
raise MissingAssets(
|
|
818
|
-
"assets must be passed
|
|
942
|
+
"assets must be passed via `expression` or `assets` options, or via class-level `default_assets`."
|
|
819
943
|
)
|
|
820
944
|
|
|
821
945
|
asset_indexes = asset_indexes or {}
|
|
@@ -824,12 +948,17 @@ class MultiBaseReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
824
948
|
indexes = kwargs.pop("indexes", None)
|
|
825
949
|
|
|
826
950
|
def _reader(asset: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
827
|
-
idx = asset_indexes.get(asset) or indexes
|
|
951
|
+
idx = asset_indexes.get(asset) or indexes
|
|
828
952
|
|
|
829
953
|
asset_info = self._get_asset_info(asset)
|
|
830
|
-
|
|
954
|
+
reader, options = self._get_reader(asset_info)
|
|
955
|
+
|
|
831
956
|
with self.ctx(**asset_info.get("env", {})):
|
|
832
|
-
with
|
|
957
|
+
with reader(
|
|
958
|
+
asset_info["url"],
|
|
959
|
+
tms=self.tms,
|
|
960
|
+
**{**self.reader_options, **options},
|
|
961
|
+
) as src:
|
|
833
962
|
data = src.feature(*args, indexes=idx, **kwargs)
|
|
834
963
|
|
|
835
964
|
self._update_statistics(
|
|
@@ -886,6 +1015,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
886
1015
|
reader_options: Dict = attr.ib(factory=dict)
|
|
887
1016
|
|
|
888
1017
|
bands: Sequence[str] = attr.ib(init=False)
|
|
1018
|
+
default_bands: Optional[Sequence[str]] = attr.ib(init=False, default=None)
|
|
889
1019
|
|
|
890
1020
|
def __enter__(self):
|
|
891
1021
|
"""Support using with Context Managers."""
|
|
@@ -913,7 +1043,11 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
913
1043
|
|
|
914
1044
|
return bands
|
|
915
1045
|
|
|
916
|
-
def info(
|
|
1046
|
+
def info(
|
|
1047
|
+
self,
|
|
1048
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1049
|
+
**kwargs: Any,
|
|
1050
|
+
) -> Info:
|
|
917
1051
|
"""Return metadata from multiple bands.
|
|
918
1052
|
|
|
919
1053
|
Args:
|
|
@@ -929,22 +1063,22 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
929
1063
|
UserWarning,
|
|
930
1064
|
)
|
|
931
1065
|
|
|
932
|
-
bands = bands or self.bands
|
|
933
|
-
|
|
934
|
-
if isinstance(bands, str):
|
|
935
|
-
bands = (bands,)
|
|
1066
|
+
bands = cast_to_sequence(bands or self.bands)
|
|
936
1067
|
|
|
937
1068
|
def _reader(band: str, **kwargs: Any) -> Info:
|
|
938
1069
|
url = self._get_band_url(band)
|
|
939
|
-
with self.reader(
|
|
1070
|
+
with self.reader(
|
|
1071
|
+
url,
|
|
1072
|
+
tms=self.tms,
|
|
1073
|
+
**self.reader_options,
|
|
1074
|
+
) as src:
|
|
940
1075
|
return src.info()
|
|
941
1076
|
|
|
942
|
-
bands_metadata = multi_values(bands, _reader,
|
|
1077
|
+
bands_metadata = multi_values(bands, _reader, **kwargs)
|
|
943
1078
|
|
|
944
1079
|
meta = {
|
|
945
|
-
"bounds": self.
|
|
946
|
-
"
|
|
947
|
-
"maxzoom": self.maxzoom,
|
|
1080
|
+
"bounds": self.bounds,
|
|
1081
|
+
"crs": CRS_to_uri(self.crs) or self.crs.to_wkt(),
|
|
948
1082
|
}
|
|
949
1083
|
|
|
950
1084
|
# We only keep the value for the first band.
|
|
@@ -965,7 +1099,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
965
1099
|
|
|
966
1100
|
def statistics(
|
|
967
1101
|
self,
|
|
968
|
-
bands: Union[Sequence[str], str] = None,
|
|
1102
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
969
1103
|
expression: Optional[str] = None,
|
|
970
1104
|
categorical: bool = False,
|
|
971
1105
|
categories: Optional[List[float]] = None,
|
|
@@ -996,7 +1130,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
996
1130
|
"No `bands` option passed, will fetch statistics for all available bands.",
|
|
997
1131
|
UserWarning,
|
|
998
1132
|
)
|
|
999
|
-
bands = bands or self.bands
|
|
1133
|
+
bands = cast_to_sequence(bands or self.bands)
|
|
1000
1134
|
|
|
1001
1135
|
data = self.preview(
|
|
1002
1136
|
bands=bands,
|
|
@@ -1016,7 +1150,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1016
1150
|
tile_x: int,
|
|
1017
1151
|
tile_y: int,
|
|
1018
1152
|
tile_z: int,
|
|
1019
|
-
bands: Union[Sequence[str], str] = None,
|
|
1153
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1020
1154
|
expression: Optional[str] = None,
|
|
1021
1155
|
**kwargs: Any,
|
|
1022
1156
|
) -> ImageData:
|
|
@@ -1039,9 +1173,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1039
1173
|
f"Tile(x={tile_x}, y={tile_y}, z={tile_z}) is outside bounds"
|
|
1040
1174
|
)
|
|
1041
1175
|
|
|
1042
|
-
|
|
1043
|
-
bands = (bands,)
|
|
1044
|
-
|
|
1176
|
+
bands = cast_to_sequence(bands)
|
|
1045
1177
|
if bands and expression:
|
|
1046
1178
|
warnings.warn(
|
|
1047
1179
|
"Both expression and bands passed; expression will overwrite bands parameter.",
|
|
@@ -1051,6 +1183,13 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1051
1183
|
if expression:
|
|
1052
1184
|
bands = self.parse_expression(expression)
|
|
1053
1185
|
|
|
1186
|
+
if not bands and self.default_bands:
|
|
1187
|
+
warnings.warn(
|
|
1188
|
+
f"No bands/expression passed, defaults to {self.default_bands}",
|
|
1189
|
+
UserWarning,
|
|
1190
|
+
)
|
|
1191
|
+
bands = self.default_bands
|
|
1192
|
+
|
|
1054
1193
|
if not bands:
|
|
1055
1194
|
raise MissingBands(
|
|
1056
1195
|
"bands must be passed either via `expression` or `bands` options."
|
|
@@ -1058,11 +1197,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1058
1197
|
|
|
1059
1198
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1060
1199
|
url = self._get_band_url(band)
|
|
1061
|
-
with self.reader(
|
|
1200
|
+
with self.reader(
|
|
1201
|
+
url,
|
|
1202
|
+
tms=self.tms,
|
|
1203
|
+
**self.reader_options,
|
|
1204
|
+
) as src:
|
|
1062
1205
|
data = src.tile(*args, **kwargs)
|
|
1206
|
+
|
|
1063
1207
|
if data.metadata:
|
|
1064
1208
|
data.metadata = {band: data.metadata}
|
|
1065
|
-
|
|
1209
|
+
|
|
1210
|
+
# use `band` as name instead of band index
|
|
1211
|
+
data.band_names = [band]
|
|
1212
|
+
|
|
1066
1213
|
return data
|
|
1067
1214
|
|
|
1068
1215
|
img = multi_arrays(bands, _reader, tile_x, tile_y, tile_z, **kwargs)
|
|
@@ -1075,7 +1222,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1075
1222
|
def part(
|
|
1076
1223
|
self,
|
|
1077
1224
|
bbox: BBox,
|
|
1078
|
-
bands: Union[Sequence[str], str] = None,
|
|
1225
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1079
1226
|
expression: Optional[str] = None,
|
|
1080
1227
|
**kwargs: Any,
|
|
1081
1228
|
) -> ImageData:
|
|
@@ -1091,9 +1238,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1091
1238
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
1092
1239
|
|
|
1093
1240
|
"""
|
|
1094
|
-
|
|
1095
|
-
bands = (bands,)
|
|
1096
|
-
|
|
1241
|
+
bands = cast_to_sequence(bands)
|
|
1097
1242
|
if bands and expression:
|
|
1098
1243
|
warnings.warn(
|
|
1099
1244
|
"Both expression and bands passed; expression will overwrite bands parameter.",
|
|
@@ -1103,6 +1248,13 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1103
1248
|
if expression:
|
|
1104
1249
|
bands = self.parse_expression(expression)
|
|
1105
1250
|
|
|
1251
|
+
if not bands and self.default_bands:
|
|
1252
|
+
warnings.warn(
|
|
1253
|
+
f"No bands/expression passed, defaults to {self.default_bands}",
|
|
1254
|
+
UserWarning,
|
|
1255
|
+
)
|
|
1256
|
+
bands = self.default_bands
|
|
1257
|
+
|
|
1106
1258
|
if not bands:
|
|
1107
1259
|
raise MissingBands(
|
|
1108
1260
|
"bands must be passed either via `expression` or `bands` options."
|
|
@@ -1110,11 +1262,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1110
1262
|
|
|
1111
1263
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1112
1264
|
url = self._get_band_url(band)
|
|
1113
|
-
with self.reader(
|
|
1265
|
+
with self.reader(
|
|
1266
|
+
url,
|
|
1267
|
+
tms=self.tms,
|
|
1268
|
+
**self.reader_options,
|
|
1269
|
+
) as src:
|
|
1114
1270
|
data = src.part(*args, **kwargs)
|
|
1271
|
+
|
|
1115
1272
|
if data.metadata:
|
|
1116
1273
|
data.metadata = {band: data.metadata}
|
|
1117
|
-
|
|
1274
|
+
|
|
1275
|
+
# use `band` as name instead of band index
|
|
1276
|
+
data.band_names = [band]
|
|
1277
|
+
|
|
1118
1278
|
return data
|
|
1119
1279
|
|
|
1120
1280
|
img = multi_arrays(bands, _reader, bbox, **kwargs)
|
|
@@ -1126,7 +1286,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1126
1286
|
|
|
1127
1287
|
def preview(
|
|
1128
1288
|
self,
|
|
1129
|
-
bands: Union[Sequence[str], str] = None,
|
|
1289
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1130
1290
|
expression: Optional[str] = None,
|
|
1131
1291
|
**kwargs: Any,
|
|
1132
1292
|
) -> ImageData:
|
|
@@ -1141,9 +1301,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1141
1301
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
1142
1302
|
|
|
1143
1303
|
"""
|
|
1144
|
-
|
|
1145
|
-
bands = (bands,)
|
|
1146
|
-
|
|
1304
|
+
bands = cast_to_sequence(bands)
|
|
1147
1305
|
if bands and expression:
|
|
1148
1306
|
warnings.warn(
|
|
1149
1307
|
"Both expression and bands passed; expression will overwrite bands parameter.",
|
|
@@ -1153,6 +1311,13 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1153
1311
|
if expression:
|
|
1154
1312
|
bands = self.parse_expression(expression)
|
|
1155
1313
|
|
|
1314
|
+
if not bands and self.default_bands:
|
|
1315
|
+
warnings.warn(
|
|
1316
|
+
f"No bands/expression passed, defaults to {self.default_bands}",
|
|
1317
|
+
UserWarning,
|
|
1318
|
+
)
|
|
1319
|
+
bands = self.default_bands
|
|
1320
|
+
|
|
1156
1321
|
if not bands:
|
|
1157
1322
|
raise MissingBands(
|
|
1158
1323
|
"bands must be passed either via `expression` or `bands` options."
|
|
@@ -1160,11 +1325,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1160
1325
|
|
|
1161
1326
|
def _reader(band: str, **kwargs: Any) -> ImageData:
|
|
1162
1327
|
url = self._get_band_url(band)
|
|
1163
|
-
with self.reader(
|
|
1328
|
+
with self.reader(
|
|
1329
|
+
url,
|
|
1330
|
+
tms=self.tms,
|
|
1331
|
+
**self.reader_options,
|
|
1332
|
+
) as src:
|
|
1164
1333
|
data = src.preview(**kwargs)
|
|
1334
|
+
|
|
1165
1335
|
if data.metadata:
|
|
1166
1336
|
data.metadata = {band: data.metadata}
|
|
1167
|
-
|
|
1337
|
+
|
|
1338
|
+
# use `band` as name instead of band index
|
|
1339
|
+
data.band_names = [band]
|
|
1340
|
+
|
|
1168
1341
|
return data
|
|
1169
1342
|
|
|
1170
1343
|
img = multi_arrays(bands, _reader, **kwargs)
|
|
@@ -1178,7 +1351,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1178
1351
|
self,
|
|
1179
1352
|
lon: float,
|
|
1180
1353
|
lat: float,
|
|
1181
|
-
bands: Union[Sequence[str], str] = None,
|
|
1354
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1182
1355
|
expression: Optional[str] = None,
|
|
1183
1356
|
**kwargs: Any,
|
|
1184
1357
|
) -> PointData:
|
|
@@ -1195,9 +1368,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1195
1368
|
PointData
|
|
1196
1369
|
|
|
1197
1370
|
"""
|
|
1198
|
-
|
|
1199
|
-
bands = (bands,)
|
|
1200
|
-
|
|
1371
|
+
bands = cast_to_sequence(bands)
|
|
1201
1372
|
if bands and expression:
|
|
1202
1373
|
warnings.warn(
|
|
1203
1374
|
"Both expression and bands passed; expression will overwrite bands parameter.",
|
|
@@ -1207,18 +1378,33 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1207
1378
|
if expression:
|
|
1208
1379
|
bands = self.parse_expression(expression)
|
|
1209
1380
|
|
|
1381
|
+
if not bands and self.default_bands:
|
|
1382
|
+
warnings.warn(
|
|
1383
|
+
f"No bands/expression passed, defaults to {self.default_bands}",
|
|
1384
|
+
UserWarning,
|
|
1385
|
+
)
|
|
1386
|
+
bands = self.default_bands
|
|
1387
|
+
|
|
1210
1388
|
if not bands:
|
|
1211
1389
|
raise MissingBands(
|
|
1212
1390
|
"bands must be passed either via `expression` or `bands` options."
|
|
1213
1391
|
)
|
|
1214
1392
|
|
|
1215
|
-
def _reader(band: str, *args, **kwargs: Any) -> PointData:
|
|
1393
|
+
def _reader(band: str, *args: Any, **kwargs: Any) -> PointData:
|
|
1216
1394
|
url = self._get_band_url(band)
|
|
1217
|
-
with self.reader(
|
|
1395
|
+
with self.reader(
|
|
1396
|
+
url,
|
|
1397
|
+
tms=self.tms,
|
|
1398
|
+
**self.reader_options,
|
|
1399
|
+
) as src:
|
|
1218
1400
|
data = src.point(*args, **kwargs)
|
|
1401
|
+
|
|
1219
1402
|
if data.metadata:
|
|
1220
1403
|
data.metadata = {band: data.metadata}
|
|
1221
|
-
|
|
1404
|
+
|
|
1405
|
+
# use `band` as name instead of band index
|
|
1406
|
+
data.band_names = [band]
|
|
1407
|
+
|
|
1222
1408
|
return data
|
|
1223
1409
|
|
|
1224
1410
|
data = multi_points(bands, _reader, lon, lat, **kwargs)
|
|
@@ -1230,7 +1416,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1230
1416
|
def feature(
|
|
1231
1417
|
self,
|
|
1232
1418
|
shape: Dict,
|
|
1233
|
-
bands: Union[Sequence[str], str] = None,
|
|
1419
|
+
bands: Optional[Union[Sequence[str], str]] = None,
|
|
1234
1420
|
expression: Optional[str] = None,
|
|
1235
1421
|
**kwargs: Any,
|
|
1236
1422
|
) -> ImageData:
|
|
@@ -1246,9 +1432,7 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1246
1432
|
rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info.
|
|
1247
1433
|
|
|
1248
1434
|
"""
|
|
1249
|
-
|
|
1250
|
-
bands = (bands,)
|
|
1251
|
-
|
|
1435
|
+
bands = cast_to_sequence(bands)
|
|
1252
1436
|
if bands and expression:
|
|
1253
1437
|
warnings.warn(
|
|
1254
1438
|
"Both expression and bands passed; expression will overwrite bands parameter.",
|
|
@@ -1258,6 +1442,13 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1258
1442
|
if expression:
|
|
1259
1443
|
bands = self.parse_expression(expression)
|
|
1260
1444
|
|
|
1445
|
+
if not bands and self.default_bands:
|
|
1446
|
+
warnings.warn(
|
|
1447
|
+
f"No bands/expression passed, defaults to {self.default_bands}",
|
|
1448
|
+
UserWarning,
|
|
1449
|
+
)
|
|
1450
|
+
bands = self.default_bands
|
|
1451
|
+
|
|
1261
1452
|
if not bands:
|
|
1262
1453
|
raise MissingBands(
|
|
1263
1454
|
"bands must be passed either via `expression` or `bands` options."
|
|
@@ -1265,11 +1456,19 @@ class MultiBandReader(SpatialMixin, metaclass=abc.ABCMeta):
|
|
|
1265
1456
|
|
|
1266
1457
|
def _reader(band: str, *args: Any, **kwargs: Any) -> ImageData:
|
|
1267
1458
|
url = self._get_band_url(band)
|
|
1268
|
-
with self.reader(
|
|
1459
|
+
with self.reader(
|
|
1460
|
+
url,
|
|
1461
|
+
tms=self.tms,
|
|
1462
|
+
**self.reader_options,
|
|
1463
|
+
) as src:
|
|
1269
1464
|
data = src.feature(*args, **kwargs)
|
|
1465
|
+
|
|
1270
1466
|
if data.metadata:
|
|
1271
1467
|
data.metadata = {band: data.metadata}
|
|
1272
|
-
|
|
1468
|
+
|
|
1469
|
+
# use `band` as name instead of band index
|
|
1470
|
+
data.band_names = [band]
|
|
1471
|
+
|
|
1273
1472
|
return data
|
|
1274
1473
|
|
|
1275
1474
|
img = multi_arrays(bands, _reader, shape, **kwargs)
|