<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Visualize imagery over time
In this notebook, we will show how to combine the Data API and Tiles API to make a timelapse animation for a point of interest.
Setup
Set API Key
Get your API key from your Planet account info and paste it below in place of YOUR_KEY_HERE
Step1:  Check data api connection
Make data api request to test that the api key is working
Step3:  Data API Search
In this next part, we will search for items that match a given date range, item_type, and location
Data API quick-search wrapper
Make a search function that can take a geojson geometry and give us item_ids
Step5:  Geometry helper
Convert coordinates to geojson geometry format
Step6:  Make a geometry dict for coordinates in San Francisco
Step7:  Try getting item ids
Step9:  Getting Webtiles
Although we could download images for the item_ids above, we can get a nice visual preview through webtiles. These are 256x256 PNG images on a spatial grid, often used for web maps.
Generating tile urls
We want to get urls for many tiles over time for a given latitude, longitude, and zoom level.
Let's re-use some of the filters we exposed in the Data API search wrapper.
Step10:  Testing tile urls
Click the links below to see tile images in your browser
Step11:  Display a tile
Step13:  Animate tiles over time
<ASSISTANT_TASK:>
Python Code:
import os
# Setup the API Key from the `PL_API_KEY` environment variable
PLANET_API_KEY = os.getenv('PL_API_KEY')
# If you're following along with this notebook, you can enter your API Key on the following line, and uncomment it:
# PLANET_API_KEY = 'YOUR_KEY_HERE'
assert PLANET_API_KEY, 'api key not set'
# Import helper modules
import json
import mercantile
import requests
Explanation: Visualize imagery over time
In this notebook, we will show how to combine the Data API and Tiles API to make a timelapse animation for a point of interest.
Setup
Set API Key
Get your API key from your Planet account info and paste it below in place of YOUR_KEY_HERE
End of explanation
# Setup Planet Data API base URL
API_URL = "https://api.planet.com/data/v1"
# Setup the session
session = requests.Session()
# Authenticate
session.auth = (PLANET_API_KEY, "")
# Make a GET request to the Planet Data API
resp = session.get(API_URL)
if not resp.ok:
    print("Something is wrong:", resp.content)
Explanation: Check data api connection
Make data api request to test that the api key is working
End of explanation
from datetime import datetime
def get_item_ids(geometry, item_type='PSScene', start_date=None, end_date=None, limit=100):
    Get Planet Data API item_id values for matching filters.
    Args:
        geometry: geojson geometry dict
        item_type: item_type (see https://developers.planet.com/docs/api/items-assets/#item-types)
        start_date: inclusive lower bound ISO 8601 datetime string (include items captured on or after this date)
        end_date: exclusive lower bound ISO 8601 datetime string (include items captured before this date)
        limit: max number of ids to return
    Returns:
        item_ids: list of id strings
    
    # Data API Geometry Filter
    geometry_filter = {
        "type": "GeometryFilter",
        "field_name": "geometry",
        "config": geometry
    }
    # use a default end_date of the current time
    if not end_date:
        end_date = datetime.utcnow().isoformat() + 'Z'
    date_filter = {
        "type": "DateRangeFilter", # Type of filter -> Date Range
        "field_name": "acquired", # The field to filter on: "acquired" -> Date on which the "image was taken"
        "config": {
            "lt": end_date, # "lt" -> Less than
        }
    }
    # start_date is optional
    if start_date:
        # greater than or equal to start date
        date_filter["config"]["gte"] = start_date
    # combine geometry and date filters with an AndFilter
    and_filter = {
        "type": "AndFilter",
        "config": [geometry_filter, date_filter]
    }
    quick_url = "{}/quick-search".format(API_URL)
    # Setup the request
    filter_request = {
        "item_types" : [item_type],
        "filter" : and_filter
    }
    # get ids from search results
    resp = session.post(quick_url, json=filter_request)
    results = resp.json()
    ids = [f['id'] for f in results['features']]
    # follow pagination links until we hit the limit
    while len(ids) < limit and results['_links'].get('next'):
        results = requests.get(results['_links'].get('next')).json()
        more_ids = [f['id'] for f in results['features']]
        ids += more_ids
    return ids[:limit]
Explanation: Data API Search
In this next part, we will search for items that match a given date range, item_type, and location
Data API quick-search wrapper
Make a search function that can take a geojson geometry and give us item_ids
End of explanation
def coords_to_geometry(lat, lon):
    Given latitude and longitude floats, construct a geojson geometry dict
    return {
        "type": "Point",
        "coordinates": [lon, lat]
    }
Explanation: Geometry helper
Convert coordinates to geojson geometry format
End of explanation
geom = coords_to_geometry(37.77493, -122.41942)
print(geom)
Explanation: Make a geometry dict for coordinates in San Francisco
End of explanation
get_item_ids(geom, start_date="2019-01-01T00:00:00.000Z", end_date="2019-10-01T00:00:00.000Z", limit=5)
Explanation: Try getting item ids
End of explanation
def get_tile_urls(lat, lon, zoom=15, item_type='PSScene', start_date='2019-01-01T00:00:00.000Z', end_date='2019-10-01T00:00:00.000Z', limit=5):
    Get webtile urls for given coordinates, zoom, and matching filters.
    Args:
        lat: latitude float
        lon: longitude float
        zoom: zoom level int (usually between 1 and 15)
        item_type: item_type (see https://developers.planet.com/docs/api/items-assets/#item-types)
        start_date: inclusive lower bound ISO 8601 datetime string (include items captured on or after this date)
        end_date: exclusive lower bound ISO 8601 datetime string (include items captured before this date)
        limit: max number of ids to return
    Returns:
        item_ids: list of id strings
    
    geom = coords_to_geometry(lat, lon)
    item_ids = get_item_ids(geom, item_type=item_type, start_date=start_date, end_date=end_date, limit=limit)
    tile = mercantile.tile(lon, lat, zoom)
    tile_url_template = 'https://tiles.planet.com/data/v1/{item_type}/{item_id}/{z}/{x}/{y}.png?api_key={api_key}'
    return [tile_url_template.format(item_type=item_type, item_id=i, x=tile.x, y=tile.y, z=zoom, api_key=PLANET_API_KEY) for i in item_ids]
Explanation: Getting Webtiles
Although we could download images for the item_ids above, we can get a nice visual preview through webtiles. These are 256x256 PNG images on a spatial grid, often used for web maps.
Generating tile urls
We want to get urls for many tiles over time for a given latitude, longitude, and zoom level.
Let's re-use some of the filters we exposed in the Data API search wrapper.
End of explanation
tile_urls = get_tile_urls(37.77493, -122.41942, limit=5)
for url in tile_urls:
    print(url)
    print()
Explanation: Testing tile urls
Click the links below to see tile images in your browser
End of explanation
from IPython.display import Image
resp = requests.get(tile_urls[0])
Image(resp.content)
Explanation: Display a tile
End of explanation
%matplotlib inline
from IPython.display import HTML
import random
import time
def animate(urls, delay=1.0, loops=1):
    Display an animated loop of images
    Args:
        urls: list of image url strings
        delay: how long in seconds to display each image
        loops: how many times to repeat the image sequence
    
    disp_id = str(random.random())
    display("placeholder", display_id=disp_id)
    for loop in range(loops):
        for frame_url in urls:
            htmlDisplay = f'<img src="{frame_url}" class="mySlides">'
            display(HTML(htmlDisplay), display_id=disp_id, update=True)
            time.sleep(delay)
animate(tile_urls, delay=0.5, loops=3)
tile_urls = get_tile_urls(37.77493, -122.41942, limit=100)
animate(tile_urls, delay=1, loops=3)
Explanation: Animate tiles over time
End of explanation
<END_TASK>