pystac-client Introduction¶
This notebook shows basic use of pystac-client to open an API, iterate through Collections and Items, and perform simple spatio-temporal searches.
[1]:
from pystac_client import Client
# set pystac_client logger to DEBUG to see API calls
import logging
logging.basicConfig()
logger = logging.getLogger('pystac_client')
logger.setLevel(logging.DEBUG)
Client¶
We first connect to an API by retrieving the root catalog, or landing page, of the API with the Client.open function.
[2]:
# STAC API root URL
URL = 'https://planetarycomputer.microsoft.com/api/stac/v1'
# custom headers
headers = []
cat = Client.open(URL, headers=headers)
cat
DEBUG:pystac_client.stac_api_io:GET https://planetarycomputer.microsoft.com/api/stac/v1 Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
[2]:
<Client id=microsoft-pc>
CollectionClient¶
As with a static catalog the get_collections function will iterate through the Collections in the Catalog. Notice that because this is an API it can get all the Collections through a single call, rather than having to fetch each one individually.
[3]:
for collection in cat.get_collections():
print(collection)
DEBUG:pystac_client.stac_api_io:GET https://planetarycomputer.microsoft.com/api/stac/v1/collections Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
<CollectionClient id=gap>
<CollectionClient id=nasadem>
<CollectionClient id=daymet-annual-na>
<CollectionClient id=hrea>
<CollectionClient id=daymet-monthly-hi>
<CollectionClient id=daymet-daily-na>
<CollectionClient id=daymet-monthly-na>
<CollectionClient id=daymet-annual-pr>
<CollectionClient id=daymet-daily-pr>
<CollectionClient id=daymet-daily-hi>
<CollectionClient id=daymet-monthly-pr>
<CollectionClient id=aster-l1t>
<CollectionClient id=daymet-annual-hi>
<CollectionClient id=io-lulc>
<CollectionClient id=jrc-gsw>
<CollectionClient id=landsat-8-c2-l2>
<CollectionClient id=mobi>
<CollectionClient id=mtbs>
<CollectionClient id=terraclimate>
<CollectionClient id=sentinel-2-l2a>
<CollectionClient id=us-census>
<CollectionClient id=cop-dem-glo-30>
<CollectionClient id=cop-dem-glo-90>
<CollectionClient id=fia>
<CollectionClient id=gbif>
<CollectionClient id=goes-cmi>
<CollectionClient id=3dep-seamless>
<CollectionClient id=alos-dem>
<CollectionClient id=gridmet>
<CollectionClient id=hgb>
<CollectionClient id=naip>
[4]:
collection = cat.get_collection('aster-l1t')
collection
DEBUG:pystac_client.stac_api_io:GET https://planetarycomputer.microsoft.com/api/stac/v1/collections/aster-l1t Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
[4]:
<CollectionClient id=aster-l1t>
Items¶
The main functions for getting items return iterators, where pystac-client will handle retrieval of additional pages when needed. Note that one request is made for the first ten items, then a second request for the next ten.
[5]:
items = collection.get_items()
# flush stdout so we can see the exact order that things happen
def get_ten_items(items):
for i, item in enumerate(items):
print(f"{i}: {item}", flush=True)
if i == 9:
return
print('First page', flush=True)
get_ten_items(items)
print('Second page', flush=True)
get_ten_items(items)
First page
DEBUG:pystac_client.stac_api_io:GET https://planetarycomputer.microsoft.com/api/stac/v1/collections/aster-l1t/items?limit=100 Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
0: <Item id=AST_L1T_00312272006020322_20150518201805>
1: <Item id=AST_L1T_00312272006020313_20150518201753>
2: <Item id=AST_L1T_00312272006020304_20150518201753>
3: <Item id=AST_L1T_00312272006020256_20150518201805>
4: <Item id=AST_L1T_00312272006013731_20150518201743>
5: <Item id=AST_L1T_00312272006013722_20150518201738>
6: <Item id=AST_L1T_00312272006013714_20150518201738>
7: <Item id=AST_L1T_00312272006013705_20150517144401>
8: <Item id=AST_L1T_00312272006013656_20150517144401>
9: <Item id=AST_L1T_00312272006013647_20150517144406>
Second page
0: <Item id=AST_L1T_00312272006013638_20150517144356>
1: <Item id=AST_L1T_00312272006013629_20150517144344>
2: <Item id=AST_L1T_00312272006013620_20150517144344>
3: <Item id=AST_L1T_00312272006013612_20150517144400>
4: <Item id=AST_L1T_00312272006013603_20150517144346>
5: <Item id=AST_L1T_00312272006013554_20150517144346>
6: <Item id=AST_L1T_00312272006013545_20150517144346>
7: <Item id=AST_L1T_00312272006013536_20150517144340>
8: <Item id=AST_L1T_00312272006013527_20150517144346>
9: <Item id=AST_L1T_00312272006013519_20150517144336>
API Search¶
If the Catalog is an API, we have the ability to search for items based on spatio-temporal properties.
[6]:
# AOI around Delfzijl, in northern Netherlands
geom = {
"type": "Polygon",
"coordinates": [
[
[
6.42425537109375,
53.174765470134616
],
[
7.344360351562499,
53.174765470134616
],
[
7.344360351562499,
53.67393435835391
],
[
6.42425537109375,
53.67393435835391
],
[
6.42425537109375,
53.174765470134616
]
]
]
}
# limit sets the # of items per page so we can see multiple pages getting fetched
search = cat.search(
collections = "aster-l1t",
intersects = geom,
datetime = "2000-01-01/2010-12-31",
max_items = 15,
limit = 5
)
# PySTAC ItemCollection
items = search.get_all_items()
# Dictionary (GeoJSON FeatureCollection)
item_json = items.to_dict()
len(items)
DEBUG:pystac_client.stac_api_io:POST https://planetarycomputer.microsoft.com/api/stac/v1/search Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '353', 'Content-Type': 'application/json'} Payload: {"limit": 5, "datetime": "2000-01-01T00:00:00Z/2010-12-31T23:59:59Z", "collections": ["aster-l1t"], "intersects": {"type": "Polygon", "coordinates": [[[6.42425537109375, 53.174765470134616], [7.344360351562499, 53.174765470134616], [7.344360351562499, 53.67393435835391], [6.42425537109375, 53.67393435835391], [6.42425537109375, 53.174765470134616]]]}}
DEBUG:pystac_client.stac_api_io:POST https://planetarycomputer.microsoft.com/api/stac/v1/search Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '411', 'Content-Type': 'application/json'} Payload: {"limit": 5, "datetime": "2000-01-01T00:00:00Z/2010-12-31T23:59:59Z", "collections": ["aster-l1t"], "intersects": {"type": "Polygon", "coordinates": [[[6.42425537109375, 53.174765470134616], [7.344360351562499, 53.174765470134616], [7.344360351562499, 53.67393435835391], [6.42425537109375, 53.67393435835391], [6.42425537109375, 53.174765470134616]]]}, "token": "next:AST_L1T_00307172006105029_20150515082245"}
DEBUG:pystac_client.stac_api_io:POST https://planetarycomputer.microsoft.com/api/stac/v1/search Headers: {'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '411', 'Content-Type': 'application/json'} Payload: {"limit": 5, "datetime": "2000-01-01T00:00:00Z/2010-12-31T23:59:59Z", "collections": ["aster-l1t"], "intersects": {"type": "Polygon", "coordinates": [[[6.42425537109375, 53.174765470134616], [7.344360351562499, 53.174765470134616], [7.344360351562499, 53.67393435835391], [6.42425537109375, 53.67393435835391], [6.42425537109375, 53.174765470134616]]]}, "token": "next:AST_L1T_00306062006105631_20150514173924"}
[6]:
15
[7]:
# note that this will work in JupyterLab, but not in a Jupyter Notebook
import IPython.display
IPython.display.JSON(item_json)
[7]:
<IPython.core.display.JSON object>
[8]:
# this cell can be used in Jupyter Notebook. Use above if using JupyterLab
import json
import uuid
from IPython.display import display_javascript, display_html, display
class RenderJSON(object):
def __init__(self, json_data):
if isinstance(json_data, dict) or isinstance(json_data, list):
self.json_str = json.dumps(json_data)
else:
self.json_str = json_data
self.uuid = str(uuid.uuid4())
def _ipython_display_(self):
display_html('<div id="{}" style="height: 600px; width:100%;font: 12px/18px monospace !important;"></div>'.format(self.uuid), raw=True)
display_javascript("""
require(["https://rawgit.com/caldwell/renderjson/master/renderjson.js"], function() {
renderjson.set_show_to_level(2);
document.getElementById('%s').appendChild(renderjson(%s))
});
""" % (self.uuid, self.json_str), raw=True)
RenderJSON(item_json)
[ ]: