**Teaching:**30 minutes**Exercises:**60 minutes

- Where can upper air data be found and what format is it in?
- How can I obtain upper air data programatically?
- How can MetPy be used to make a Skew-T Log-P diagram?
- What calculations can be performed on the data?

Upper air observations are reported as a plain text file in a tabular format that represents the down sampled raw data transmitted by the balloon. Data are reported an mandatory levels and at levels of significant change. An example of the beginning of sounding data may look like this:

```
-----------------------------------------------------------------------------
PRES HGHT TEMP DWPT RELH MIXR DRCT SKNT THTA THTE THTV
hPa m C C % g/kg deg knot K K K
-----------------------------------------------------------------------------
1000.0 270
991.0 345 -0.3 -2.8 83 3.15 0 0 273.6 282.3 274.1
984.0 403 10.2 -7.8 27 2.17 327 4 284.7 291.1 285.0
963.0 581 11.8 -9.2 22 1.99 226 17 288.0 294.1 288.4
959.7 610 11.6 -9.4 22 1.96 210 19 288.1 294.1 288.5
```

The data are available to download from the University of Wyoming archive and the Iowa State archive. **There is no need to download data manually.** We can use the siphon library (also developed at Unidata) to request and download these data. Let's download some data from Miami just prior to Irma's landfall.

First, we need to create a `datetime`

object that has the time of observation we are looking for. We can then request the data for a specific station. Currently date range requests are not possible, but planned for future releases.

In [ ]:

```
from datetime import datetime
from siphon.simplewebservice.wyoming import WyomingUpperAir
from metpy.io import get_upper_air_data
date = datetime(2017, 9, 10, 6)
station = 'MFL'
df = WyomingUpperAir.request_data(date, station)
```

The data are returned as a `pandas`

`DataFrame`

:

In [ ]:

```
df
```

Next, we will pull out the data and attach the units which are stored in a dictionary in the `DataFrame`

attribute `units`

.

In [ ]:

```
from metpy.units import units
p = df['pressure'].values * units(df.units['pressure'])
T = df['temperature'].values * units(df.units['temperature'])
Td = df['dewpoint'].values * units(df.units['dewpoint'])
u = df['u_wind'].values * units(df.units['u_wind'])
v = df['v_wind'].values * units(df.units['v_wind'])
```

- Get data from the 9/10/2017 00Z Key West sounding (the one closest to Irma's landfall). Use the Wyoming webpage or SPC sounding analysis page if you need to lookup the station identifier.
- Pull the data out into
`p, T, Td, u, v`

variables and attach the proper units.

In [ ]:

```
# Your code goes here
```

```
df = WyomingUpperAir.request_data(datetime(2017, 9, 10, 0), 'KEY')
p = df['pressure'].values * units(df.units['pressure'])
T = df['temperature'].values * units(df.units['temperature'])
Td = df['dewpoint'].values * units(df.units['dewpoint'])
u = df['u_wind'].values * units(df.units['u_wind'])
v = df['v_wind'].values * units(df.units['v_wind'])
```

Knowing what we already know about plotting in Python, we can explore the data a little, but the plots are not exactly what we are used to looking at. (Also notice that if we do not provide unit labels, `matplotlib`

will work with the units attached to the quantities!

In [ ]:

```
import matplotlib.pyplot as plt
%matplotlib inline
```

In [ ]:

```
fig = plt.figure(figsize=(10, 10))
ax1 = plt.subplot()
ax1.plot(T, p, color='tab:red')
ax1.plot(Td, p, color='blue')
ax1.set_ylim(1000, 0)
```

As meteorologists, we are used to looking at soundings on the Skew-T Log-p diagram. This is a tricky plot to make – the isotherms are skewed diagonally, pressure is plotted in log space, and we often want to see fiducial lines showing dry adiabats, moist adiabats, etc. MetPy has the capability to make a Skew-T baked in!

In [ ]:

```
from metpy.plots import SkewT
# Create a new figure. The dimensions here give a good aspect ratio
fig = plt.figure(figsize=(10, 10))
skew = SkewT(fig)
# Plot the data using normal plotting functions, all of the transforms
# happen in the background!
skew.plot(p, T, color='tab:red')
```

Let's set the pressure limits to be sensible for what we're interested in, say 1000-100 hPa. We'll also add wind barbs using the `plot_barbs`

functionality from `metpy`

.

In [ ]:

```
# Add wind barbs
skew.plot_barbs(p, u, v)
# Set some sensible axis limits
skew.ax.set_ylim(1000, 100)
fig
```

- Add a blue line for dewpoint.
- Set the x-axis limits to something sensible.

In [ ]:

```
# Your code goes here
```

```
skew.plot(p, Td, color='blue')
skew.ax.set_xlim(-40, 60)
fig
```

Generally we are interested in some thermodynamic parameters when looking at upper air data. We often want to know what the level of free convection (LFC), the lifted condensation level (LCL), or the equilibrium level (EL) is for a given sounding. MetPy implements these calculations for you, taking care of the numerical methods and testing. Let’s calculate some of these values and add them to our Skew-T.

In [ ]:

```
import metpy.calc as mpcalc
lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
```

In [ ]:

```
# Only try to draw the line if the value isn't NaN!
if lcl_pressure:
skew.ax.axhline(lcl_pressure, color='black')
fig
```

- Add the LFC to the plot (lfc takes the pressure, temperature, and dewpoint profiles).
- Add the EL to the plot.

In [ ]:

```
# Your code goes here
```

```
# Calculate the LFC and plot it if it exists
lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td)
if lfc_pressure:
skew.ax.axhline(lfc_pressure, color='tab:brown')
# Calculate the EL and plot it if it exists
el_pressure, el_temperature = mpcalc.el(p, T, Td)
if el_pressure:
skew.ax.axhline(el_pressure, color='tab:blue')
fig
```

When considering the stability of the atmosphere we often talk about the ideal parcel path. A parcel lifted from the surface along a dry adiabatic path until it becomes saturated, then lifted along a moist adiabatic path. MetPy will calculated the ideal parcel path given the starting point (generally the surface).

In [ ]:

```
parcel_path = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')
```

In [ ]:

```
print(parcel_path)
```

In [ ]:

```
skew.plot(p, parcel_path, color='black')
fig
```

Some of the most requested thermodynamic parameters are the Convective Available Potential Energy (CAPE) and Convective INhibition (CIN). MetPy will allow you to compute these in a single call!

In [ ]:

```
mpcalc.surface_based_cape_cin(p, T, Td)
```

- Calculate the most unstable CAPE/CIN for this sounding. What do you expect the results to be?

**HINT**: Look at the documentation for `most_unstable_cape_cin`

.

In [ ]:

```
# Your code goes here
```

```
mpcalc.most_unstable_cape_cin(p, T, Td)
```

`cape_cin`

takes an arbitrary parcel as its last argument.
There are several other parameters you can calculate with MetPy. These include bulk shear, Bunkers storm motion, precipitable water, significant tornado parameter, storm relative helicity, and supercell composite. See the documentation for how to use each of these and their recpective sources.

Let's calculate an interesting parameter for this sounding from hurricane Irma - percipitable water:

In [ ]:

```
mpcalc.precipitable_water(Td, p)
```

In [ ]:

```
mpcalc.precipitable_water(Td, p).to('inches')
```

- Calculate the bulk shear over the lowest 200 hPa of the sounding.

**HINT**: Look at the documentation for `bulk_shear`

.

In [ ]:

```
# Your code goes here
```

```
shr_u, shr_v = mpcalc.bulk_shear(p, u, v, depth=200 * units.hPa)
print(shr_u, shr_v)
```

Now that you’ve got the basics of the Skew-T down, it’s time to really dress it up. You could use the `moist_lapse`

and `dry_lapse`

functions in the calculations module to calculate and dry fiducials on the plot, but MetPy can do it for us.

In [ ]:

```
# Add the relevant special lines
skew.plot_dry_adiabats()
fig
```

- Add moist adiabats to the skew-T using
`plot_moist_adiabats()`

. - Add mixing ratio lines to the skew-T using
`plot_mixing_lines().`

In [ ]:

```
# Your code goes here
```

```
skew.plot_moist_adiabats()
skew.plot_mixing_lines()
fig
```

We can also shade the areas that represent CAPE and CIN to make things a little more visually appealing.

In [ ]:

```
# Shade areas representing CAPE and CIN
skew.shade_cin(p, T, parcel_path)
skew.shade_cape(p, T, parcel_path)
fig
```

We can also highlight certain isotherms. One important isotherm is the freezing point of water. Let’s add a highlight to that line. The skew transform happens automatically!

In [ ]:

```
skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)
fig
```

We can also add a hodograph to the plot, using matplotlib's `inset_axes`

function:

In [ ]:

```
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from metpy.plots import Hodograph
from metpy.units import units
import numpy as np
# Get the wind speed from the dataset
windspeed = df['speed'] * units(df.units['speed'])
# Add an axes to the plot
ax_hod = inset_axes(skew.ax, '30%', '30%', loc=1, borderpad=3)
# Plot the hodograph
h = Hodograph(ax_hod, component_range=100.)
# Grid the hodograph
h.add_grid(increment=20)
# Plot the data on the hodograph
mask = (p >= 100 * units.mbar)
h.plot(u[mask], v[mask], c='k')
fig
```

We can also color the hodograph based on another variable - either continuously or in a segmented way. Here we'll color the hodograph by height above ground level.

In [ ]:

```
fig = plt.figure(figsize=(3, 3))
h = Hodograph()
bounds = [0, 1, 3, 5, 10] * units.km
colors = ['magenta', 'red', 'yellow', 'green']
heights = df['height'].values * units(df.units['height'])
h.plot_colormapped(u, v, heights, bounds=bounds, colors=colors)
h.add_grid(increment=20)
```

- Use the
`plot_colormapped`

function to make a hodograph in a new figure with the line colored continuously by the windspeed.

In [ ]:

```
# Your code goes here
```

```
fig = plt.figure(figsize=(3, 3))
h = Hodograph()
h.plot_colormapped(u[mask], v[mask], windspeed[mask]) # Plot a line colored by wind speed
h.add_grid(increment=20)
```