Emilio Mayorga, University of Washington, Seattle. 2018-5-10. Demo put together using as a starting point instructions from Azavea from October 2017.
The Model My Watershed API allows you to delineate watersheds and analyze geo-data for watersheds and arbitrary areas. You can read more about the work at WikiWatershed or use the web app.
MMW users can discover their API keys through the user interface, and test the MMW geoprocessing API on either the live or staging apps. An Account page with the API key is available from either app (live or staging). To see it, go to the app, log in, and click on "Account" in the dropdown that appears when you click on your username in the top right. Your key is different between staging and production. For testing with the staging API and key, go to https://staging.app.wikiwatershed.org/api/docs/
The API can be tested from the command line using curl. This example uses the staging API to test the watershed endpoint:
curl -H "Content-Type: application/json" -H "Authorization: Token YOUR_API_KEY" -X POST
-d '{ "location": [39.67185,-75.76743] }' https://staging.app.wikiwatershed.org/api/watershed/
In [1]:
import json
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
In [2]:
def requests_retry_session(
retries=3,
backoff_factor=0.3,
status_forcelist=(500, 502, 504),
session=None,
):
session = session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
In [3]:
s = requests.Session()
In [4]:
APIToken = 'Token YOURTOKEN' # Replace YOURTOKEN with your actual token string/key
s.headers.update({
'Authorization': APIToken,
'Content-Type': 'application/json'
})
MMW staging (test) API Rapid Watershed Delineation (RWD) "watershed" endpoint:
In [5]:
post_url = 'https://staging.app.wikiwatershed.org/api/watershed/'
Parameters passed to the RWD ("watershed") API request. This is a point in Salt Lake City
In [6]:
payload = {
'location': [40.746054, -111.847987], # [latitude, longitude]
'snappingOn': True,
'dataSource': 'nhd'}
json_dat = json.dumps(payload)
In [7]:
post_req = requests_retry_session(session=s).post(post_url, data=json_dat)
In [8]:
json_out = json.loads(post_req.content)
json_out
Out[8]:
The job is not completed instantly and the results are not returned directly by the API request that initiated the job. The user must first issue an API request to confirm that the job is complete, then fetch the results. The demo presented here performs automated retries (checks) until the server confirms the job is completed, then requests the JSON results and converts (deserializes) them into a Python dictionary.
In [9]:
get_url = 'https://staging.app.wikiwatershed.org/api/jobs/{job}/'.format
In [10]:
result = ''
while not result:
get_req = requests_retry_session(session=s).get(get_url(job=json_out['job']))
result = json.loads(get_req.content)['result']
In [11]:
type(result), result.keys()
Out[11]:
The results (result) are made up of two dictionary items: input_pt and watershed. Each one of those is a GeoJSON-like object already converted to a Python dictionary.
input_pt:
In [12]:
input_pt_geojson = result['input_pt']
In [13]:
input_pt_geojson
Out[13]:
watershed:
In [14]:
watershed_geojson = result['watershed']
In [15]:
watershed_geojson.keys(), watershed_geojson['geometry'].keys()
Out[15]:
In [16]:
watershed_geojson['properties']
Out[16]:
In [17]:
# watershed has just one feature -- a single polygon
print("Number of polygon features: {} \nFeature type: {} \nNumber of vertices in polygon: {}".format(
len(watershed_geojson['geometry']['coordinates']),
watershed_geojson['geometry']['type'],
len(watershed_geojson['geometry']['coordinates'][0])
))
In [18]:
%matplotlib inline
import folium
In [19]:
# Initialize Folium map
m = folium.Map(location=[input_pt_geojson['properties']['Lat'], input_pt_geojson['properties']['Lon']],
tiles='CartoDB positron', zoom_start=12)
In [20]:
# Add RWD watershed and drainage point onto map
folium.GeoJson(watershed_geojson).add_to(m);
folium.GeoJson(input_pt_geojson).add_to(m);
In [21]:
m
Out[21]: