Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4f07807

Browse files
committed
Merge pull request #5485 from ianthomas23/5477_contour_decreasing_levels
Contour levels must be increasing
2 parents d9080f4 + 4c62289 commit 4f07807

File tree

7 files changed

+63
-13
lines changed

7 files changed

+63
-13
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2015-11-16 Levels passed to contour(f) and tricontour(f) must be in increasing
2+
order.
3+
14
2015-10-21 Added get_ticks_direction()
25

36
2015-02-27 Added the rcParam 'image.composite_image' to permit users

lib/matplotlib/contour.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,12 @@ def _contour_level_args(self, z, args):
11921192
if self.filled and len(self.levels) < 2:
11931193
raise ValueError("Filled contours require at least 2 levels.")
11941194

1195+
if len(self.levels) > 1 and np.amin(np.diff(self.levels)) <= 0.0:
1196+
if hasattr(self, '_corner_mask') and self._corner_mask == 'legacy':
1197+
warnings.warn("Contour levels are not increasing")
1198+
else:
1199+
raise ValueError("Contour levels must be increasing")
1200+
11951201
def _process_levels(self):
11961202
"""
11971203
Assign values to :attr:`layers` based on :attr:`levels`,
@@ -1442,16 +1448,16 @@ def _process_args(self, *args, **kwargs):
14421448
else:
14431449
contour_generator = args[0]._contour_generator
14441450
else:
1451+
self._corner_mask = kwargs.get('corner_mask', None)
1452+
if self._corner_mask is None:
1453+
self._corner_mask = mpl.rcParams['contour.corner_mask']
1454+
14451455
x, y, z = self._contour_args(args, kwargs)
14461456

14471457
_mask = ma.getmask(z)
14481458
if _mask is ma.nomask or not _mask.any():
14491459
_mask = None
14501460

1451-
self._corner_mask = kwargs.get('corner_mask', None)
1452-
if self._corner_mask is None:
1453-
self._corner_mask = mpl.rcParams['contour.corner_mask']
1454-
14551461
if self._corner_mask == 'legacy':
14561462
cbook.warn_deprecated('1.5',
14571463
name="corner_mask='legacy'",
@@ -1674,13 +1680,15 @@ def _initialize_x_y(self, z):
16741680
contour(Z,V)
16751681
contour(X,Y,Z,V)
16761682
1677-
draw contour lines at the values specified in sequence *V*
1683+
draw contour lines at the values specified in sequence *V*,
1684+
which must be in increasing order.
16781685
16791686
::
16801687
16811688
contourf(..., V)
16821689
1683-
fill the ``len(V)-1`` regions between the values in *V*
1690+
fill the ``len(V)-1`` regions between the values in *V*,
1691+
which must be in increasing order.
16841692
16851693
::
16861694
@@ -1743,8 +1751,8 @@ def _initialize_x_y(self, z):
17431751
17441752
*levels*: [level0, level1, ..., leveln]
17451753
A list of floating point numbers indicating the level
1746-
curves to draw; e.g., to draw just the zero contour pass
1747-
``levels=[0]``
1754+
curves to draw, in increasing order; e.g., to draw just
1755+
the zero contour pass ``levels=[0]``
17481756
17491757
*origin*: [ *None* | 'upper' | 'lower' | 'image' ]
17501758
If *None*, the first value of *Z* will correspond to the

lib/matplotlib/tests/test_contour.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from matplotlib import mlab
1010
from matplotlib.testing.decorators import cleanup, image_comparison
1111
from matplotlib import pyplot as plt
12+
from nose.tools import assert_equal, assert_raises
13+
import warnings
1214

1315
import re
1416

@@ -264,6 +266,19 @@ def test_corner_mask():
264266
plt.contourf(z, corner_mask=corner_mask)
265267

266268

269+
@cleanup
270+
def test_contourf_decreasing_levels():
271+
# github issue 5477.
272+
z = [[0.1, 0.3], [0.5, 0.7]]
273+
plt.figure()
274+
assert_raises(ValueError, plt.contourf, z, [1.0, 0.0])
275+
# Legacy contouring algorithm gives a warning rather than raising an error,
276+
# plus a DeprecationWarning.
277+
with warnings.catch_warnings(record=True) as w:
278+
plt.contourf(z, [1.0, 0.0], corner_mask='legacy')
279+
assert_equal(len(w), 2)
280+
281+
267282
if __name__ == '__main__':
268283
import nose
269284
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

lib/matplotlib/tests/test_triangulation.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from numpy.testing import assert_array_equal, assert_array_almost_equal,\
1111
assert_array_less
1212
import numpy.ma.testutils as matest
13-
from matplotlib.testing.decorators import image_comparison
13+
from matplotlib.testing.decorators import cleanup, image_comparison
1414
import matplotlib.cm as cm
1515
from matplotlib.path import Path
1616

@@ -1021,6 +1021,16 @@ def test_trianalyzer_mismatched_indices():
10211021
triang2 = analyser._get_compressed_triangulation()
10221022

10231023

1024+
@cleanup
1025+
def test_tricontourf_decreasing_levels():
1026+
# github issue 5477.
1027+
x = [0.0, 1.0, 1.0]
1028+
y = [0.0, 0.0, 1.0]
1029+
z = [0.2, 0.4, 0.6]
1030+
plt.figure()
1031+
assert_raises(ValueError, plt.tricontourf, x, y, z, [1.0, 0.0])
1032+
1033+
10241034
if __name__ == '__main__':
10251035
import nose
10261036
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

lib/matplotlib/tri/_tri_wrapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,12 @@ static PyObject* PyTriContourGenerator_create_filled_contour(PyTriContourGenerat
295295
return NULL;
296296
}
297297

298+
if (lower_level >= upper_level)
299+
{
300+
PyErr_SetString(PyExc_ValueError,
301+
"filled contour levels must be increasing");
302+
}
303+
298304
PyObject* result;
299305
CALL_CPP("create_filled_contour",
300306
(result = self->ptr->create_filled_contour(lower_level,

lib/matplotlib/tri/tricontour.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,15 @@ def _contour_args(self, args, kwargs):
141141
142142
tricontour(..., Z, V)
143143
144-
draw contour lines at the values specified in sequence *V*
144+
draw contour lines at the values specified in sequence *V*,
145+
which must be in increasing order.
145146
146147
::
147148
148149
tricontourf(..., Z, V)
149150
150-
fill the (len(*V*)-1) regions between the values in *V*
151+
fill the (len(*V*)-1) regions between the values in *V*,
152+
which must be in increasing order.
151153
152154
::
153155
@@ -186,8 +188,8 @@ def _contour_args(self, args, kwargs):
186188
187189
*levels* [level0, level1, ..., leveln]
188190
A list of floating point numbers indicating the level
189-
curves to draw; e.g., to draw just the zero contour pass
190-
``levels=[0]``
191+
curves to draw, in increasing order; e.g., to draw just
192+
the zero contour pass ``levels=[0]``
191193
192194
*origin*: [ *None* | 'upper' | 'lower' | 'image' ]
193195
If *None*, the first value of *Z* will correspond to the

src/_contour_wrapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ static PyObject* PyQuadContourGenerator_create_filled_contour(PyQuadContourGener
9797
return NULL;
9898
}
9999

100+
if (lower_level >= upper_level)
101+
{
102+
PyErr_SetString(PyExc_ValueError,
103+
"filled contour levels must be increasing");
104+
}
105+
100106
PyObject* result;
101107
CALL_CPP("create_filled_contour",
102108
(result = self->ptr->create_filled_contour(lower_level,

0 commit comments

Comments
 (0)