diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7cfd56ed..05d2bfcb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ['3.7', '3.8', '3.9']
+ python-version: ['3.8', '3.9', '3.10']
steps:
- uses: actions/checkout@v2
@@ -28,17 +28,16 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install pre-commit codecov
-
- - name: Install module
- run: python -m pip install .["test"]
+ python -m pip install -e .["test"]
- name: Run pre-commit
if: ${{ matrix.python-version == env.LATEST_PY_VERSION }}
- run: pre-commit run --all-files
+ run: |
+ python -m pip install pre-commit
+ pre-commit run --all-files
- name: Run tests
- run: python -m pytest --cov rio_tiler --cov-report xml --cov-report term-missing --benchmark-skip
+ run: python -m pytest --cov rio_tiler --cov-report xml --cov-report term-missing --benchmark-skip -s -vv
- name: Upload Results
if: ${{ matrix.python-version == env.LATEST_PY_VERSION }}
@@ -73,20 +72,20 @@ jobs:
- name: Run Benchmark
run: python -m pytest --benchmark-only --benchmark-autosave --benchmark-columns 'min, max, mean, median' --benchmark-sort 'min' --benchmark-json output.json
- - name: Store and Compare benchmark result
- uses: benchmark-action/github-action-benchmark@v1
- with:
- name: rio-tiler Benchmarks
- tool: 'pytest'
- output-file-path: output.json
- alert-threshold: '130%'
- comment-on-alert: true
- fail-on-alert: true
- # GitHub API token to make a commit comment
- github-token: ${{ secrets.GITHUB_TOKEN }}
- # Make a commit on `gh-pages` only if master
- auto-push: ${{ github.ref == 'refs/heads/master' }}
- benchmark-data-dir-path: benchmarks
+ # - name: Store and Compare benchmark result
+ # uses: benchmark-action/github-action-benchmark@v1
+ # with:
+ # name: rio-tiler Benchmarks
+ # tool: 'pytest'
+ # output-file-path: output.json
+ # alert-threshold: '130%'
+ # comment-on-alert: true
+ # fail-on-alert: true
+ # # GitHub API token to make a commit comment
+ # github-token: ${{ secrets.GITHUB_TOKEN }}
+ # # Make a commit on `gh-pages` only if master
+ # auto-push: ${{ github.ref == 'refs/heads/master' }}
+ # benchmark-data-dir-path: benchmarks
publish:
needs: [tests]
diff --git a/.github/workflows/deploy_mkdocs.yml b/.github/workflows/deploy_mkdocs.yml
index 97bdf800..336a99d1 100644
--- a/.github/workflows/deploy_mkdocs.yml
+++ b/.github/workflows/deploy_mkdocs.yml
@@ -44,8 +44,9 @@ jobs:
rio_tiler.expression \
rio_tiler.models \
rio_tiler.io.base \
- rio_tiler.io.cogeo \
+ rio_tiler.io.rasterio \
rio_tiler.io.stac \
+ rio_tiler.io.xarray \
rio_tiler.mosaic.methods.base \
rio_tiler.mosaic.methods.defaults \
rio_tiler.mosaic.reader \
diff --git a/.gitignore b/.gitignore
index 5f96ea0b..87350fa2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -108,4 +108,4 @@ tests/benchmarks/data/*
tests/fixtures/mask*
.vscode/settings.json
-docs/api*
+docs/src/api/*
diff --git a/CHANGES.md b/CHANGES.md
index e207d274..5615dfdc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,4 +1,162 @@
+# 4.0.0 (TBD)
+
+* add python 3.10 support
+* add `apply_expression` method in `rio_tiler.models.ImageData` class
+* update `rio-tiler.reader.read/part` to avoid using WarpedVRT when no *reprojection* or *nodata override* is needed
+* add `rio_tiler.io.rasterio.ImageReader` to work either with Non-geo or Geo images in a Non-geo manner (a.k.a: in the pixel coordinates system)
+ ```python
+ with ImageReader("image.jpg") as src:
+ im = src.part((0, 100, 100, 0))
+
+ with ImageReader("image.jpg") as src:
+ im = src.tile(0, 0, src.maxzoom)
+ print(im.bounds)
+
+ >>> BoundingBox(left=0.0, bottom=256.0, right=256.0, top=0.0)
+ ```
+
+* add `rio_tiler.io.xarray.XarrayReader` to work with `xarray.DataArray`
+ ```python
+ import xarray
+ from rio_tiler.io import XarrayReader
+
+ with xarray.open_dataset(
+ "https://ncsa.osn.xsede.org/Pangeo/pangeo-forge/noaa-coastwatch-geopolar-sst-feedstock/noaa-coastwatch-geopolar-sst.zarr",
+ engine="zarr",
+ decode_coords="all"
+ ) as src:
+ ds = src["analysed_sst"][:1]
+ ds.rio.write_crs("epsg:4326", inplace=True)
+
+ with XarrayReader(ds) as dst:
+ img = dst.tile(1, 1, 2)
+ ```
+ note: `xarray` and `rioxarray` optional dependencies are needed for the reader
+
+**breaking changes**
+
+* remove python 3.7 support
+* update rasterio requirement to `>=1.3` to allow python 3.10 support
+* rename `rio_tiler.io.cogeo` to `rio_tiler.io.rasterio`
+* rename `COGReader` to `Reader`. We added `rio_tiler.io.COGReader` alias to `rio_tiler.io.Reader` backwards compatibility
+ ```python
+ # before
+ from rio_tiler.io import COGReader
+ from rio_tiler.io.cogeo import COGReader
+
+ # now
+ from rio_tiler.io import Reader
+ from rio_tiler.io.rasterio import Reader
+ ```
+
+* `rio_tiler.readers.read()`, `rio_tiler.readers.part()`, `rio_tiler.readers.preview()` now return a ImageData object
+* remove `minzoom` and `maxzoom` attribute in `rio_tiler.io.SpatialMixin` base class
+* remove `minzoom` and `maxzoom` attribute in `rio_tiler.io.Reader` (now defined as properties)
+* use `b` prefix for band names in `rio_tiler.models.ImageData` class (and in rio-tiler's readers)
+ ```python
+ # before
+ with COGReader("cog.tif") as cog:
+ img = cog.read()
+ print(cog.band_names)
+ >>> ["1", "2", "3"]
+
+ print(cog.info().band_metadata)
+ >>> [("1", {}), ("2", {}), ("3", {})]
+
+ print(cog.info().band_descriptions)
+ >>> [("1", ""), ("2", ""), ("3", "")]
+
+ print(list(cog.statistics()))
+ >>> ["1", "2", "3"]
+
+ # now
+ with Reader("cog.tif") as cog:
+ img = cog.read()
+ print(img.band_names)
+ >>> ["b1", "b2", "b3"]
+
+ print(cog.info().band_metadata)
+ >>> [("b1", {}), ("b2", {}), ("b3", {})]
+
+ print(cog.info().band_descriptions)
+ >>> [("b1", ""), ("b2", ""), ("b3", "")]
+
+ print(list(cog.statistics()))
+ >>> ["b1", "b2", "b3"]
+
+ with STACReader("stac.json") as stac:
+ print(stac.tile(701, 102, 8, assets=("green", "red")).band_names)
+ >>> ["green_b1", "red_b1"]
+ ```
+
+* depreciate `asset_expression` in MultiBaseReader. Use of expression is now possible
+* `expression` for MultiBaseReader must be in form of `{asset}_b{index}`
+
+ ```python
+ # before
+ with STACReader("stac.json") as stac:
+ stac.tile(701, 102, 8, expression="green/red")
+
+ # now
+ with STACReader("stac.json") as stac:
+ stac.tile(701, 102, 8, expression="green_b1/red_b1")
+ ```
+
+* `rio_tiler.reader.point()` (and all Reader's point methods) now return a **rio_tiler.models.PointData** object
+
+ ```python
+ # before
+ with rasterio.open("cog.tif") as src::
+ v = rio_tiler.reader.point(10.20, -42.0)
+ print(v)
+ >>> [0, 0, 0]
+
+ with COGReader("cog.tif") as cog:
+ print(cog.point(10.20, -42.0))
+ >>> [0, 0, 0]
+
+ # now
+ with rasterio.open("cog.tif") as src::
+ v = rio_tiler.reader.point(src, (10.20, -42))
+ print(v)
+ >>> PointData(
+ data=array([3744], dtype=uint16),
+ mask=array([255], dtype=uint8),
+ band_names=['b1'],
+ coordinates=(10.20, -42),
+ crs=CRS.from_epsg(4326),
+ assets=['cog.tif'],
+ metadata={}
+ )
+
+ with Reader("cog.tif") as cog:
+ print(cog.point(10.20, -42.0))
+ >>> PointData(
+ data=array([3744], dtype=uint16),
+ mask=array([255], dtype=uint8),
+ band_names=['b1'],
+ coordinates=(10.20, -42),
+ crs=CRS.from_epsg(4326),
+ assets=['cog.tif'],
+ metadata={}
+ )
+ ```
+
+* deleted `rio_tiler.reader.preview` function and updated `rio_tiler.reader.read` to allow width/height/max_size options
+* reordered keyword options in all `rio_tiler.reader` function for consistency
+* removed `AlphaBandWarning` warning when automatically excluding alpha band from data
+* remove `nodata`, `unscale`, `resampling_method`, `vrt_options` and `post_process` options to `Reader` init method and replaced with `options`
+ ```python
+ # before
+ with COGReader("cog.tif", nodata=1, resampling_method="bilinear") as cog:
+ data = cog.preview()
+
+ # now
+ with Reader(COGEO, options={"nodata": 1, "resampling_method": "bilinear"}) as cog:
+ data = cog.preview()
+ ```
+
# 3.1.6 (2022-07-22)
* Hide `NotGeoreferencedWarning` warnings in `utils.render` and `utils.resize_array`
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 602de440..f2c1e08d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -56,8 +56,9 @@ pdocs as_markdown \
rio_tiler.expression \
rio_tiler.models \
rio_tiler.io.base \
- rio_tiler.io.cogeo \
+ rio_tiler.io.rasterio \
rio_tiler.io.stac \
+ rio_tiler.io.xarray \
rio_tiler.mosaic.methods.base \
rio_tiler.mosaic.methods.defaults \
rio_tiler.mosaic.reader \
diff --git a/README.md b/README.md
index a86573e9..3d450bdf 100644
--- a/README.md
+++ b/README.md
@@ -47,16 +47,16 @@ data and metadata from any raster source supported by Rasterio/GDAL.
This includes local and remote files via HTTP, AWS S3, Google Cloud Storage,
etc.
-At the low level, `rio-tiler` is *just* a wrapper around the [rasterio.vrt.WarpedVRT](https://github.com/rasterio/rasterio/blob/5b76d05fb374e64602166d6cd880c38424fad39b/rasterio/vrt.py#L15) class, which can be useful for doing re-projection and/or property overriding (e.g nodata value).
+At the low level, `rio-tiler` is *just* a wrapper around the [rasterio](https://github.com/rasterio/rasterio) and [GDAL](https://github.com/osgeo/gdal) libraries.
## Features
- Read any dataset supported by GDAL/Rasterio
```python
- from rio_tiler.io import COGReader
+ from rio_tiler.io import Reader
- with COGReader("my.tif") as image:
+ with Reader("my.tif") as image:
print(image.dataset) # rasterio opened dataset
img = image.read() # similar to rasterio.open("my.tif").read() but returns a rio_tiler.models.ImageData object
```
@@ -64,9 +64,9 @@ At the low level, `rio-tiler` is *just* a wrapper around the [rasterio.vrt.Warpe
- User friendly `tile`, `part`, `feature`, `point` reading methods
```python
- from rio_tiler.io import COGReader
+ from rio_tiler.io import Reader
- with COGReader("my.tif") as image:
+ with Reader("my.tif") as image:
img = image.tile(x, y, z) # read mercator tile z-x-y
img = image.part(bbox) # read the data intersecting a bounding box
img = image.feature(geojson_feature) # read the data intersecting a geojson feature
@@ -76,9 +76,9 @@ At the low level, `rio-tiler` is *just* a wrapper around the [rasterio.vrt.Warpe
- Enable property assignment (e.g nodata) on data reading
```python
- from rio_tiler.io import COGReader
+ from rio_tiler.io import Reader
- with COGReader("my.tif") as image:
+ with Reader("my.tif") as image:
img = image.tile(x, y, z, nodata=-9999) # read mercator tile z-x-y
```
@@ -107,14 +107,46 @@ At the low level, `rio-tiler` is *just* a wrapper around the [rasterio.vrt.Warpe
)
```
+- [Xarray](https://xarray.dev) support **(>=4.0)**
+
+ ```python
+ import xarray
+ from rio_tiler.io import XarrayReader
+
+ ds = xarray.open_dataset(
+ "https://pangeo.blob.core.windows.net/pangeo-public/daymet-rio-tiler/na-wgs84.zarr/",
+ engine="zarr",
+ decode_coords="all",
+ consolidated=True,
+ )
+ da = ds["tmax"]
+ with XarrayReader(da) as dst:
+ print(dst.info())
+ img = dst.tile(1, 1, 2)
+ ```
+ *Note: The XarrayReader needs optional dependencies to be installed `pip install rio-tiler["xarray"]`.*
+
+- Non-Geo Image support **(>=4.0)**
+
+ ```python
+ from rio_tiler.io import ImageReader
+
+ with ImageReader("image.jpeg") as src:
+ im = src.tile(0, 0, src.maxzoom) # read top-left `tile`
+ im = src.part((0, 100, 100, 0)) # read top-left 100x100 pixels
+ pt = src.point(0, 0) # read pixel value
+ ```
+
+ *Note: `ImageReader` is also compatible with proper geo-referenced raster datasets.*
+
- [Mosaic](https://cogeotiff.github.io/rio-tiler/mosaic/) (merging or stacking)
```python
- from rio_tiler.io import COGReader
+ from rio_tiler.io import Reader
from rio_tiler.mosaic import mosaic_reader
def reader(file, x, y, z, **kwargs):
- with COGReader(file) as image:
+ with Reader(file) as image:
return image.tile(x, y, z, **kwargs)
img, assets = mosaic_reader(["image1.tif", "image2.tif"], reader, x, y, z)
@@ -124,11 +156,11 @@ At the low level, `rio-tiler` is *just* a wrapper around the [rasterio.vrt.Warpe
```python
import morecantile
- from rio_tiler.io import COGReader
+ from rio_tiler.io import Reader
# Use EPSG:4326 (WGS84) grid
wgs84_grid = morecantile.tms.get("WorldCRS84Quad")
- with COGReader("my.tif", tms=wgs84_grid) as cog:
+ with Reader("my.tif", tms=wgs84_grid) as cog:
img = cog.tile(1, 1, 1)
```
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index 0289ac90..a269cc9d 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -51,8 +51,9 @@ nav:
- rio_tiler.models: api/rio_tiler/models.md
- rio_tiler.io:
- rio_tiler.io.base: api/rio_tiler/io/base.md
- - rio_tiler.io.cogeo: api/rio_tiler/io/cogeo.md
+ - rio_tiler.io.rasterio: api/rio_tiler/io/rasterio.md
- rio_tiler.io.stac: api/rio_tiler/io/stac.md
+ - rio_tiler.io.xarray: api/rio_tiler/io/xarray.md
- rio_tiler.mosaic:
- rio_tiler.mosaic.reader: api/rio_tiler/mosaic/reader.md
- rio_tiler.mosaic.methods:
@@ -64,6 +65,7 @@ nav:
- rio_tiler.utils: api/rio_tiler/utils.md
- Migration from v1.0 to v2.0: 'v2_migration.md'
- Migration from v2.0 to v3.0: 'v3_migration.md'
+ - Migration from v3.0 to v4.0: 'v4_migration.md'
- Development - Contributing: 'contributing.md'
- Release Notes: 'release-notes.md'
diff --git a/docs/src/advanced/custom_readers.md b/docs/src/advanced/custom_readers.md
index b105043d..2507909d 100644
--- a/docs/src/advanced/custom_readers.md
+++ b/docs/src/advanced/custom_readers.md
@@ -1,7 +1,7 @@
`rio-tiler` provides multiple [abstract base
classes](https://docs.python.org/3.7/library/abc.html) from which it derives its
-main readers: [`COGReader`](../readers.md#cogreader) and
+main readers: [`Reader`](../readers.md#reader) and
[`STACReader`](../readers.md#stacreader). You can also use these classes to build
custom readers.
@@ -16,8 +16,6 @@ Main `rio_tiler.io` Abstract Base Class.
- **input**: Input
- **tms**: The TileMatrixSet define which default projection and map grid the reader uses. Defaults to WebMercatorQuad.
-- **minzoom**: Dataset's minzoom. Not in the `__init__` method.
-- **maxzoom**: Dataset's maxzoom. Not in the `__init__` method.
- **bounds**: Dataset's bounding box. Not in the `__init__` method.
- **crs**: dataset's crs. Not in the `__init__` method.
- **geographic_crs**: CRS to use as geographic coordinate system. Defaults to WGS84. Not in the `__init__` method.
@@ -45,13 +43,7 @@ Abstract methods, are method that **HAVE TO** be implemented in the child class.
- **point**: reads pixel value for a specific point (`List`)
- **feature**: reads data for a geojson feature (`rio_tiler.models.ImageData`)
-Example: [`COGReader`](../readers.md#cogreader)
-
-### **AsyncBaseReader**
-
-Equivalent of `BaseReader` for async-ready readers (e.g [aiocogeo](https://github.com/geospatial-jeff/aiocogeo)). The `AsyncBaseReader` has the same attributes/properties/methods as the `BaseReader`.
-
-see example of reader built using `AsyncBaseReader`: https://github.com/cogeotiff/rio-tiler/blob/832ecbd97f560c2764818bca30ca95ef25408527/tests/test_io_async.py#L49
+Example: [`Reader`](../readers.md#reader)
### **MultiBaseReader**
@@ -69,7 +61,7 @@ from typing import Dict, Type
import attr
from morecantile import TileMatrixSet
from rio_tiler.io.base import MultiBaseReader
-from rio_tiler.io import COGReader, BaseReader
+from rio_tiler.io import Reader, BaseReader
from rio_tiler.constants import WEB_MERCATOR_TMS
from rio_tiler.models import Info
@@ -81,7 +73,7 @@ class AssetFileReader(MultiBaseReader):
# because we add another attribute (prefix) we need to
# re-specify the other attribute for the class
- reader: Type[BaseReader] = attr.ib(default=COGReader)
+ reader: Type[BaseReader] = attr.ib(default=Reader)
reader_options: Dict = attr.ib(factory=dict)
tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
@@ -111,30 +103,30 @@ class AssetFileReader(MultiBaseReader):
# we have a directoty with "scene_b1.tif", "scene_b2.tif"
with AssetFileReader(input="my_dir/", prefix="scene_") as cr:
print(cr.assets)
- >>> ['b1', 'b2']
+ >>> ['band1', 'band2']
- info = cr.info(assets=("b1", "b2"))
+ info = cr.info(assets=("band1", "band2"))
# MultiBaseReader returns a Dict
assert isinstance(info, dict)
print(list(info))
- >>> ['b1', 'b2']
+ >>> ['band1', 'band2']
- assert isinstance(info["b1"], Info)
- print(info["b1"].json(exclude_none=True))
+ assert isinstance(info["band1"], Info)
+ print(info["band1"].json(exclude_none=True))
>>> {
'bounds': [-11.979244865430259, 24.296321392464325, -10.874546803397614, 25.304623891542263],
'minzoom': 7,
'maxzoom': 9,
- 'band_metadata': [('1', {})],
- 'band_descriptions': [('1', '')],
+ 'band_metadata': [('b1', {})],
+ 'band_descriptions': [('b1', '')],
'dtype': 'uint16',
'nodata_type': 'Nodata',
'colorinterp': ['gray']
}
- img = cr.tile(238, 218, 9, assets=("b1", "b2"))
+ img = cr.tile(238, 218, 9, assets=("band1", "band2"))
print(img.assets)
- >>> ['my_dir/scene_b1.tif', 'my_dir/scene_b2.tif']
+ >>> ['my_dir/scene_band1.tif', 'my_dir/scene_band2.tif']
# Each assets have 1 bands, so when combining each img we get a (2, 256, 256) array.
print(img.data.shape)
@@ -199,24 +191,24 @@ class BandFileReader(MultiBandReader):
# we have a directoty with "scene_b1.tif", "scene_b2.tif"
with BandFileReader(input="my_dir/", prefix="scene_") as cr:
print(cr.bands)
- >>> ['b1', 'b2']
+ >>> ['band1', 'band2']
- print(cr.info(bands=("b1", "b2")).json(exclude_none=True))
+ print(cr.info(bands=("band1", "band2")).json(exclude_none=True))
>>> {
'bounds': [-11.979244865430259, 24.296321392464325, -10.874546803397614, 25.304623891542263],
'minzoom': 7,
'maxzoom': 9,
- 'band_metadata': [('b1', {}), ('b2', {})],
- 'band_descriptions': [('b1', ''), ('b2', '')],
+ 'band_metadata': [('band1', {}), ('band2', {})],
+ 'band_descriptions': [('band1', ''), ('band2', '')],
'dtype': 'uint16',
'nodata_type': 'Nodata',
'colorinterp': ['gray', 'gray']
}
- img = cr.tile(238, 218, 9, bands=("b1", "b2"))
+ img = cr.tile(238, 218, 9, bands=("band1", "band2"))
print(img.assets)
- >>> ['my_dir/scene_b1.tif', 'my_dir/scene_b2.tif']
+ >>> ['my_dir/scene_band1.tif', 'my_dir/scene_band2.tif']
print(img.data.shape)
>>> (2, 256, 256)
@@ -227,7 +219,7 @@ Note: [`rio-tiler-pds`][rio-tiler-pds] readers are built using the `MultiBandRea
[rio-tiler-pds]: https://github.com/cogeotiff/rio-tiler-pds
-## Custom COGReader subclass
+## Custom Reader subclass
The example :point_down: was created as a response to https://github.com/developmentseed/titiler/discussions/235. In short, the user needed a way to keep metadata information from an asset within a STAC item.
@@ -239,12 +231,12 @@ But rio-tiler has been designed to be easily customizable.
import attr
from rasterio.io import DatasetReader
from rio_tiler.io.stac import fetch, _to_pystac_item
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
import pystac
@attr.s
-class CustomSTACReader(COGReader):
- """Custom COG Reader support."""
+class CustomSTACReader(Reader):
+ """Custom Reader support."""
# This will keep the STAC item info within the instance
item: pystac.Item = attr.ib(default=None, init=False)
@@ -279,7 +271,7 @@ In this `CustomSTACReader`, we are using a custom path `schema` in form of `{ite
1. Parse the input path to get the STAC url and asset name
2. Fetch and parse the STAC item
3. Construct a new `input` using the asset full url.
-4. Fall back to the regular `COGReader` initialization (using `super().__attrs_post_init__()`)
+4. Fall back to the regular `Reader` initialization (using `super().__attrs_post_init__()`)
## Simple Reader
@@ -298,7 +290,7 @@ from morecantile import TileMatrixSet
from rio_tiler.constants import BBox, WEB_MERCATOR_TMS
@attr.s
-class Reader(BaseReader):
+class SimpleReader(BaseReader):
input: DatasetReader = attr.ib()
@@ -355,6 +347,6 @@ class Reader(BaseReader):
)
with rasterio.open("file.tif") as src:
- with Reader(src) as cog:
+ with SimpleReader(src) as cog:
img = cog.tile(1, 1, 1)
```
diff --git a/docs/src/advanced/dynamic_tiler.md b/docs/src/advanced/dynamic_tiler.md
index 8e6d5d2a..896de250 100644
--- a/docs/src/advanced/dynamic_tiler.md
+++ b/docs/src/advanced/dynamic_tiler.md
@@ -20,7 +20,7 @@ your own API.
### Requirements
-- `rio-tiler ~= 3.0`
+- `rio-tiler ~= 4.0`
- `fastapi`
- `uvicorn`
@@ -49,7 +49,7 @@ from starlette.requests import Request
from starlette.responses import Response
from rio_tiler.profiles import img_profiles
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
app = FastAPI(
@@ -75,7 +75,7 @@ def tile(
url: str = Query(..., description="Cloud Optimized GeoTIFF URL."),
):
"""Handle tile requests."""
- with COGReader(url) as cog:
+ with Reader(url) as cog:
img = cog.tile(x, y, z)
content = img.render(img_format="PNG", **img_profiles.get("png"))
return Response(content, media_type="image/png")
@@ -90,7 +90,7 @@ def tilejson(
tile_url = request.url_for("tile", {"z": "{z}", "x": "{x}", "y": "{y}"})
tile_url = f"{tile_url}?url={url}"
- with COGReader(url) as cog:
+ with Reader(url) as cog:
return {
"bounds": cog.geographic_bounds,
"minzoom": cog.minzoom,
diff --git a/docs/src/advanced/feature.md b/docs/src/advanced/feature.md
index 391151e5..98877862 100644
--- a/docs/src/advanced/feature.md
+++ b/docs/src/advanced/feature.md
@@ -1,12 +1,12 @@
![](https://user-images.githubusercontent.com/10407788/105767632-3f959e80-5f29-11eb-9331-969f3f53111e.png)
-Starting with `rio-tiler` v2, a `.feature()` method exists on `rio-tiler`'s readers (e.g `COGReader`) which enables data reading for GeoJSON defined (polygon or multipolygon) shapes.
+Starting with `rio-tiler` v2, a `.feature()` method exists on `rio-tiler`'s readers (e.g `Reader`) which enables data reading for GeoJSON defined (polygon or multipolygon) shapes.
```python
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
from rio_tiler.models import ImageData
-with COGReader("my-tif.tif") as cog:
+with Reader("my-tif.tif") as cog:
# Read data for a given geojson polygon
img: ImageData = cog.feature(geojson_feature, max_size=1024) # we limit the max_size to 1024
```
@@ -15,12 +15,12 @@ Under the hood, the `.feature` method uses `GDALWarpVRT`'s `cutline` option and
the `.part()` method. The below process is roughly what `.feature` does for you.
```python
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
from rio_tiler.utils import create_cutline
from rasterio.features import bounds as featureBounds
-# Use COGReader to open and read the dataset
-with COGReader("my_tif.tif") as cog:
+# Use Reader to open and read the dataset
+with Reader("my_tif.tif") as cog:
# Create WTT Cutline
cutline = create_cutline(cog.dataset, feat, geometry_crs="epsg:4326")
@@ -36,8 +36,8 @@ Another interesting fact about the `cutline` option is that it can be used with
```python
bbox = featureBounds(feat)
-# Use COGReader to open and read the dataset
-with COGReader("my_tif.tif") as cog:
+# Use Reader to open and read the dataset
+with Reader("my_tif.tif") as cog:
# Create WTT Cutline
cutline = create_cutline(cog.dataset, feat, geometry_crs="epsg:4326")
diff --git a/docs/src/advanced/tms.md b/docs/src/advanced/tms.md
index 8d4e6b72..0e29d34a 100644
--- a/docs/src/advanced/tms.md
+++ b/docs/src/advanced/tms.md
@@ -6,12 +6,12 @@ Starting with rio-tiler 2.0, we replaced [`mercantile`][mercantile] with [_`more
```python
import morecantile
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
from rasterio.crs import CRS
from pyproj import CRS as projCRS
# By default we use WebMercator TMS
-with COGReader("my.tif") as cog:
+with Reader("my.tif") as cog:
img = cog.tile(1, 1, 1)
assert img.crs == CRS.from_epsg(3857) # default image output is the TMS crs (WebMercator)
@@ -34,7 +34,7 @@ for name, tms in morecantile.tms.tms.items():
# Use EPSG:4326 (WGS84) grid
wgs84_grid = morecantile.tms.get("WorldCRS84Quad")
-with COGReader("my.tif", tms=wgs84_grid) as cog:
+with Reader("my.tif", tms=wgs84_grid) as cog:
img = cog.tile(1, 1, 1)
assert img.crs == CRS.from_epsg(4326)
@@ -43,7 +43,7 @@ extent = [-948.75, -543592.47, 5817.41, -3333128.95] # From https:///epsg.io/30
epsg3031TMS = morecantile.TileMatrixSet.custom(
extent, projCRS.from_epsg(3031), identifier="MyCustomTmsEPSG3031"
)
-with COGReader("my.tif", tms=epsg3031TMS) as cog:
+with Reader("my.tif", tms=epsg3031TMS) as cog:
img = cog.tile(1, 1, 1)
assert img.crs == CRS.from_epsg(3031)
```
diff --git a/docs/src/advanced/zonal_stats.md b/docs/src/advanced/zonal_stats.md
index 2ff5e911..39e33eb4 100644
--- a/docs/src/advanced/zonal_stats.md
+++ b/docs/src/advanced/zonal_stats.md
@@ -12,8 +12,8 @@ from rio_tiler.models import BandStatistics
from geojson_pydantic.features import Feature, FeatureCollection
from geojson_pydantic.geometries import Polygon
-class COGReader(io.COGReader):
- """Custom COGReader with zonal_statistics method."""
+class Reader(io.Reader):
+ """Custom Reader with zonal_statistics method."""
def zonal_statistics(
self,
@@ -49,7 +49,7 @@ class COGReader(io.COGReader):
geojson = FeatureCollection(features=[geojson])
for feature in geojson:
- # Get data overlapping with the feature (using COGReader.feature method)
+ # Get data overlapping with the feature (using Reader.feature method)
data = self.feature(
feature.dict(exclude_none=True),
max_size=max_size,
diff --git a/docs/src/colormap.md b/docs/src/colormap.md
index 9799c63b..ffaf69e0 100644
--- a/docs/src/colormap.md
+++ b/docs/src/colormap.md
@@ -8,26 +8,25 @@ to `rio_tiler.utils.render`:
```python
from rio_tiler.colormap import cmap
-from rio_tiler.io import COGReader
+from rio_tiler.io import Reader
# Get Colormap
# You can list available colormap names with `cmap.list()`
cm = cmap.get("cfastie")
-with COGReader(
- "s3://landsat-pds/c1/L8/015/029/LC08_L1GT_015029_20200119_20200119_01_RT/LC08_L1GT_015029_20200119_20200119_01_RT_B8.TIF",
- nodata=0,
-) as cog:
- img = cog.tile(150, 187, 9)
+with Reader(
+ "https://sentinel-cogs.s3.amazonaws.com/sentinel-s2-l2a-cogs/29/R/KH/2020/2/S2A_29RKH_20200219_0_L2A/B01.tif",
+) as src:
+ img = src.tile(239, 220, 9)
# Rescale the data linearly from 0-10000 to 0-255
- image_rescale = img.post_process(
+ img.rescale(
in_range=((0, 10000),),
out_range=((0, 255),)
)
# Apply colormap and create a PNG buffer
- buff = image_rescale.render(colormap=cm) # this returns a buffer (PNG by default)
+ buff = img.render(colormap=cm) # this returns a buffer (PNG by default)
```
The `render` method accept colormap in form of:
diff --git a/docs/src/examples/Using-nonEarth-dataset.ipynb b/docs/src/examples/Using-nonEarth-dataset.ipynb
index 070abace..48e287cf 100644
--- a/docs/src/examples/Using-nonEarth-dataset.ipynb
+++ b/docs/src/examples/Using-nonEarth-dataset.ipynb
@@ -21,7 +21,7 @@
"# Requirements\n",
"\n",
"To be able to run this notebook you'll need the following requirements:\n",
- "- rio-tiler~= 3.0\n",
+ "- rio-tiler~=4.0\n",
"- ipyleaflet\n",
"- matplotlib"
]
@@ -44,14 +44,14 @@
"outputs": [],
"source": [
"%pylab inline\n",
- "from rio_tiler.io import COGReader\n",
+ "from rio_tiler.io import Reader\n",
"\n",
"# In order to fully work, we'll need to build a custom TileMatrixSet\n",
"from morecantile import TileMatrixSet\n",
"from pyproj import CRS\n",
"\n",
"# For this DEMO we will use this file\n",
- "src_path = \"https://asc-jupiter.s3-us-west-2.amazonaws.com/europa/galileo_voyager/controlled_mosaics/11ESCOLORS01-02_GalileoSSI_Equi-cog.tif\""
+ "src_path = \"https://raw.githubusercontent.com/cogeotiff/rio-tiler/master/tests/fixtures/cog_nonearth.tif\""
]
},
{
@@ -60,12 +60,12 @@
"metadata": {},
"outputs": [],
"source": [
- "\n",
"# Let's first try with default\n",
- "# We should see 2 different warnings here\n",
- "# - UserWarning: Cannot dertermine min/max zoom based on dataset informations: We cannot get default Zooms in WebMercator projection\n",
+ "# We should see 3 different warnings here\n",
"# - UserWarning: Cannot dertermine bounds in WGS84: There is no existing transformation to WGS84\n",
- "with COGReader(src_path) as cog:\n",
+ "# - UserWarning: Cannot dertermine minzoom based on dataset informations: We cannot get default Zooms in WebMercator projection\n",
+ "# - UserWarning: Cannot dertermine maxzoom based on dataset informations: We cannot get default Zooms in WebMercator projection\n",
+ "with Reader(src_path) as cog:\n",
" print(cog.info().json())"
]
},
@@ -75,7 +75,6 @@
"metadata": {},
"outputs": [],
"source": [
- "\n",
"# Create a CUSTOM TMS using the europa ESRI:104915 projection\n",
"europa_crs = CRS.from_authority(\"ESRI\", 104915)\n",
"europa_tms = TileMatrixSet.custom(\n",
@@ -85,8 +84,8 @@
"# Use Custom TMS instead of Web Mercator\n",
"# We should see 2 different warnings here\n",
"# - UserWarning: Could not create coordinate Transformer from input CRS to WGS84: This is from morecantile. It means some methods won't be available but we can ignore. \n",
- "# - UserWarning: Cannot dertermine bounds in WGS84: Same as before. the `cog.geographic` property will return default (-180.0, -90.0, 180.0, 90.0)\n",
- "with COGReader(src_path, tms=europa_tms) as cog:\n",
+ "# - UserWarning: Cannot dertermine bounds in WGS84: Same as before. the `cog.geographic_bounds` property will return default (-180.0, -90.0, 180.0, 90.0)\n",
+ "with Reader(src_path, tms=europa_tms) as cog:\n",
" print(cog.info().json())\n",
" img = cog.preview()\n",
" imshow(img.data_as_image())"
@@ -95,20 +94,22 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {},
+ "metadata": {
+ "scrolled": false
+ },
"outputs": [],
"source": [
"# Read a Tile\n",
"from rasterio.warp import transform_bounds\n",
"\n",
- "with COGReader(src_path, tms=europa_tms) as cog:\n",
+ "with Reader(src_path, tms=europa_tms) as cog:\n",
" # get dataset bounds in TMS's CRS projection\n",
" bounds_in_tms = transform_bounds(cog.crs, europa_tms.rasterio_crs, *cog.bounds)\n",
" tile = cog.tms._tile(bounds_in_tms[0], bounds_in_tms[1], cog.minzoom)\n",
" print(tile)\n",
"\n",
" img = cog.tile(tile.x, tile.y, tile.z)\n",
- " imshow(img.data_as_image())\n"
+ " imshow(img.data_as_image())"
]
},
{
@@ -150,7 +151,7 @@
"from tornado.httpserver import HTTPServer\n",
"from tornado.concurrent import run_on_executor\n",
"\n",
- "from rio_tiler.io import COGReader\n",
+ "from rio_tiler.io import Reader\n",
"from rio_tiler.errors import TileOutsideBounds\n",
"from rio_tiler.profiles import img_profiles\n",
"\n",
@@ -195,7 +196,7 @@
" def _get_tile(self, z, x, y):\n",
"\n",
" try:\n",
- " with COGReader(self.url, tms=europa_tms) as cog:\n",
+ " with Reader(self.url, tms=europa_tms) as cog:\n",
" data = cog.tile(x, y, z)\n",
" except TileOutsideBounds:\n",
" raise web.HTTPError(404)\n",
@@ -267,7 +268,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -281,7 +282,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.2"
+ "version": "3.9.13"
}
},
"nbformat": 4,
diff --git a/docs/src/examples/Using-rio-tiler-STACReader.ipynb b/docs/src/examples/Using-rio-tiler-STACReader.ipynb
index 43169315..6354400e 100644
--- a/docs/src/examples/Using-rio-tiler-STACReader.ipynb
+++ b/docs/src/examples/Using-rio-tiler-STACReader.ipynb
@@ -53,7 +53,7 @@
"source": [
"from rio_tiler.io import STACReader\n",
"from rio_tiler.profiles import img_profiles\n",
- "from rio_tiler.models import ImageData, Metadata"
+ "from rio_tiler.models import ImageData"
]
},
{
@@ -191,10 +191,10 @@
"source": [
"fig, axs = plt.subplots(1, 4, sharey=True, tight_layout=True, dpi=150)\n",
"\n",
- "axs[0].plot(meta[\"B01\"][\"1\"].histogram[1][0:-1], meta[\"B01\"][\"1\"].histogram[0])\n",
- "axs[1].plot(meta[\"B02\"][\"1\"].histogram[1][0:-1], meta[\"B02\"][\"1\"].histogram[0])\n",
- "axs[2].plot(meta[\"B03\"][\"1\"].histogram[1][0:-1], meta[\"B03\"][\"1\"].histogram[0])\n",
- "axs[3].plot(meta[\"B04\"][\"1\"].histogram[1][0:-1], meta[\"B04\"][\"1\"].histogram[0])"
+ "axs[0].plot(meta[\"B01\"][\"b1\"].histogram[1][0:-1], meta[\"B01\"][\"b1\"].histogram[0])\n",
+ "axs[1].plot(meta[\"B02\"][\"b1\"].histogram[1][0:-1], meta[\"B02\"][\"b1\"].histogram[0])\n",
+ "axs[2].plot(meta[\"B03\"][\"b1\"].histogram[1][0:-1], meta[\"B03\"][\"b1\"].histogram[0])\n",
+ "axs[3].plot(meta[\"B04\"][\"b1\"].histogram[1][0:-1], meta[\"B04\"][\"b1\"].histogram[0])"
]
},
{
@@ -256,11 +256,12 @@
"outputs": [],
"source": [
"# The sentinel data is stored as UInt16, we need to do some data rescaling to display data from 0 to 255\n",
- "print(img.data.min(), img.data.max())\n",
+ "print(img.data.min(), img.data.max())x\n",
+ "\n",
+ "img.rescale(in_range=((0, 10000),))\n",
+ "print(img.min(), img.max())\n",
"\n",
- "image = img.post_process(in_range=((0, 10000),))\n",
- "image = image.data_as_image()\n",
- "print(image.min(), image.max())\n",
+ "image = img.data_as_image()\n",
"imshow(image)"
]
},
@@ -279,14 +280,16 @@
"source": [
"with STACReader(src_path) as stac:\n",
" # By default `preview()` will return an array with its longest dimension lower or equal to 1024px\n",
- " img = stac.preview(expression=\"(B08-B04)/(B08+B04)\", max_size=256)\n",
+ " img = stac.preview(expression=\"(B08_b1-B04_b1)/(B08_b1+B04_b1)\", max_size=256)\n",
" print(img.data.shape)\n",
" # learn more about the ImageData model https://cogeotiff.github.io/rio-tiler/models/#imagedata\n",
" assert isinstance(img, ImageData)\n",
"\n",
"# NDVI data range should be between -1 and 1\n",
- "image = img.post_process(in_range=((-1,1),))\n",
- "image = image.data_as_image()\n",
+ "print(img.data.min(), img.data.max())\n",
+ "\n",
+ "img.rescale(in_range=((-1,1),))\n",
+ "image = img.data_as_image()\n",
"imshow(image)"
]
},
@@ -303,7 +306,8 @@
"hash": "e5a596c8625da0593f23bdd5ea51ce5c4572779fa5edc69fb6a18fc94feb7fb6"
},
"kernelspec": {
- "display_name": "Python 3.8.2 64-bit",
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
"name": "python3"
},
"language_info": {
@@ -316,7 +320,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.2"
+ "version": "3.9.13"
}
},
"nbformat": 4,
diff --git a/docs/src/examples/Using-rio-tiler-XarrayReader.ipynb b/docs/src/examples/Using-rio-tiler-XarrayReader.ipynb
new file mode 100644
index 00000000..0eb3085c
--- /dev/null
+++ b/docs/src/examples/Using-rio-tiler-XarrayReader.ipynb
@@ -0,0 +1,972 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "45bf509c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import xarray\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "from rio_tiler.io.xarray import XarrayReader"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d2c1f9bd",
+ "metadata": {},
+ "source": [
+ "### daymet"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "feb70fe3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "
<xarray.Dataset>\n",
+ "Dimensions: (time: 1, y: 3728, x: 17268)\n",
+ "Coordinates:\n",
+ " lambert_conformal_conic int64 0\n",
+ " * time (time) datetime64[ns] 1980-07-01T12:00:00\n",
+ " * x (x) float64 -180.0 -180.0 -179.9 ... 180.0 180.0\n",
+ " * y (y) float64 83.78 83.76 83.74 ... 6.126 6.105 6.084\n",
+ "Data variables:\n",
+ " tmax (time, y, x) float32 ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.6\n",
+ " Version_data: Daymet Data Version 4.0\n",
+ " Version_software: Daymet Software Version 4.0\n",
+ " citation: Please see http://daymet.ornl.gov/ for current Daymet ...\n",
+ " references: Please see http://daymet.ornl.gov/ for current informa...\n",
+ " source: Daymet Software Version 4.0\n",
+ " start_year: 1980
"
+ ],
+ "text/plain": [
+ "\n",
+ "Dimensions: (time: 1, y: 3728, x: 17268)\n",
+ "Coordinates:\n",
+ " lambert_conformal_conic int64 ...\n",
+ " * time (time) datetime64[ns] 1980-07-01T12:00:00\n",
+ " * x (x) float64 -180.0 -180.0 -179.9 ... 180.0 180.0\n",
+ " * y (y) float64 83.78 83.76 83.74 ... 6.126 6.105 6.084\n",
+ "Data variables:\n",
+ " tmax (time, y, x) float32 ...\n",
+ "Attributes:\n",
+ " Conventions: CF-1.6\n",
+ " Version_data: Daymet Data Version 4.0\n",
+ " Version_software: Daymet Software Version 4.0\n",
+ " citation: Please see http://daymet.ornl.gov/ for current Daymet ...\n",
+ " references: Please see http://daymet.ornl.gov/ for current informa...\n",
+ " source: Daymet Software Version 4.0\n",
+ " start_year: 1980"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ds = xarray.open_dataset(\n",
+ " \"https://pangeo.blob.core.windows.net/pangeo-public/daymet-rio-tiler/na-wgs84.zarr/\",\n",
+ " engine=\"zarr\",\n",
+ " decode_coords=\"all\",\n",
+ " consolidated=True,\n",
+ ")\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "cafd96de",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "
<xarray.DataArray 'tmax' (time: 1, y: 3728, x: 17268)>\n",
+ "[64375104 values with dtype=float32]\n",
+ "Coordinates:\n",
+ " lambert_conformal_conic int64 0\n",
+ " * time (time) datetime64[ns] 1980-07-01T12:00:00\n",
+ " * x (x) float64 -180.0 -180.0 -179.9 ... 180.0 180.0\n",
+ " * y (y) float64 83.78 83.76 83.74 ... 6.126 6.105 6.084\n",
+ "Attributes:\n",
+ " cell_methods: area: mean time: maximum within days time: mean over days\n",
+ " coordinates: lon lat\n",
+ " long_name: annual average of daily maximum temperature\n",
+ " units: degrees C
"
+ ],
+ "text/plain": [
+ "\n",
+ "[64375104 values with dtype=float32]\n",
+ "Coordinates:\n",
+ " lambert_conformal_conic int64 0\n",
+ " * time (time) datetime64[ns] 1980-07-01T12:00:00\n",
+ " * x (x) float64 -180.0 -180.0 -179.9 ... 180.0 180.0\n",
+ " * y (y) float64 83.78 83.76 83.74 ... 6.126 6.105 6.084\n",
+ "Attributes:\n",
+ " cell_methods: area: mean time: maximum within days time: mean over days\n",
+ " coordinates: lon lat\n",
+ " long_name: annual average of daily maximum temperature\n",
+ " units: degrees C"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "da = ds[\"tmax\"]\n",
+ "da"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "d29e0c33",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "bounds=BoundingBox(left=-179.99998449579846, bottom=6.073484821356791, right=179.98170598363066, top=83.79467217916716) minzoom=1 maxzoom=6 band_metadata=[('b1', {'long_name': '24-hour day based on local time', 'standard_name': 'time'})] band_descriptions=[('b1', '1980-07-01T12:00:00.000000000')] dtype='float32' nodata_type='Nodata' colorinterp=None scale=None offset=None colormap=None attrs={'cell_methods': 'area: mean time: maximum within days time: mean over days', 'coordinates': 'lon lat', 'long_name': 'annual average of daily maximum temperature', 'units': 'degrees C'} height=3728 count=1 name='tmax' width=17268\n"
+ ]
+ }
+ ],
+ "source": [
+ "da = ds[\"tmax\"]\n",
+ "with XarrayReader(da) as dst:\n",
+ " print(dst.info())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "93d11d9c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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3LlzceaZZ2LHjh1Rm3379mH16tU48MADsf/+++Pss8/Grl27ojbPPPMMzjjjDMyYMQNz587FFVdcgWazOejBH6A05iQJZqgE01SCurKXY12Hg+6OEEJIBRiUcG3duhWrV6/GAw88gM2bN6PRaGD58uXYu3evb3PZZZfhBz/4Ab797W9j69atePbZZ3HWWWf5/Wma4owzzkBvby/uv/9+3Hbbbbj11ltx3XXXDXrwNaUxTVlvZwpBQ6ydlQotLkIImawoERmybfLCCy9g7ty52Lp1K0477TTs2bMHBx98MG6//Xb88R//MQDg17/+NY4++mhs27YNp5xyCu644w68733vw7PPPot58+YBAG6++WZcddVVeOGFF9DR0dHvebu7uzFr1ix07TgEcw6o4zXpxauSoje7lB4BekXj2EP/baiXRgghZBRxz/E9e/Zg5syZgzp2WDGuPXv2AADmzJkDANi+fTsajQaWLVvm2xx11FE49NBDsW3bNgDAtm3bcPzxx3vRAoAVK1agu7sbjz32WOl5enp60N3dHb0A4DXTwIvmNbwqdiZXAjvpuFc0GtUO3xFCCGnDkJ/uxhhceumlOPXUU3HccccBALq6utDR0YHZs2dHbefNm4euri7fJhQtt9/tK2PDhg2YNWuWfx1yyCEAgAYEvZK/XFKGgYIRNdRLI4QQMoEZcjr86tWr8eijj+K+++4byfGUsm7dOqxdu9Z/7+7uxiGHHIJeEdSRCxTT3wkhZPIzJOFas2YNfvjDH+Lee+/F61//er99/vz56O3txe7duyOra9euXZg/f75v89Of/jTqz2UdujZFOjs70dnZ2bK9IfaVgtYVIYRMFQblKhQRrFmzBt/97ndx1113YdGiRdH+k046CfV6HVu2bPHbduzYgWeeeQZLliwBACxZsgSPPPIInn/+ed9m8+bNmDlzJo455phBDV5gRSsV+yKEEDL5GZTFtXr1atx+++34/ve/jwMOOMDHpGbNmoXp06dj1qxZuPDCC7F27VrMmTMHM2fOxCc+8QksWbIEp5xyCgBg+fLlOOaYY/CRj3wEGzduRFdXF6655hqsXr261KrqC1Z9J4SQqceg0uGVKrdqbrnlFnz0ox8FYCcgX3755fjWt76Fnp4erFixAt/4xjciN+DTTz+NSy65BPfccw/2228/nH/++bjxxhtRqw1MR10a5QOPzsfiYxnXIoSQqjGcdPhhzeMaL4ZzwYQQQsafcZvHRQghhIw1FC5CCCGVgsJFCCGkUlC4CCGEVAoKFyGEkEpB4SKEEFIpKFyEEEIqBYWLEEJIpaBwEUIIqRQULkIIIZWCwkUIIaRSULgIIYRUCgoXIYSQSkHhIoQQUikoXIQQQioFhYsQQkiloHARQgipFBQuQgghlYLCRQghpFJQuAghhFQKChchhJBKQeEihBBSKShchBBCKgWFixBCSKWgcBFCCKkUFC5CCCGVgsJFCCGkUlC4CCGEVAoKFyGEkEpB4SKEEFIpKFyEEEIqBYWLEEJIpaBwEUIIqRQULkIIIZWCwkUIIaRSULgIIYRUCgoXIYSQSkHhIoQQUikoXIQQQioFhYsQQkiloHARQgipFBQuQgghlYLCRQghpFJQuAghhFQKChchhJBKQeEihBBSKShchBBCKgWFixBCSKWgcBFCCKkUFC5CCCGVgsJFCCGkUlC4CCGEVAoKFyGEkEpB4SKEEFIpKFyEEEIqBYWLEEJIpaBwEUIIqRQULkIIIZWCwkUIIaRSULgIIYRUCgoXIYSQSjEo4dqwYQNOPvlkHHDAAZg7dy7OPPNM7NixI2pz+umnQykVvT7+8Y9HbZ555hmcccYZmDFjBubOnYsrrrgCzWZz+FdDCCFk0lMbTOOtW7di9erVOPnkk9FsNnH11Vdj+fLl+NWvfoX99tvPt7vooovwmc98xn+fMWOG/5ymKc444wzMnz8f999/P5577jn86Z/+Ker1Or7whS+MwCURQgiZzCgRkaEe/MILL2Du3LnYunUrTjvtNADW4nrzm9+Mr3zlK6XH3HHHHXjf+96HZ599FvPmzQMA3HzzzbjqqqvwwgsvoKOjo9/zdnd3Y9asWdizZw9mzpw51OETQggZJ4bzHB9WjGvPnj0AgDlz5kTbv/nNb+Kggw7Ccccdh3Xr1uHVV1/1+7Zt24bjjz/eixYArFixAt3d3XjsscdKz9PT04Pu7u7oRQghZGoyKFdhiDEGl156KU499VQcd9xxfvuHP/xhHHbYYVi4cCEefvhhXHXVVdixYwe+853vAAC6uroi0QLgv3d1dZWea8OGDVi/fv1Qh0oIIWQSMWThWr16NR599FHcd9990faLL77Yfz7++OOxYMECLF26FE8++SSOOOKIIZ1r3bp1WLt2rf/e3d2NQw45ZGgDJ4QQUmmG5Cpcs2YNfvjDH+Luu+/G61//+j7bLl68GACwc+dOAMD8+fOxa9euqI37Pn/+/NI+Ojs7MXPmzOhFCCFkajIo4RIRrFmzBt/97ndx1113YdGiRf0e89BDDwEAFixYAABYsmQJHnnkETz//PO+zebNmzFz5kwcc8wxgxkOIYSQKcigXIWrV6/G7bffju9///s44IADfExq1qxZmD59Op588kncfvvteO9734sDDzwQDz/8MC677DKcdtppOOGEEwAAy5cvxzHHHIOPfOQj2LhxI7q6unDNNddg9erV6OzsHPkrJIQQMqkYVDq8Uqp0+y233IKPfvSj+O1vf4s/+ZM/waOPPoq9e/fikEMOwQc/+EFcc801kXvv6aefxiWXXIJ77rkH++23H84//3zceOONqNUGpqNMhyeEkGoznOf4sOZxjRcULkIIqTbDeY4POatwPHFay/lchBBSTdzzeyi2UyWF6+WXXwYApsQTQkjFefnllzFr1qxBHVNJV6ExBjt27MAxxxyD3/72t3QXluDmuvH+lMP70ze8P/3De9Q3/d0fEcHLL7+MhQsXQuvBzcyqpMWltcbrXvc6AOC8rn7g/ekb3p++4f3pH96jvunr/gzW0nJwPS5CCCGVgsJFCCGkUlRWuDo7O3H99ddz0nIbeH/6hvenb3h/+of3qG9G8/5UMjmDEELI1KWyFhchhJCpCYWLEEJIpaBwEUIIqRQULkIIIZWiksL19a9/HW94wxswbdo0LF68GD/96U/He0jjwg033AClVPQ66qij/P59+/Zh9erVOPDAA7H//vvj7LPPblnEc7Jx77334v3vfz8WLlwIpRS+973vRftFBNdddx0WLFiA6dOnY9myZXjiiSeiNi+99BLOO+88zJw5E7Nnz8aFF16IV155ZQyvYvTo7/589KMfbfk3tXLlyqjNZL0/GzZswMknn4wDDjgAc+fOxZlnnokdO3ZEbQbyf+qZZ57BGWecgRkzZmDu3Lm44oor0Gw2x/JSRo2B3KPTTz+95d/Qxz/+8ajNcO9R5YTr7//+77F27Vpcf/31+MUvfoETTzwRK1asiBamnEoce+yxeO655/zrvvvu8/suu+wy/OAHP8C3v/1tbN26Fc8++yzOOuuscRzt6LN3716ceOKJ+PrXv166f+PGjfjqV7+Km2++GQ8++CD2228/rFixAvv27fNtzjvvPDz22GPYvHkzfvjDH+Lee+/FxRdfPFaXMKr0d38AYOXKldG/qW9961vR/sl6f7Zu3YrVq1fjgQcewObNm9FoNLB8+XLs3bvXt+nv/1SapjjjjDPQ29uL+++/H7fddhtuvfVWXHfddeNxSSPOQO4RAFx00UXRv6GNGzf6fSNyj6RivP3tb5fVq1f772maysKFC2XDhg3jOKrx4frrr5cTTzyxdN/u3bulXq/Lt7/9bb/t8ccfFwCybdu2MRrh+AJAvvvd7/rvxhiZP3++fPGLX/Tbdu/eLZ2dnfKtb31LRER+9atfCQD52c9+5tvccccdopSSf/u3fxuzsY8FxfsjInL++efLBz7wgbbHTKX78/zzzwsA2bp1q4gM7P/U//k//0e01tLV1eXb/NVf/ZXMnDlTenp6xvYCxoDiPRIRede73iV//ud/3vaYkbhHlbK4ent7sX37dixbtsxv01pj2bJl2LZt2ziObPx44oknsHDhQhx++OE477zz8MwzzwAAtm/fjkajEd2ro446CoceeuiUvVdPPfUUurq6onsya9YsLF682N+Tbdu2Yfbs2Xjb297m2yxbtgxaazz44INjPubx4J577sHcuXNx5JFH4pJLLsGLL77o902l+7Nnzx4AwJw5cwAM7P/Utm3bcPzxx2PevHm+zYoVK9Dd3Y3HHntsDEc/NhTvkeOb3/wmDjroIBx33HFYt24dXn31Vb9vJO5RpYrs/vu//zvSNI0uGADmzZuHX//61+M0qvFj8eLFuPXWW3HkkUfiueeew/r16/HOd74Tjz76KLq6utDR0YHZs2dHx8ybNw9dXV3jM+Bxxl132b8ft6+rqwtz586N9tdqNcyZM2dK3LeVK1firLPOwqJFi/Dkk0/i6quvxqpVq7Bt2zYkSTJl7o8xBpdeeilOPfVUHHfccQAwoP9TXV1dpf++3L7JRNk9AoAPf/jDOOyww7Bw4UI8/PDDuOqqq7Bjxw585zvfATAy96hSwkViVq1a5T+fcMIJWLx4MQ477DD8wz/8A6ZPnz6OIyNV5ZxzzvGfjz/+eJxwwgk44ogjcM8992Dp0qXjOLKxZfXq1Xj00UejmDGJaXePwnjn8ccfjwULFmDp0qV48sknccQRR4zIuSvlKjzooIOQJElLFs+uXbswf/78cRrVxGH27Nl405vehJ07d2L+/Pno7e3F7t27ozZT+V656+7r38/8+fNbEn2azSZeeumlKXnfDj/8cBx00EHYuXMngKlxf9asWYMf/vCHuPvuu/H617/ebx/I/6n58+eX/vty+yYL7e5RGYsXLwaA6N/QcO9RpYSro6MDJ510ErZs2eK3GWOwZcsWLFmyZBxHNjF45ZVX8OSTT2LBggU46aSTUK/Xo3u1Y8cOPPPMM1P2Xi1atAjz58+P7kl3dzcefPBBf0+WLFmC3bt3Y/v27b7NXXfdBWOM/w84lfjd736HF198EQsWLAAwue+PiGDNmjX47ne/i7vuuguLFi2K9g/k/9SSJUvwyCOPROK+efNmzJw5E8ccc8zYXMgo0t89KuOhhx4CgOjf0LDv0RCTScaNv/u7v5POzk659dZb5Ve/+pVcfPHFMnv27ChDZapw+eWXyz333CNPPfWU/NM//ZMsW7ZMDjroIHn++edFROTjH/+4HHrooXLXXXfJz3/+c1myZIksWbJknEc9urz88svyy1/+Un75y18KALnpppvkl7/8pTz99NMiInLjjTfK7Nmz5fvf/748/PDD8oEPfEAWLVokr732mu9j5cqV8pa3vEUefPBBue++++SNb3yjnHvuueN1SSNKX/fn5Zdflk9+8pOybds2eeqpp+QnP/mJvPWtb5U3vvGNsm/fPt/HZL0/l1xyicyaNUvuueceee655/zr1Vdf9W36+z/VbDbluOOOk+XLl8tDDz0kd955pxx88MGybt268bikEae/e7Rz5075zGc+Iz//+c/lqaeeku9///ty+OGHy2mnneb7GIl7VDnhEhH52te+Joceeqh0dHTI29/+dnnggQfGe0jjwoc+9CFZsGCBdHR0yOte9zr50Ic+JDt37vT7X3vtNfmzP/sz+b3f+z2ZMWOGfPCDH5TnnntuHEc8+tx9990CoOV1/vnni4hNib/22mtl3rx50tnZKUuXLpUdO3ZEfbz44oty7rnnyv777y8zZ86UCy64QF5++eVxuJqRp6/78+qrr8ry5cvl4IMPlnq9LocddphcdNFFLT8KJ+v9KbsvAOSWW27xbQbyf+o3v/mNrFq1SqZPny4HHXSQXH755dJoNMb4akaH/u7RM888I6eddprMmTNHOjs75fd///fliiuukD179kT9DPcecVkTQgghlaJSMS5CCCGEwkUIIaRSULgIIYRUCgoXIYSQSkHhIoQQUikoXIQQQioFhYsQQkiloHARQgipFBQuQgghlYLCRQghpFJQuAghhFQKChchhJBK8f8DrW8dU/uBssAAAAAASUVORK5CYII=",
+ "text/plain": [
+ "