Skip to content

Commit

Permalink
Fix for skewt subroutines ignoring x axis units
Browse files Browse the repository at this point in the history
Wet and dry adiabats, along with mixing lines, do not correctly
plot unless everything is in degrees celcius. This is especially
a problem when the plots show the wrong values without giving
any sort of warning. This fix makes the subroutines plot onto
units matching the xaxis or input temperature.
Checklist

Closes #1155
test added
  • Loading branch information
jibbals authored and dopplershift committed Dec 3, 2021
1 parent 30d7b74 commit 5356ef8
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 16 deletions.
63 changes: 47 additions & 16 deletions src/metpy/plots/skewt.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,38 @@ def plot(self, pressure, t, *args, **kwargs):
t, pressure = _delete_masked_points(t, pressure)
return self.ax.plot(t, pressure, *args, **kwargs)

def _get_line_starting_temps(self, t0=None, spacing=10):
r"""Determine starting temperatures for adiabats etc.
Return starting teperatures for subroutine lines, based on xaxis
Parameters
----------
t0 : array_like, optional
range of temperatures to be converted to match the xaxis
spacing : int or float, optional
Spacing between t0 values, default is 10
Returns
-------
units.Quantity
"""
# set default temperatures
if t0 is None:
# minimum and maximum temperature
xmin, xmax = self.ax.get_xlim()
t0 = np.arange(xmin, xmax + 1, spacing) * self.ax.xaxis.units

# if temperature has no units, guess from the lower bound
if not hasattr(t0, 'units'):
if np.nanmin(t0) > 150:
t0 = t0 * units.degK
else:
t0 = t0 * units.degC

# return temperature in units matching axes
return t0.to(self.ax.xaxis.units)

def plot_barbs(self, pressure, u, v, c=None, xloc=1.0, x_clip_radius=0.1,
y_clip_radius=0.08, **kwargs):
r"""Plot wind barbs.
Expand Down Expand Up @@ -449,7 +481,7 @@ def plot_dry_adiabats(self, t0=None, pressure=None, **kwargs):
Parameters
----------
t0 : array_like, optional
Starting temperature values in Kelvin. If none are given, they will be
Starting temperature values. If none are given, they will be
generated using the current temperature range at the bottom of
the plot.
pressure : array_like, optional
Expand All @@ -475,18 +507,16 @@ def plot_dry_adiabats(self, t0=None, pressure=None, **kwargs):
if self.dry_adiabats:
self.dry_adiabats.remove()

# Determine set of starting temps if necessary
if t0 is None:
xmin, xmax = self.ax.get_xlim()
t0 = units.Quantity(np.arange(xmin, xmax + 1, 10), 'degC')
# Get line start temperatures
t0 = self._get_line_starting_temps(t0)

# Get pressure levels based on ylims if necessary
if pressure is None:
pressure = units.Quantity(np.linspace(*self.ax.get_ylim()), 'mbar')
pressure = units.Quantity(np.linspace(*self.ax.get_ylim()), self.ax.yaxis.units)

# Assemble into data for plotting
t = dry_lapse(pressure, t0[:, np.newaxis],
units.Quantity(1000., 'mbar')).to(units.degC)
units.Quantity(1000., 'mbar')).to(t0.units)
linedata = [np.vstack((ti.m, pressure.m)).T for ti in t]

# Add to plot
Expand All @@ -508,7 +538,7 @@ def plot_moist_adiabats(self, t0=None, pressure=None, **kwargs):
Parameters
----------
t0 : array_like, optional
Starting temperature values in Kelvin. If none are given, they will be
Starting temperature values. If none are given, they will be
generated using the current temperature range at the bottom of
the plot.
pressure : array_like, optional
Expand All @@ -535,18 +565,15 @@ def plot_moist_adiabats(self, t0=None, pressure=None, **kwargs):
self.moist_adiabats.remove()

# Determine set of starting temps if necessary
if t0 is None:
xmin, xmax = self.ax.get_xlim()
t0 = units.Quantity(np.concatenate((np.arange(xmin, 0, 10),
np.arange(0, xmax + 1, 5))), 'degC')
t0 = self._get_line_starting_temps(t0)

# Get pressure levels based on ylims if necessary
if pressure is None:
pressure = units.Quantity(np.linspace(*self.ax.get_ylim()), 'mbar')
pressure = units.Quantity(np.linspace(*self.ax.get_ylim()), self.ax.yaxis.units)

# Assemble into data for plotting
t = moist_lapse(pressure, t0[:, np.newaxis],
units.Quantity(1000., 'mbar')).to(units.degC)
units.Quantity(1000., 'mbar')).to(t0.units)
linedata = [np.vstack((ti.m, pressure.m)).T for ti in t]

# Add to plot
Expand Down Expand Up @@ -597,10 +624,14 @@ def plot_mixing_lines(self, mixing_ratio=None, pressure=None, **kwargs):

# Set pressure range if necessary
if pressure is None:
pressure = units.Quantity(np.linspace(600, max(self.ax.get_ylim())), 'mbar')
# from highest pressure to 60% of highest pressure
pmax = max(self.ax.get_ylim())
pressure = units.Quantity(np.linspace(0.6 * pmax, pmax), self.ax.yaxis.units)

# Dewpoint contours calculated and converted to xaxis units
td = dewpoint(vapor_pressure(pressure, mixing_ratio)).to(self.ax.xaxis.units)

# Assemble data for plotting
td = dewpoint(vapor_pressure(pressure, mixing_ratio))
linedata = [np.vstack((t.m, pressure.m)).T for t in td]

# Add to plot
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions tests/plots/test_skewt.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ def test_skewt_api_units():
return fig


@pytest.mark.mpl_image_compare(tolerance=.027, remove_text=True, style='default')
def test_skewt_adiabat_units():
"""Test adiabats and mixing lines can handle different units."""
with matplotlib.rc_context({'axes.autolimit_mode': 'data'}):
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig)
p = np.linspace(950, 100, 10) * units.hPa
t = np.linspace(18, -20, 10) * units.degC

skew.plot(p, t, 'r')

# Add lines with units different to the xaxis
t0 = (np.linspace(-20, 20, 5) * units.degC).to(units.degK)
skew.plot_dry_adiabats(t0=t0)
# add lines with no units
t0 = np.linspace(-20, 20, 5)
skew.plot_moist_adiabats(t0=t0)
skew.plot_mixing_lines()

return fig


@pytest.mark.mpl_image_compare(tolerance=0., remove_text=True, style='default')
def test_skewt_default_aspect_empty():
"""Test SkewT with default aspect and no plots, only special lines."""
Expand Down

0 comments on commit 5356ef8

Please sign in to comment.