Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shade area on SkewT #382

Merged
merged 8 commits into from
Apr 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ matrix:
- python: 2.7
env:
- VERSIONS="numpy==1.9.1 matplotlib==1.4.0 scipy==0.14.0 pint==0.7"
- TASK="coverage"
- TEST_OUTPUT_CONTROL=""
- python: 3.4
env:
Expand Down
26 changes: 26 additions & 0 deletions metpy/plots/_mpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,29 @@ def get_usetex(self):

# Monkey-patch scattertext onto Axes
Axes.scattertext = scattertext


# See if we need to add in the Tableau colors which were added in Matplotlib 2.0
import matplotlib.colors # noqa: E402
if not hasattr(matplotlib.colors, 'TABLEAU_COLORS'):
from collections import OrderedDict

# These colors are from Tableau
TABLEAU_COLORS = (
('blue', '#1f77b4'),
('orange', '#ff7f0e'),
('green', '#2ca02c'),
('red', '#d62728'),
('purple', '#9467bd'),
('brown', '#8c564b'),
('pink', '#e377c2'),
('gray', '#7f7f7f'),
('olive', '#bcbd22'),
('cyan', '#17becf'),
)

# Normalize name to "tab:<name>" to avoid name collisions.
matplotlib.colors.TABLEAU_COLORS = OrderedDict(
('tab:' + name, value) for name, value in TABLEAU_COLORS)

matplotlib.colors.cnames.update(matplotlib.colors.TABLEAU_COLORS)
108 changes: 108 additions & 0 deletions metpy/plots/skewt.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,114 @@ def plot_mixing_lines(self, w=None, p=None, **kwargs):
kwargs.setdefault('alpha', 0.8)
return self.ax.add_collection(LineCollection(linedata, **kwargs))

def shade_area(self, y, x1, x2=0, which='both', **kwargs):
r"""Shade area between two curves.

Shades areas between curves. Area can be where one is greater or less than the other
or all areas shaded.

Parameters
----------
y : array_like
1-dimensional array of numeric y-values
x1 : array_like
1-dimensional array of numeric x-values
x2 : array_like
1-dimensional array of numeric x-values
which : string
Specifies if `positive`, `negative`, or `both` areas are being shaded.
Will be overridden by where.
kwargs
Other keyword arguments to pass to :class:`matplotlib.collections.PolyCollection`

Returns
-------
:class:`matplotlib.collections.PolyCollection`

See Also
--------
:class:`matplotlib.collections.PolyCollection`
:func:`matplotlib.axes.Axes.fill_betweenx`
"""
fill_properties = {'positive':
{'facecolor': 'tab:red', 'alpha': 0.4, 'where': x1 > x2},
'negative':
{'facecolor': 'tab:blue', 'alpha': 0.4, 'where': x1 < x2},
'both':
{'facecolor': 'tab:green', 'alpha': 0.4, 'where': None}}

try:
fill_args = fill_properties[which]
fill_args.update(kwargs)
except KeyError:
raise ValueError('Unknown option for which: {0}'.format(str(which)))

arrs = y, x1, x2

if fill_args['where'] is not None:
arrs = arrs + (fill_args['where'],)
fill_args.pop('where', None)

arrs = delete_masked_points(*arrs)

return self.ax.fill_betweenx(*arrs, **fill_args)

def shade_cape(self, p, t, t_parcel, **kwargs):
r"""Shade areas of CAPE.

Shades areas where the parcel is warmer than the environment (areas of positive
buoyancy.

Parameters
----------
p : array_like
Pressure values
t : array_like
Temperature values
t_parcel : array_like
Parcel path temperature values
kwargs
Other keyword arguments to pass to :class:`matplotlib.collections.PolyCollection`

Returns
-------
:class:`matplotlib.collections.PolyCollection`

See Also
--------
:class:`matplotlib.collections.PolyCollection`
:func:`matplotlib.axes.Axes.fill_betweenx`
"""
return self.shade_area(p, t_parcel, t, which='positive', **kwargs)

def shade_cin(self, p, t, t_parcel, **kwargs):
r"""Shade areas of CIN.

Shades areas where the parcel is cooler than the environment (areas of negative
buoyancy.

Parameters
----------
p : array_like
Pressure values
t : array_like
Temperature values
t_parcel : array_like
Parcel path temperature values
kwargs
Other keyword arguments to pass to :class:`matplotlib.collections.PolyCollection`

Returns
-------
:class:`matplotlib.collections.PolyCollection`

See Also
--------
:class:`matplotlib.collections.PolyCollection`
:func:`matplotlib.axes.Axes.fill_betweenx`
"""
return self.shade_area(p, t_parcel, t, which='negative', **kwargs)


@exporter.export
class Hodograph(object):
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions metpy/plots/tests/test_skewt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
"""Tests for the `skewt` module."""

import matplotlib
from matplotlib.gridspec import GridSpec
import matplotlib.pyplot as plt
import numpy as np
Expand All @@ -13,6 +14,8 @@
from metpy.testing import patch_round, set_agg_backend # noqa: F401
from metpy.units import units

MPL_VERSION = matplotlib.__version__[:3]


@pytest.mark.mpl_image_compare(tolerance=0.021, remove_text=True)
def test_skewt_api():
Expand Down Expand Up @@ -60,6 +63,60 @@ def test_skewt_with_grid_enabled():
SkewT()


@pytest.fixture()
def test_profile():
"""Return data for a test profile."""
return np.linspace(1000, 100, 10), np.linspace(20, -20, 10), np.linspace(25, -30, 10)


@pytest.mark.mpl_image_compare(tolerance={'1.4': 1.71}.get(MPL_VERSION, 0.), remove_text=True)
def test_skewt_shade_cape_cin(test_profile):
"""Test shading CAPE and CIN on a SkewT plot."""
p, t, tp = test_profile
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig)
skew.plot(p, t, 'r')
skew.plot(p, tp, 'k')
skew.shade_cape(p, t, tp)
skew.shade_cin(p, t, tp)
return fig


@pytest.mark.mpl_image_compare(tolerance={'1.4': 1.70}.get(MPL_VERSION, 0.), remove_text=True)
def test_skewt_shade_area(test_profile):
"""Test shading areas on a SkewT plot."""
p, t, tp = test_profile
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig)
skew.plot(p, t, 'r')
skew.plot(p, tp, 'k')
skew.shade_area(p, t, tp)
return fig


def test_skewt_shade_area_invalid(test_profile):
"""Test shading areas on a SkewT plot."""
p, t, tp = test_profile
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig)
skew.plot(p, t, 'r')
skew.plot(p, tp, 'k')
with pytest.raises(ValueError):
skew.shade_area(p, t, tp, which='positve')


@pytest.mark.mpl_image_compare(tolerance={'1.4': 1.75}.get(MPL_VERSION, 0.), remove_text=True)
def test_skewt_shade_area_kwargs(test_profile):
"""Test shading areas on a SkewT plot with kwargs."""
p, t, tp = test_profile
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig)
skew.plot(p, t, 'r')
skew.plot(p, tp, 'k')
skew.shade_area(p, t, tp, facecolor='m')
return fig


@pytest.mark.mpl_image_compare(tolerance=0, remove_text=True)
def test_hodograph_api():
"""Basic test of Hodograph API."""
Expand Down