Skip to content

Commit 2bb7ea8

Browse files
committed
MNT: expire legend-related deprecations
1 parent 2d319fe commit 2bb7ea8

File tree

4 files changed

+24
-34
lines changed

4 files changed

+24
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Mixing positional and keyword arguments for ``legend`` handles and labels...
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... is no longer valid. If passing *handles* and *labels* to ``legend``, they must
4+
now be passed either both positionally or both as keywords.
5+
6+
Legend labels for ``plot``
7+
~~~~~~~~~~~~~~~~~~~~~~~~~~
8+
Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when
9+
plotting a single dataset, the sequence was automatically cast to string for the legend
10+
label. Now, if the sequence length is not one an error is raised. To keep the old
11+
behavior, cast the sequence to string before passing.

lib/matplotlib/axes/_base.py

-7
Original file line numberDiff line numberDiff line change
@@ -523,13 +523,6 @@ def _plot_args(self, axes, tup, kwargs, *,
523523
labels = [label] * n_datasets
524524
elif len(label) == n_datasets:
525525
labels = label
526-
elif n_datasets == 1:
527-
msg = (f'Passing label as a length {len(label)} sequence when '
528-
'plotting a single dataset is deprecated in Matplotlib 3.9 '
529-
'and will error in 3.11. To keep the current behavior, '
530-
'cast the sequence to string before passing.')
531-
_api.warn_deprecated('3.9', message=msg)
532-
labels = [label]
533526
else:
534527
raise ValueError(
535528
f"label must be scalar or have the same length as the input "

lib/matplotlib/legend.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs):
12861286
legend(handles=handles, labels=labels)
12871287
12881288
The behavior for a mixture of positional and keyword handles and labels
1289-
is undefined and issues a warning; it will be an error in the future.
1289+
is undefined and raises an error.
12901290
12911291
Parameters
12921292
----------
@@ -1319,10 +1319,8 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs):
13191319
handlers = kwargs.get('handler_map')
13201320

13211321
if (handles is not None or labels is not None) and args:
1322-
_api.warn_deprecated("3.9", message=(
1323-
"You have mixed positional and keyword arguments, some input may "
1324-
"be discarded. This is deprecated since %(since)s and will "
1325-
"become an error in %(removal)s."))
1322+
raise TypeError("When passing handles and labels, they must both be "
1323+
"passed positionally or both as keywords.")
13261324

13271325
if (hasattr(handles, "__len__") and
13281326
hasattr(labels, "__len__") and

lib/matplotlib/tests/test_legend.py

+10-22
Original file line numberDiff line numberDiff line change
@@ -390,17 +390,14 @@ def test_legend_kwargs_handles_labels(self):
390390
ax.legend(labels=('a', 'b'), handles=(lnc, lns))
391391
Legend.assert_called_with(ax, (lnc, lns), ('a', 'b'))
392392

393-
def test_warn_mixed_args_and_kwargs(self):
393+
def test_error_mixed_args_and_kwargs(self):
394394
fig, ax = plt.subplots()
395395
th = np.linspace(0, 2*np.pi, 1024)
396396
lns, = ax.plot(th, np.sin(th), label='sin')
397397
lnc, = ax.plot(th, np.cos(th), label='cos')
398-
with pytest.warns(DeprecationWarning) as record:
398+
msg = 'must both be passed positionally or both as keywords'
399+
with pytest.raises(TypeError, match=msg):
399400
ax.legend((lnc, lns), labels=('a', 'b'))
400-
assert len(record) == 1
401-
assert str(record[0].message).startswith(
402-
"You have mixed positional and keyword arguments, some input may "
403-
"be discarded.")
404401

405402
def test_parasite(self):
406403
from mpl_toolkits.axes_grid1 import host_subplot # type: ignore[import]
@@ -460,16 +457,13 @@ def test_legend_kw_args(self):
460457
fig, (lines, lines2), ('a', 'b'), loc='right',
461458
bbox_transform=fig.transFigure)
462459

463-
def test_warn_args_kwargs(self):
460+
def test_error_args_kwargs(self):
464461
fig, axs = plt.subplots(1, 2)
465462
lines = axs[0].plot(range(10))
466463
lines2 = axs[1].plot(np.arange(10) * 2.)
467-
with pytest.warns(DeprecationWarning) as record:
464+
msg = 'must both be passed positionally or both as keywords'
465+
with pytest.raises(TypeError, match=msg):
468466
fig.legend((lines, lines2), labels=('a', 'b'))
469-
assert len(record) == 1
470-
assert str(record[0].message).startswith(
471-
"You have mixed positional and keyword arguments, some input may "
472-
"be discarded.")
473467

474468

475469
def test_figure_legend_outside():
@@ -1178,21 +1172,15 @@ def test_plot_multiple_input_single_label(label):
11781172
assert legend_texts == [str(label)] * 2
11791173

11801174

1181-
@pytest.mark.parametrize('label_array', [['low', 'high'],
1182-
('low', 'high'),
1183-
np.array(['low', 'high'])])
1184-
def test_plot_single_input_multiple_label(label_array):
1175+
def test_plot_single_input_multiple_label():
11851176
# test ax.plot() with 1D array like input
11861177
# and iterable label
11871178
x = [1, 2, 3]
11881179
y = [2, 5, 6]
11891180
fig, ax = plt.subplots()
1190-
with pytest.warns(mpl.MatplotlibDeprecationWarning,
1191-
match='Passing label as a length 2 sequence'):
1192-
ax.plot(x, y, label=label_array)
1193-
leg = ax.legend()
1194-
assert len(leg.get_texts()) == 1
1195-
assert leg.get_texts()[0].get_text() == str(label_array)
1181+
with pytest.raises(ValueError,
1182+
match='label must be scalar or have the same length'):
1183+
ax.plot(x, y, label=['low', 'high'])
11961184

11971185

11981186
def test_plot_single_input_list_label():

0 commit comments

Comments
 (0)