Create a Skew-T plot using remote data from University of Wyoming.
This example uses example data from the University of Wyoming sounding archive for 12 UTC 31 October 2016 for Minneapolis, MN (MPX).
Imports¶
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import metpy.calc as mpcalc
from metpy.cbook import get_test_data
from metpy.plots import add_metpy_logo, SkewT
from metpy.units import units
from datetime import datetime
from siphon.simplewebservice.wyoming import WyomingUpperAirObtain Data and Format¶
This requires an internet connection to access the sounding data from a
remote server at the University of Wyoming.
First we will create variables for date, time and station.
Format: datetime(YYYY, MM, DD, HH)
The station entry will need the be the three letter identifier of the station you want to look at. The National Center for Atmospheric Research (NCAR) Research Applications Labratory (RAL) continously updates a detailed list of all stations.
# Create variables for preferred date, time and station
preferred_date = datetime(2016, 10, 26, 12)
station = 'MPX'# Read remote sounding data based on preferred_date and station
sounding_data = WyomingUpperAir.request_data(preferred_date, station)---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
Cell In[3], line 2
1 # Read remote sounding data based on preferred_date and station
----> 2 sounding_data = WyomingUpperAir.request_data(preferred_date, station)
File ~/micromamba/envs/metpy-cookbook/lib/python3.14/site-packages/siphon/simplewebservice/wyoming.py:58, in WyomingUpperAir.request_data(cls, time, site_id, recalc, **kwargs)
32 r"""Retrieve upper air observations from the Wyoming archive.
33
34 Parameters
(...) 55
56 """
57 endpoint = cls()
---> 58 df = endpoint._get_data(time, site_id, recalc=recalc)
59 return df
File ~/micromamba/envs/metpy-cookbook/lib/python3.14/site-packages/siphon/simplewebservice/wyoming.py:81, in WyomingUpperAir._get_data(self, time, site_id, recalc)
61 def _get_data(self, time, site_id, recalc=False):
62 r"""Download and parse upper air observations from an online archive.
63
64 Parameters
(...) 79
80 """
---> 81 raw_data = self._get_data_raw(time, site_id, recalc=recalc)
82 soup = BeautifulSoup(raw_data, 'html.parser')
83 tabular_data = StringIO(soup.find_all('pre')[0].contents[0])
File ~/micromamba/envs/metpy-cookbook/lib/python3.14/site-packages/siphon/simplewebservice/wyoming.py:164, in WyomingUpperAir._get_data_raw(self, time, site_id, recalc)
161 if recalc:
162 path += '&REPLOT=1'
--> 164 resp = self.get_path(path)
165 # See if the return is valid, but has no data
166 if resp.text.find("Can't") != -1:
File ~/micromamba/envs/metpy-cookbook/lib/python3.14/site-packages/siphon/http_util.py:453, in HTTPEndPoint.get_path(self, path, query)
430 def get_path(self, path, query=None):
431 """Make a GET request, optionally including a query, to a relative path.
432
433 The path of the request includes a path on top of the base URL
(...) 451
452 """
--> 453 return self.get(self.url_path(path), query)
File ~/micromamba/envs/metpy-cookbook/lib/python3.14/site-packages/siphon/http_util.py:488, in HTTPEndPoint.get(self, path, params)
486 else:
487 text = resp.text
--> 488 raise requests.HTTPError(f'Error accessing {resp.request.url}\n'
489 f'Server Error ({resp.status_code: d}: {text})')
490 return resp
HTTPError: Error accessing https://weather.arcc.uwyo.edu/cgi-bin/sounding/?region=naconf&TYPE=TEXT%3ALIST&YEAR=2016&MONTH=10&FROM=2612&TO=2612&STNM=MPX
Server Error ( 404: Not Found)sounding_dataAssign Units¶
We will pull the data out of the example dataset into individual variables and assign units. This is explained in further detain in the Simple Sounding notebook and in the Metpy documentation.
pres = sounding_data['pressure'].values * units.hPa
temp = sounding_data['temperature'].values * units.degC
dewpoint = sounding_data['dewpoint'].values * units.degC
wind_speed = sounding_data['speed'].values * units.knots
wind_dir = sounding_data['direction'].values * units.degrees
u = sounding_data['u_wind'].values * units.knots
v = sounding_data['v_wind'].values * units.knotsCreate Sounding Plot¶
# Create figure and set size
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig, rotation=45)
# Plot temperature and dewpoint lines
skew.plot(pres, temp, 'red')
skew.plot(pres, dewpoint, 'green')
# Plot wind barbs
my_interval = np.arange(100, 1000, 25) * units('hPa')
ix = mpcalc.resample_nn_1d(pres, my_interval)
skew.plot_barbs(pres[ix], u[ix], v[ix], y_clip_radius=0.001)
# Improve labels and set axis limits
skew.ax.set_xlabel('Temperature (\N{DEGREE CELSIUS})')
skew.ax.set_ylabel('Pressure (hPa)')
skew.ax.set_ylim(1000, 100)
# Add the relevant special lines
skew.plot_dry_adiabats(t0=np.arange(233, 533, 10) * units.K, alpha=0.25, color='orangered')
skew.plot_moist_adiabats(t0=np.arange(233, 400, 5) * units.K, alpha=0.25, color='tab:green')
skew.plot_mixing_lines(pressure=np.arange(1000, 99, -25) * units.hPa, linestyle='dotted', color='tab:blue')
# Add the MetPy logo!
fig = plt.gcf()
add_metpy_logo(fig, 115, 100, size='small');
# Add some descriptive titles
plt.title('{} Sounding'.format(station), loc='left')
plt.title('Valid Time: {}'.format(preferred_date), loc='right');