This tutorial is an introduction to Planet's Data API using the official Python client, the planet
module.
This tutorial assumes familiarity with the Python programming language throughout. Python modules used in this tutorial are:
You should also have an account on the Planet Platform and retrieve your API key from your account page.
This tutorial will cover the basic operations possible with the Python client, particularly those that interact with the Data API.
The basic workflow for interacting with the Data API is:
In [1]:
from planet import api
We next need to create a ClientV1
object registered with our API key. The API key will be automatically read from the PL_API_KEY
environment variable if it exists. If not it can be provided when creating the api
object.
In [2]:
client = api.ClientV1()
# client = api.ClientV1(api_key="abcdef0123456789") <-- not a real key
# print client.auth.value
ClientV1
provides basic low-level access to Planet’s API. Only one ClientV1
should be in existence for an application. The client is thread safe and takes care to avoid API throttling and also retries any throttled requests. Any exceptional HTTP responses are handled by translation to one of the planet.api.exceptions
classes.
We will also create a small helper function to print out JSON with proper indentation.
In [3]:
import json
def p(data):
print(json.dumps(data, indent=2))
Let's also read in a GeoJSON geometry into a variable so we can use it during testing.
In [4]:
with open("data/san-francisco.json") as f:
geom = json.loads(f.read())
We can search for items that are interesting by using the quick_search
member function. Searches, however, always require a proper request that includes a filter that selects the specific items to return as seach results.
The Planet Python client also includes planet.api.filters
to assist in the creation of search filters.
In [5]:
from planet.api import filters
The possible filters include and_filter
, date_filter
, range_filter
and so on, mirroring the options supported by the Planet API.
In [6]:
from datetime import datetime
start_date = datetime(year=2017, month=1, day=1)
date_filter = filters.date_range('acquired', gte=start_date)
cloud_filter = filters.range_filter('cloud_cover', lte=0.1)
In [7]:
and_filter = filters.and_filter(date_filter, cloud_filter)
In [8]:
p(and_filter)
In addition to the filter, a properly-constructed request also contains the list of item types that we want to select.
In [9]:
item_types = ["REOrthoTile", "PSOrthoTile"]
req = filters.build_search_request(and_filter, item_types)
In [10]:
p(req)
In [11]:
res = client.quick_search(req)
The results of quick_search
can be handled in different ways, but most commonly the user will either iterating through the list of items (items_iter
) or writing items to a GeoJSON file (json_encode
).
In either case, the number of items must be specified.
In [13]:
for item in res.items_iter(4):
print(item['id'], item['properties']['item_type'])
If the number of items requested is more than 250, the client will automatically fetch more pages of results in order to get the exact number requested.
In [14]:
with open('output/results.json','w') as f:
res.json_encode(f,1000)
This GeoJSON file can be opened and viewed in any compatible application.
In [15]:
print(item['id'])
In [16]:
assets = client.get_assets(item).get()
In [17]:
for asset in sorted(assets.keys()):
print(asset)
In [18]:
activation = client.activate(assets['analytic'])
activation.response.status_code
Out[18]:
A response of 202 means that the request has been accepted and the activation will begin shortly. A 204 code indicates that the asset is already active and no further action is needed. A 401 code means the user does not have permissions to download this file.
Below, we are polling the API until the item is done activation. This may take awhile.
In [19]:
import time
asset_activated = False
while asset_activated == False:
# Get asset and its activation status
assets = client.get_assets(item).get()
asset = assets.get('analytic')
asset_status = asset["status"]
# If asset is already active, we are done
if asset_status == 'active':
asset_activated = True
print("Asset is active and ready to download")
# Still activating. Wait and check again.
else:
print("...Still waiting for asset activation...")
time.sleep(3)
In [20]:
callback = api.write_to_file(directory='output/')
body = client.download(assets['analytic_xml'], callback=callback)
body.await()
Out[20]:
In [21]:
searches = client.get_searches()
In [22]:
for search in searches.items_iter(100):
print(search['id'], search['name'])
In [23]:
item_types = ["PSScene3Band"]
san_francisco_filter = filters.geom_filter(geom)
req = filters.build_search_request(san_francisco_filter, item_types, name="San Francisco")
In [24]:
p(req)
In [25]:
res = client.create_search(req)
In [26]:
search = res.get()
print(search["id"], search["name"])
In [27]:
res = client.saved_search(search["id"])
In [28]:
for item in res.items_iter(20):
print(item["id"], item["properties"]["view_angle"])
In [29]:
item_types = ["PSScene3Band"]
san_francisco_filter = filters.geom_filter(geom)
req = filters.build_search_request(san_francisco_filter, item_types, interval="year")
In [30]:
stats = client.stats(req).get()
In [31]:
p(stats)
In [32]:
assets = client.get_assets(item)
In [33]:
assets.last_modified()
In [34]:
assets.get()
Out[34]:
In [ ]: