From ffc7ab0990cf994f08fee286db326a2c28a8fce3 Mon Sep 17 00:00:00 2001
From: Ruth Comer <10599679+rcomer@users.noreply.github.com>
Date: Sat, 10 Feb 2024 14:02:12 +0000
Subject: [PATCH] Update handling of sequence labels for plot

---
 .../next_api_changes/behavior/27767-REC.rst   |  7 +++++++
 .../deprecations/27767-REC.rst                |  9 +++++++++
 lib/matplotlib/axes/_base.py                  | 20 +++++++++++++------
 lib/matplotlib/tests/test_legend.py           | 10 +++++++++-
 4 files changed, 39 insertions(+), 7 deletions(-)
 create mode 100644 doc/api/next_api_changes/behavior/27767-REC.rst
 create mode 100644 doc/api/next_api_changes/deprecations/27767-REC.rst

diff --git a/doc/api/next_api_changes/behavior/27767-REC.rst b/doc/api/next_api_changes/behavior/27767-REC.rst
new file mode 100644
index 000000000000..f6b4dc156732
--- /dev/null
+++ b/doc/api/next_api_changes/behavior/27767-REC.rst
@@ -0,0 +1,7 @@
+Legend labels for ``plot``
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when
+plotting a single dataset, the sequence was automatically cast to string for the legend
+label.  Now, if the sequence has only one element, that element will be the legend
+label.  To keep the old behavior, cast the sequence to string before passing.
diff --git a/doc/api/next_api_changes/deprecations/27767-REC.rst b/doc/api/next_api_changes/deprecations/27767-REC.rst
new file mode 100644
index 000000000000..68781090df0a
--- /dev/null
+++ b/doc/api/next_api_changes/deprecations/27767-REC.rst
@@ -0,0 +1,9 @@
+Legend labels for ``plot``
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when
+plotting a single dataset, the sequence was automatically cast to string for the legend
+label.  This behavior is now deprecated and in future will error if the sequence length
+is not one (consistent with multi-dataset behavior, where the number of elements must
+match the number of datasets).  To keep the old behavior, cast the sequence to string
+before passing.
diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py
index 51347f08b989..0617fc7681bd 100644
--- a/lib/matplotlib/axes/_base.py
+++ b/lib/matplotlib/axes/_base.py
@@ -513,14 +513,22 @@ def _plot_args(self, axes, tup, kwargs, *,
 
         label = kwargs.get('label')
         n_datasets = max(ncx, ncy)
-        if n_datasets > 1 and not cbook.is_scalar_or_string(label):
-            if len(label) != n_datasets:
-                raise ValueError(f"label must be scalar or have the same "
-                                 f"length as the input data, but found "
-                                 f"{len(label)} for {n_datasets} datasets.")
+
+        if cbook.is_scalar_or_string(label):
+            labels = [label] * n_datasets
+        elif len(label) == n_datasets:
             labels = label
+        elif n_datasets == 1:
+            msg = (f'Passing label as a length {len(label)} sequence when '
+                    'plotting a single dataset is deprecated in Matplotlib 3.9 '
+                    'and will error in 3.11.  To keep the current behavior, '
+                    'cast the sequence to string before passing.')
+            _api.warn_deprecated('3.9', message=msg)
+            labels = [label]
         else:
-            labels = [label] * n_datasets
+            raise ValueError(
+                f"label must be scalar or have the same length as the input "
+                f"data, but found {len(label)} for {n_datasets} datasets.")
 
         result = (make_artist(axes, x[:, j % ncx], y[:, j % ncy], kw,
                               {**kwargs, 'label': label})
diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py
index b23649f22e48..73892698882c 100644
--- a/lib/matplotlib/tests/test_legend.py
+++ b/lib/matplotlib/tests/test_legend.py
@@ -1197,12 +1197,20 @@ def test_plot_single_input_multiple_label(label_array):
     x = [1, 2, 3]
     y = [2, 5, 6]
     fig, ax = plt.subplots()
-    ax.plot(x, y, label=label_array)
+    with pytest.warns(mpl.MatplotlibDeprecationWarning,
+                      match='Passing label as a length 2 sequence'):
+        ax.plot(x, y, label=label_array)
     leg = ax.legend()
     assert len(leg.get_texts()) == 1
     assert leg.get_texts()[0].get_text() == str(label_array)
 
 
+def test_plot_single_input_list_label():
+    fig, ax = plt.subplots()
+    line, = ax.plot([[0], [1]], label=['A'])
+    assert line.get_label() == 'A'
+
+
 def test_plot_multiple_label_incorrect_length_exception():
     # check that exception is raised if multiple labels
     # are given, but number of on labels != number of lines