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

Skip to content

Commit c1a9443

Browse files
committed
Better default bool contour levels.
1 parent ecf2c88 commit c1a9443

File tree

4 files changed

+41
-14
lines changed

4 files changed

+41
-14
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``contour`` and ``contourf`` auto-select suitable levels when given boolean inputs
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
If the height array given to `.Axes.contour` or `.Axes.contourf` is of bool
4+
dtype and *levels* is not specified, *levels* now defaults to ``[0.5]`` for
5+
`~.Axes.contour` and ``[0, 0.5, 1]`` for `.Axes.contourf`.

lib/matplotlib/contour.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,15 +1117,20 @@ def _autolev(self, N):
11171117

11181118
return lev[i0:i1]
11191119

1120-
def _process_contour_level_args(self, args):
1120+
def _process_contour_level_args(self, args, z_dtype):
11211121
"""
11221122
Determine the contour levels and store in self.levels.
11231123
"""
11241124
if self.levels is None:
1125-
if len(args) == 0:
1126-
levels_arg = 7 # Default, hard-wired.
1127-
else:
1125+
if args:
11281126
levels_arg = args[0]
1127+
elif z_dtype.char == "?": # bool
1128+
if self.filled:
1129+
levels_arg = [0, .5, 1]
1130+
else:
1131+
levels_arg = [.5]
1132+
else:
1133+
levels_arg = 7 # Default, hard-wired.
11291134
else:
11301135
levels_arg = self.levels
11311136
if isinstance(levels_arg, Integral):
@@ -1447,12 +1452,12 @@ def _contour_args(self, args, kwargs):
14471452
fn = 'contour'
14481453
nargs = len(args)
14491454
if nargs <= 2:
1450-
z = ma.asarray(args[0], dtype=np.float64)
1455+
z, *args = args
1456+
z = ma.asarray(z)
14511457
x, y = self._initialize_x_y(z)
1452-
args = args[1:]
14531458
elif nargs <= 4:
1454-
x, y, z = self._check_xyz(args[:3], kwargs)
1455-
args = args[3:]
1459+
x, y, z_orig, *args = args
1460+
x, y, z = self._check_xyz(x, y, z_orig, kwargs)
14561461
else:
14571462
raise _api.nargs_error(fn, takes="from 1 to 4", given=nargs)
14581463
z = ma.masked_invalid(z, copy=False)
@@ -1462,20 +1467,19 @@ def _contour_args(self, args, kwargs):
14621467
z = ma.masked_where(z <= 0, z)
14631468
_api.warn_external('Log scale: values of z <= 0 have been masked')
14641469
self.zmin = float(z.min())
1465-
self._process_contour_level_args(args)
1470+
self._process_contour_level_args(args, z.dtype)
14661471
return (x, y, z)
14671472

1468-
def _check_xyz(self, args, kwargs):
1473+
def _check_xyz(self, x, y, z, kwargs):
14691474
"""
14701475
Check that the shapes of the input arrays match; if x and y are 1D,
14711476
convert them to 2D using meshgrid.
14721477
"""
1473-
x, y = args[:2]
14741478
x, y = self.axes._process_unit_info([("x", x), ("y", y)], kwargs)
14751479

14761480
x = np.asarray(x, dtype=np.float64)
14771481
y = np.asarray(y, dtype=np.float64)
1478-
z = ma.asarray(args[2], dtype=np.float64)
1482+
z = ma.asarray(z)
14791483

14801484
if z.ndim != 2:
14811485
raise TypeError(f"Input z must be 2D, not {z.ndim}D")

lib/matplotlib/tests/test_contour.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,3 +693,20 @@ def test_contour_remove():
693693
assert ax.get_children() != orig_children
694694
cs.remove()
695695
assert ax.get_children() == orig_children
696+
697+
698+
def test_bool_autolevel():
699+
x, y = np.random.rand(2, 9)
700+
z = (np.arange(9) % 2).reshape((3, 3)).astype(bool)
701+
m = [[False, False, False], [False, True, False], [False, False, False]]
702+
assert plt.contour(z.tolist()).levels.tolist() == [.5]
703+
assert plt.contour(z).levels.tolist() == [.5]
704+
assert plt.contour(np.ma.array(z, mask=m)).levels.tolist() == [.5]
705+
assert plt.contourf(z.tolist()).levels.tolist() == [0, .5, 1]
706+
assert plt.contourf(z).levels.tolist() == [0, .5, 1]
707+
assert plt.contourf(np.ma.array(z, mask=m)).levels.tolist() == [0, .5, 1]
708+
z = z.ravel()
709+
assert plt.tricontour(x, y, z.tolist()).levels.tolist() == [.5]
710+
assert plt.tricontour(x, y, z).levels.tolist() == [.5]
711+
assert plt.tricontourf(x, y, z.tolist()).levels.tolist() == [0, .5, 1]
712+
assert plt.tricontourf(x, y, z).levels.tolist() == [0, .5, 1]

lib/matplotlib/tri/_tricontour.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ def _process_args(self, *args, **kwargs):
5353
def _contour_args(self, args, kwargs):
5454
tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args,
5555
**kwargs)
56-
z = np.ma.asarray(args[0])
56+
z, *args = args
57+
z = np.ma.asarray(z)
5758
if z.shape != tri.x.shape:
5859
raise ValueError('z array must have same length as triangulation x'
5960
' and y arrays')
@@ -74,7 +75,7 @@ def _contour_args(self, args, kwargs):
7475
if self.logscale and self.zmin <= 0:
7576
func = 'contourf' if self.filled else 'contour'
7677
raise ValueError(f'Cannot {func} log of negative values.')
77-
self._process_contour_level_args(args[1:])
78+
self._process_contour_level_args(args, z.dtype)
7879
return (tri, z)
7980

8081

0 commit comments

Comments
 (0)