demo
titiler.PgSTAC Demo¶
This Notebook aims to show the different features provided by titiler.pgstac application
In order to run this demo you'll need to have a PgSTAC database and the titiler.pgstac application running. The easiest way to launch them is to use the repo's docker-compose.yml
docker compose up tiler
Python requirements¶
pip install httpx folium pypgstac psycopg psycopg-pool geojson-pydantic
Populate the PgSTAC db with data¶
$ pypgstac load collections tests/fixtures/noaa-emergency-response.json --dsn postgresql://username:password@localhost:5439/postgis --method insert
$ pypgstac load items tests/fixtures/noaa-eri-nashville2020.json --dsn postgresql://username:password@localhost:5439/postgis --method insert
In [1]:
Copied!
import json
import httpx
from folium import Map, TileLayer, GeoJson
from geojson_pydantic import Feature, Polygon
endpoint = "http://127.0.0.1:8081"
print(httpx.get(f"{endpoint}/healthz").json())
import json
import httpx
from folium import Map, TileLayer, GeoJson
from geojson_pydantic import Feature, Polygon
endpoint = "http://127.0.0.1:8081"
print(httpx.get(f"{endpoint}/healthz").json())
{'database_online': True}
In [3]:
Copied!
# bounds of the noaa-eri-nashville2020.json items
bounds = (-87.0251, 36.0999, -85.4249, 36.2251)
poly = Polygon.from_bounds(*bounds)
geojson = Feature(type="Feature", geometry=poly, properties=None).model_dump(exclude_none=True)
m = Map(
tiles="OpenStreetMap",
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=8
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
m
# bounds of the noaa-eri-nashville2020.json items
bounds = (-87.0251, 36.0999, -85.4249, 36.2251)
poly = Polygon.from_bounds(*bounds)
geojson = Feature(type="Feature", geometry=poly, properties=None).model_dump(exclude_none=True)
m = Map(
tiles="OpenStreetMap",
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=8
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
m
Out[3]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Register Search query¶
In [4]:
Copied!
search_request = {
# Filter collection
"collections": ["noaa-emergency-response"],
# limit bounds of the known items (note: the bbox will also be used in the tilejson response)
"bbox": bounds,
"filter-lang": "cql-json",
}
response = httpx.post(
f"{endpoint}/mosaic/register", json=search_request,
).json()
print(response)
searchid = response["id"]
search_request = {
# Filter collection
"collections": ["noaa-emergency-response"],
# limit bounds of the known items (note: the bbox will also be used in the tilejson response)
"bbox": bounds,
"filter-lang": "cql-json",
}
response = httpx.post(
f"{endpoint}/mosaic/register", json=search_request,
).json()
print(response)
searchid = response["id"]
{'searchid': '6d436413d0eed760acc2f6bd16ca77a5', 'links': [{'rel': 'metadata', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/6d436413d0eed760acc2f6bd16ca77a5/info'}, {'rel': 'tilejson', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/6d436413d0eed760acc2f6bd16ca77a5/tilejson.json'}]}
Show list of Mosaics¶
In [5]:
Copied!
response = httpx.get(f"{endpoint}/mosaic/list").json()
print(
[
search["search"]["hash"]
for search in response["searches"]
]
)
response = httpx.get(f"{endpoint}/mosaic/list").json()
print(
[
search["search"]["hash"]
for search in response["searches"]
]
)
['b2b4e952ae7a8dd69cd11d595b398945', '6d436413d0eed760acc2f6bd16ca77a5']
Get Search Metadata¶
In [6]:
Copied!
info_response = httpx.get(f"{endpoint}/mosaic/{searchid}/info").json()
print(info_response)
info_response = httpx.get(f"{endpoint}/mosaic/{searchid}/info").json()
print(info_response)
{'search': {'hash': '6d436413d0eed760acc2f6bd16ca77a5', 'search': {'bbox': [-87.0251, 36.0999, -85.4249, 36.2251], 'collections': ['noaa-emergency-response'], 'filter-lang': 'cql-json'}, '_where': "collection = ANY ('{noaa-emergency-response}') AND st_intersects(geometry, '0103000020E610000001000000050000004BC8073D9BC155C0696FF085C90C42404BC8073D9BC155C0302AA913D01C42408104C58F315B55C0302AA913D01C42408104C58F315B55C0696FF085C90C42404BC8073D9BC155C0696FF085C90C4240')", 'orderby': 'datetime DESC, id DESC', 'lastused': '2023-05-24T10:09:15.184690+00:00', 'usecount': 1, 'metadata': {'type': 'mosaic'}}, 'links': [{'rel': 'self', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/6d436413d0eed760acc2f6bd16ca77a5/info'}, {'rel': 'tilejson', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/6d436413d0eed760acc2f6bd16ca77a5/tilejson.json'}]}
Get TileJSON¶
Note: to return a valid tilejson document you'll need to pass either the assets
or expression
option.
In [7]:
Copied!
tj_response = httpx.get(f"{endpoint}/mosaic/{searchid}/tilejson.json?assets=cog").json()
print(tj_response)
tj_response = httpx.get(f"{endpoint}/mosaic/{searchid}/tilejson.json?assets=cog").json()
print(tj_response)
{'tilejson': '2.2.0', 'name': '6d436413d0eed760acc2f6bd16ca77a5', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['http://127.0.0.1:8081/mosaic/6d436413d0eed760acc2f6bd16ca77a5/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=cog'], 'minzoom': 0, 'maxzoom': 24, 'bounds': [-87.0251, 36.0999, -85.4249, 36.2251], 'center': [-86.225, 36.162499999999994, 0]}
Load tiles¶
In [8]:
Copied!
m = Map(
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=14
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
aod_layer = TileLayer(
tiles=tj_response["tiles"][0],
attr="Mosaic",
min_zoom=14,
max_zoom=18,
max_native_zoom=18,
)
aod_layer.add_to(m)
m
m = Map(
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=14
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
aod_layer = TileLayer(
tiles=tj_response["tiles"][0],
attr="Mosaic",
min_zoom=14,
max_zoom=18,
max_native_zoom=18,
)
aod_layer.add_to(m)
m
Out[8]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Register a Mosaic with Metadata¶
In [9]:
Copied!
search_request = {
# Filter collection
"collections": ["noaa-emergency-response"],
# limit bounds of the known items (note: the bbox will also be used in the tilejson response)
"bbox": bounds,
"filter-lang": "cql-json",
"metadata": {
"bounds": [-87.0251, 36.0999, -85.4249, 36.2251], # This is redondant because it's in the bbox filter
"minzoom": 14,
"maxzoom": 18,
"assets": ["cog"],
"defaults": {
"true_color": {
"bidx": [1, 2, 3],
},
},
},
}
response = httpx.post(
f"{endpoint}/mosaic/register", json=search_request,
).json()
print(response)
searchid = response["id"]
search_request = {
# Filter collection
"collections": ["noaa-emergency-response"],
# limit bounds of the known items (note: the bbox will also be used in the tilejson response)
"bbox": bounds,
"filter-lang": "cql-json",
"metadata": {
"bounds": [-87.0251, 36.0999, -85.4249, 36.2251], # This is redondant because it's in the bbox filter
"minzoom": 14,
"maxzoom": 18,
"assets": ["cog"],
"defaults": {
"true_color": {
"bidx": [1, 2, 3],
},
},
},
}
response = httpx.post(
f"{endpoint}/mosaic/register", json=search_request,
).json()
print(response)
searchid = response["id"]
{'searchid': '4b0db3dbd1858d54a3a55f84de97d1ca', 'links': [{'rel': 'metadata', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/info'}, {'rel': 'tilejson', 'type': 'application/json', 'href': 'http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/tilejson.json'}]}
In [10]:
Copied!
tj_response = httpx.get(f"{endpoint}/mosaic/{searchid}/tilejson.json?assets=cog").json()
print(tj_response)
tj_response = httpx.get(f"{endpoint}/mosaic/{searchid}/tilejson.json?assets=cog").json()
print(tj_response)
{'tilejson': '2.2.0', 'name': '4b0db3dbd1858d54a3a55f84de97d1ca', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=cog'], 'minzoom': 14, 'maxzoom': 18, 'bounds': [-87.0251, 36.0999, -85.4249, 36.2251], 'center': [-86.225, 36.162499999999994, 14]}
In [11]:
Copied!
m = Map(
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=14
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
aod_layer = TileLayer(
tiles=tj_response["tiles"][0],
attr="Mosaic",
min_zoom=tj_response["minzoom"],
max_zoom=tj_response["maxzoom"],
max_native_zoom=tj_response["maxzoom"],
)
aod_layer.add_to(m)
m
m = Map(
location=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),
zoom_start=14
)
geo_json = GeoJson(
data=geojson,
style_function=lambda x: {
'opacity': 1, 'dashArray': '1', 'fillOpacity': 0, 'weight': 1
},
)
geo_json.add_to(m)
aod_layer = TileLayer(
tiles=tj_response["tiles"][0],
attr="Mosaic",
min_zoom=tj_response["minzoom"],
max_zoom=tj_response["maxzoom"],
max_native_zoom=tj_response["maxzoom"],
)
aod_layer.add_to(m)
m
Out[11]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [ ]:
Copied!