Skip to content

Commit

Permalink
adds feature: Enhance draw_contours to Support Filled Contours (#7281)
Browse files Browse the repository at this point in the history
* Update mapbase.py - Add 'fill' keyword to draw_contours function. 

Added the 'fill' keyword to the draw_contours function, enabling the option to display filled contours using `~matplotlib.axes.Axes.contourf` in addition to the standard line contours. This enhancement provides users more flexibility in visualizing contour plots.

* add changelog rst.

* Tests plus figure hashes

* Apply suggestions from code review

Co-authored-by: Albert Y. Shih <ayshih@gmail.com>

* Apply suggestions from code review

Co-authored-by: Albert Y. Shih <ayshih@gmail.com>

* fix the figure hashes I messed up

* fix devdeps hash

---------

Co-authored-by: Nabil Freij <nabil.freij@gmail.com>
Co-authored-by: Albert Y. Shih <ayshih@gmail.com>
Co-authored-by: Will Barnes <will.t.barnes@gmail.com>
  • Loading branch information
4 people committed Mar 20, 2024
1 parent cf78fb4 commit fb9c959
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 5 deletions.
1 change: 1 addition & 0 deletions changelog/7281.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for the ``fill`` keyword in :meth:`~sunpy.map.GenericMap.draw_contours` to allow for filled contours.
24 changes: 20 additions & 4 deletions sunpy/map/mapbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -2316,7 +2316,7 @@ def _process_levels_arg(self, levels):
raise u.UnitsError("This map has no unit, so levels can only be specified in percent "
"or in u.dimensionless_unscaled units.")

def draw_contours(self, levels, axes=None, **contour_args):
def draw_contours(self, levels, axes=None, *, fill=False, **contour_args):
"""
Draw contours of the data.
Expand All @@ -2329,6 +2329,10 @@ def draw_contours(self, levels, axes=None, **contour_args):
axes : `matplotlib.axes.Axes`
The axes on which to plot the contours. Defaults to the current
axes.
fill : `bool`, optional
Determines the style of the contours:
- If `False` (default), contours are drawn as lines using :meth:`~matplotlib.axes.Axes.contour`.
- If `True`, contours are drawn as filled regions using :meth:`~matplotlib.axes.Axes.contourf`.
Returns
-------
Expand All @@ -2339,10 +2343,9 @@ def draw_contours(self, levels, axes=None, **contour_args):
Notes
-----
Extra keyword arguments to this function are passed through to the
`~matplotlib.axes.Axes.contour` function.
corresponding matplotlib method.
"""
axes = self._check_axes(axes)

levels = self._process_levels_arg(levels)

# Pixel indices
Expand All @@ -2362,7 +2365,20 @@ def draw_contours(self, levels, axes=None, **contour_args):
# Mask out the data array anywhere the coordinate arrays are not finite
data = np.ma.array(data, mask=~np.logical_and(np.isfinite(x), np.isfinite(y)))

cs = axes.contour(x, y, data, levels, **contour_args)
if fill:
# Ensure we have more than one level if fill is True
if len(levels) == 1:
max_val = np.nanmax(self.data)
# Ensure the existing level is less than max_val
if levels[0] < max_val:
levels = np.append(levels, max_val)
else:
raise ValueError(
f"The provided level ({levels[0]}) is not smaller than the maximum data value ({max_val}). "
"Contour level must be smaller than the maximum data value to use `fill=True`.")
cs = axes.contourf(x, y, data, levels, **contour_args)
else:
cs = axes.contour(x, y, data, levels, **contour_args)
return cs

@peek_show
Expand Down
10 changes: 9 additions & 1 deletion sunpy/map/tests/test_mapbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import pytest
from hypothesis import HealthCheck, given, settings
from matplotlib.figure import Figure
from packaging.version import Version

import astropy.units as u
import astropy.wcs
Expand Down Expand Up @@ -1399,8 +1400,15 @@ def test_contour_units(simple_map):
for c1, c2 in zip(contours_percent, contours_ref):
assert np.all(c1 == c2)

@pytest.mark.skipif(Version(matplotlib.__version__) < Version("3.6.0"), reason="Fails on old MPL versions, the first with block raises a different error")
def test_contour_inputs(simple_map):
with pytest.raises(ValueError, match='Contour levels must be increasing'):
simple_map.draw_contours([10, -10] * u.dimensionless_unscaled)

with pytest.raises(ValueError, match=r'The provided level \(1000.0\) is not smaller than the maximum data value \(8\)'):
simple_map.draw_contours(1000 * u.dimensionless_unscaled, fill=True)


def test_contour_input(simple_map):
simple_map.meta['bunit'] = 'm'

with pytest.raises(TypeError, match='The levels argument has no unit attribute'):
Expand Down
6 changes: 6 additions & 0 deletions sunpy/map/tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ def test_draw_contours_different_wcs(aia171_test_map):
aia171_test_map.draw_contours(u.Quantity(np.arange(1, 100, 10), 'percent'))


@figure_test
def test_draw_contours_aia_fill(aia171_test_map):
aia171_test_map.plot()
aia171_test_map.draw_contours(u.Quantity(np.arange(1, 100, 10), 'percent'), fill=True)


@figure_test
def test_heliographic_peek(heliographic_test_map):
heliographic_test_map.peek()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"sunpy.map.tests.test_plotting.test_plot_masked_aia171_superpixel": "ffabe0ca544b93c8084af36edb5b293cdce613d13b73ddeaa906ddf2617da34b",
"sunpy.map.tests.test_plotting.test_draw_contours_aia": "9b899f6ae244186a29f27b4167ea75b355428fbd69166cd55903e52b8f5fbf0b",
"sunpy.map.tests.test_plotting.test_draw_contours_different_wcs": "5f2abc715e899ad9b9425acfe1beb41a915423b93737781c348dfa0b99de8180",
"sunpy.map.tests.test_plotting.test_draw_contours_aia_fill": "9b12d674a94acd33b025536bc74ac88735599702684dec3d6510f6b1b39a605b",
"sunpy.map.tests.test_plotting.test_heliographic_peek": "662a24f525b30ce89ba15b7668518f31d439fa8b0c5ba84da2a71bbda31edb9a",
"sunpy.map.tests.test_plotting.test_heliographic_quadrangle_width_height": "a52dca9100f3f96644e924f283c7ba9bd26db115be3a8e19b91898406d06f9ba",
"sunpy.map.tests.test_plotting.test_heliographic_quadrangle_top_right": "40591e49e6b32ec3a27b6fc50b9e2fdfcaa9665eca70b6a515dfb9dc7c0b1724",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"sunpy.map.tests.test_plotting.test_plot_masked_aia171_superpixel": "854f60a854e0f3166762c94831445b83f5402a8aa70e34013616f7e4074476fe",
"sunpy.map.tests.test_plotting.test_draw_contours_aia": "90f83a5c24fdd88a1d14807034ba2b4ee1644d3f53745935eb8e537a2acc2b9a",
"sunpy.map.tests.test_plotting.test_draw_contours_different_wcs": "9cbb12775ed1da71226dcc500f434bdf0ece76d54894942fb34c1805d8d11de0",
"sunpy.map.tests.test_plotting.test_draw_contours_aia_fill": "abd8a02404ddcd6a4490b6b4a7d7bb0987fec7fa74cec9224bf58dcbad19985b",
"sunpy.map.tests.test_plotting.test_heliographic_peek": "662a24f525b30ce89ba15b7668518f31d439fa8b0c5ba84da2a71bbda31edb9a",
"sunpy.map.tests.test_plotting.test_heliographic_quadrangle_width_height": "a52dca9100f3f96644e924f283c7ba9bd26db115be3a8e19b91898406d06f9ba",
"sunpy.map.tests.test_plotting.test_heliographic_quadrangle_top_right": "40591e49e6b32ec3a27b6fc50b9e2fdfcaa9665eca70b6a515dfb9dc7c0b1724",
Expand Down

0 comments on commit fb9c959

Please sign in to comment.