Source code for streamstats.watershed
# -*- coding: utf-8 -*-
"""Functionality for finding watershed information for specific locations."""
from collections import OrderedDict
from streamstats import utils
[docs]class Watershed():
"""Watershed covering a spatial region, with associated information.
The USGS StreamStats API is built around watersheds as organizational
units. Watersheds in the 50 U.S. states can be found using lat/lon
lookups, along with information about the watershed including its HUC code
and a GeoJSON representation of the polygon of a watershed. Basin
characteristics can also be extracted from watersheds.
"""
base_url = "https://streamstats.usgs.gov/streamstatsservices/"
def __init__(self, lat, lon):
"""Initialize a Watershed object
:param lon: Longitude of point in decimal degrees.
:type lon: float
:param lat: Latitude of point in decimal degrees.
:type lat: float
:param simplify: Whether to simplify the polygon representation.
:type simplify: bool
"""
self.lat, self.lon = lat, lon
self.state = utils.find_state(utils.find_address(lat=lat, lon=lon))
self.data = self._delineate()
self.workspace = self.data['workspaceID']
self.parameters = self.data['parameters']
def __repr__(self):
"""Get the string representation of a watershed."""
huc = self.huc
huc_message = 'Watershed object with HUC%s: %s' % (len(huc), huc)
coord_message = 'containing lat/lon: (%s, %s)' % (self.lat, self.lon)
return ', '.join((huc_message, coord_message))
def _delineate(self):
"""Find the watershed that contains a point.
Implements a Delineate Watershed by Location query from
https://streamstats.usgs.gov/docs/streamstatsservices/#/
:rtype dict containing watershed data
"""
payload = {
'rcode': self.state,
'xlocation': self.lon,
'ylocation': self.lat,
'crs': 4326,
'includeparameters': True,
'includeflowtypes': False,
'includefeatures': True,
'simplify': False
}
url = "".join((self.base_url, "watershed.geojson"))
response = utils.requests_retry_session().get(url, params=payload)
response.raise_for_status() # raises errors early
return response.json()
@property
def huc(self):
"""Find the Hydrologic Unit Code (HUC) of the watershed."""
watershed_point = self.data['featurecollection'][0]['feature']
huc = watershed_point['features'][0]['properties']['HUCID']
return huc
@property
def boundary(self):
"""Return the full watershed GeoJSON as a dictionary.
:rtype dict containing GeoJSON watershed boundary
"""
for dictionary in self.data['featurecollection']:
if dictionary.get('name', '') == 'globalwatershed':
return dictionary['feature']
raise LookupError('Could not find "globalwatershed" in the feature'
'collection.')
@property
def characteristics(self):
"""List the available watershed characteristics.
Details about these characteristics can be found in the StreamStats
docs: https://streamstatsags.cr.usgs.gov/ss_defs/basin_char_defs.aspx
:rtype OrderedDict with characteristic codes and descriptions
"""
chars = OrderedDict((p['code'], p['name']) for p in self.parameters)
return chars
[docs] def get_characteristic(self, code=None):
"""Retrieve a specified watershed characteristic
:param code: Watershed characteristic code to extract.
:type code: string
get_characteristic() requires a characteristic code as an argument.
Valid codes can be seen as keys in the dictionary returned
by the characteristics() method.
:rtype dict containing specified characteristic's data and metadata
"""
keys = list(self.characteristics.keys())
if code not in keys:
raise ValueError("code must be a valid key: %s" % ', '.join(keys))
characteristic_index = keys.index(code)
characteristic_values = self.parameters[characteristic_index]
return characteristic_values