Create a custom tile server¶
cog_worker can be used to create a custom tile server that executes complex analyses on the fly.
1. Install dependencies¶
We’ll set up a simple server with fastapi
. We also use morecantile
to enable custom tile matrix sets, though using the default Manager parameters will give you a standard web mercator tiler.
[11]:
# if necessary
#!pip3 install --quiet morecantile
#!pip3 install --quiet fastapi[all]
2. Extend the Manager class¶
Extend the cog_worker.Manager class to add a tiling function.
[12]:
from typing import Iterable, Mapping, Tuple, Any
from cog_worker import Manager, WorkerFunction, BoundingBox
from rasterio.crs import CRS
import morecantile
class TileManager(Manager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tms = morecantile.TileMatrixSet.custom(
self._proj_bounds, CRS.from_user_input(self.proj)
)
def tile(
self,
f: WorkerFunction,
f_args: Iterable = None,
f_kwargs: Mapping = None,
z: int = 0,
x: int = 0,
y: int = 0,
tilesize: int = 256,
**kwargs
) -> Tuple[Any, BoundingBox]:
"""Execute a function for the scale and bounds of a TMS tile.
The tile method supports non-global and non-mercator tiling schemes via
Morecantile. To generate standard web tiles, instantiate the Manager
with the default parameters.
Args:
f (:obj:`cog_worker.types.WorkerFunction`): The function to execute. The function will
recieve a cog_worker.worker.Worker as its first argument.
f_args (list): Additional arguments to pass to the function.
f_kwargs (dict): Additional keyword arguments to pass to the function.
bounds (BoundingBox): The region to analize (default: self.bounds)
max_size (int): The maximum size (width or height) in pixels to compute, ignoring any buffer
(default: 1024px). Automatically reduces the scale of analysis to fit within `max_size`.
**kwargs: Additional keyword arguments to overload the Manager's properties.
(buffer).
Returns:
A tuple containing the return value of the function and the bounding
box of the executed analysis in the target projection.
"""
# get the bounds of the tile
proj_bounds = self.tms.xy_bounds(x, y, z)
left, bottom, right, top = proj_bounds
# set the scale to equal the tilesize
size = max(right - left, top - bottom)
scale = size / tilesize
kwargs.update(
{
"proj_bounds": proj_bounds,
"scale": scale,
}
)
# execute the analysis as normal
return self.execute(f, f_args, f_kwargs, **kwargs)
3. Create a FastAPI app¶
Define an endpoint that executes a WorkerFunction for a tile.
[13]:
from fastapi import FastAPI, Response
from rio_tiler.utils import render
app = FastAPI()
def read_cog(worker):
return worker.read('example-cog.tif')
functions = {
'read': read_cog
}
@app.get("/tile/{function}/{z}/{x}/{y}.png")
async def tile(
function: str,
z: int,
x: int,
y: int
):
f = functions[function]
arr, bbox = TileManager().tile(f, z=z, x=x, y=y)
img = render(arr)
return Response(img, media_type="image/png")
4. Run the app¶
Copy the code to a
main.py
.Run the app with
uvicorn main:app --reload
Check the endpoint at
http://localhost:8000/tile/read/0/0/0.png
🎉
Learn more about building a FastAPI app at https://fastapi.tiangolo.com.