Skip to content

Commit

Permalink
Implement all-station IEM Upper Air request (#234)
Browse files Browse the repository at this point in the history
* Add other simple web services to the doc build

* Add all station support for IEM Upper Air

Based on akrherz/iem#117, this commit
implements the new all-station upper air request from Iowa State.
Modifications were made to the parsing backend to allow for the returned
JSON with multiple files.
  • Loading branch information
jthielen authored and jrleeman committed Jul 5, 2018
1 parent eed47b2 commit e2fab0b
Show file tree
Hide file tree
Showing 6 changed files with 17,979 additions and 16 deletions.
21 changes: 21 additions & 0 deletions docs/api/simplewebservice.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,26 @@
:mod:`siphon.simplewebservice.wyoming`
======================================
.. automodule:: siphon.simplewebservice.wyoming
:members:
:special-members: __init__

======================================
:mod:`siphon.simplewebservice.iastate`
======================================
.. automodule:: siphon.simplewebservice.iastate
:members:
:special-members: __init__

======================================
:mod:`siphon.simplewebservice.igra2`
======================================
.. automodule:: siphon.simplewebservice.igra2
:members:
:special-members: __init__

======================================
:mod:`siphon.simplewebservice.acis`
======================================
.. automodule:: siphon.simplewebservice.acis
:members:
:special-members: __init__
77 changes: 61 additions & 16 deletions siphon/simplewebservice/iastate.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self):

@classmethod
def request_data(cls, time, site_id, **kwargs):
"""Retrieve upper air observations from Iowa State's upper air archive.
"""Retrieve upper air observations from Iowa State's archive for a single station.
Parameters
----------
Expand All @@ -46,10 +46,35 @@ def request_data(cls, time, site_id, **kwargs):
"""
endpoint = cls()
df = endpoint._get_data(time, site_id, **kwargs)
df = endpoint._get_data(time, site_id, None, **kwargs)
return df

def _get_data(self, time, site_id):
@classmethod
def request_all_data(cls, time, pressure=None, **kwargs):
"""Retrieve upper air observations from Iowa State's archive for all stations.
Parameters
----------
time : datetime
The date and time of the desired observation.
pressure : float, optional
The mandatory pressure level at which to request data (in hPa). If none is given,
all the available data in the profiles is returned.
kwargs
Arbitrary keyword arguments to use to initialize source
Returns
-------
:class:`pandas.DataFrame` containing the data
"""
endpoint = cls()
df = endpoint._get_data(time, None, pressure, **kwargs)
return df

def _get_data(self, time, site_id, pressure=None):
"""Download data from Iowa State's upper air archive.
Parameters
Expand All @@ -58,17 +83,24 @@ def _get_data(self, time, site_id):
Date and time for which data should be downloaded
site_id : str
Site id for which data should be downloaded
pressure : float, optional
Mandatory pressure level at which to request data (in hPa).
Returns
-------
:class:`pandas.DataFrame` containing the data
"""
json_data = self._get_data_raw(time, site_id)
json_data = self._get_data_raw(time, site_id, pressure)
data = {}
for pt in json_data['profiles'][0]['profile']:
for field in ('drct', 'dwpc', 'hght', 'pres', 'sknt', 'tmpc'):
data.setdefault(field, []).append(np.nan if pt[field] is None else pt[field])
for profile in json_data['profiles']:
for pt in profile['profile']:
for field in ('drct', 'dwpc', 'hght', 'pres', 'sknt', 'tmpc'):
data.setdefault(field, []).append(np.nan if pt[field] is None
else pt[field])
for field in ('station', 'valid'):
data.setdefault(field, []).append(np.nan if profile[field] is None
else profile[field])

# Make sure that the first entry has a valid temperature and dewpoint
idx = np.argmax(~(np.isnan(data['tmpc']) | np.isnan(data['dwpc'])))
Expand All @@ -81,6 +113,9 @@ def _get_data(self, time, site_id):
df['dewpoint'] = ma.masked_invalid(data['dwpc'][idx:])
df['direction'] = ma.masked_invalid(data['drct'][idx:])
df['speed'] = ma.masked_invalid(data['sknt'][idx:])
df['station'] = data['station'][idx:]
df['time'] = [datetime.strptime(valid, '%Y-%m-%dT%H:%M:%SZ')
for valid in data['valid'][idx:]]

# Calculate the u and v winds
df['u_wind'], df['v_wind'] = get_wind_components(df['speed'],
Expand All @@ -90,10 +125,6 @@ def _get_data(self, time, site_id):
df = df.dropna(subset=('temperature', 'dewpoint', 'direction', 'speed',
'u_wind', 'v_wind'), how='all').reset_index(drop=True)

df['station'] = json_data['profiles'][0]['station']
df['time'] = datetime.strptime(json_data['profiles'][0]['valid'],
'%Y-%m-%dT%H:%M:%SZ')

# Add unit dictionary
df.units = {'pressure': 'hPa',
'height': 'meter',
Expand All @@ -107,7 +138,7 @@ def _get_data(self, time, site_id):
'time': None}
return df

def _get_data_raw(self, time, site_id):
def _get_data_raw(self, time, site_id, pressure=None):
r"""Download data from the Iowa State's upper air archive.
Parameters
Expand All @@ -116,18 +147,32 @@ def _get_data_raw(self, time, site_id):
Date and time for which data should be downloaded
site_id : str
Site id for which data should be downloaded
pressure : float, optional
Mandatory pressure level at which to request data (in hPa).
Returns
-------
list of json data
"""
path = ('raob.py?ts={time:%Y%m%d%H}00&station={stid}').format(time=time, stid=site_id)
resp = self.get_path(path)
query = {'ts': time.strftime('%Y%m%d%H00')}
if site_id is not None:
query['station'] = site_id
if pressure is not None:
query['pressure'] = pressure

resp = self.get_path('raob.py', query)
json_data = json.loads(resp.text)

# See if the return is valid, but has no data
if not (json_data['profiles'] and json_data['profiles'][0]['profile']):
raise ValueError('No data available for {time:%Y-%m-%d %HZ} '
'for station {stid}.'.format(time=time, stid=site_id))
message = 'No data available '
if time is not None:
message += 'for {time:%Y-%m-%d %HZ} '.format(time=time)
if site_id is not None:
message += 'for station {stid}'.format(stid=site_id)
if pressure is not None:
message += 'for pressure {pres}'.format(pres=pressure)
message = message[:-1] + '.'
raise ValueError(message)
return json_data
Loading

0 comments on commit e2fab0b

Please sign in to comment.