10000 Merge pull request #18122 from timhoffm/legend-labels2 · matplotlib/matplotlib@7f0ff04 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7f0ff04

Browse files
authored
Merge pull request #18122 from timhoffm/legend-labels2
Document and test legend argument parsing
2 parents 9fa9efb + 0cbe4fc commit 7f0ff04

File tree

2 files changed

+78
-20
lines changed

2 files changed

+78
-20
lines changed

lib/matplotlib/legend.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,45 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs):
11621162
Get the handles and labels from the calls to either ``figure.legend``
11631163
or ``axes.legend``.
11641164
1165-
``axs`` is a list of axes (to get legend artists from)
1165+
The parser is a bit involved because we support::
1166+
1167+
legend()
1168+
legend(labels)
1169+
legend(handles, labels)
1170+
legend(labels=labels)
1171+
legend(handles=handles)
1172+
legend(handles=handles, labels=labels)
1173+
1174+
The behavior for a mixture of positional and keyword handles and labels
1175+
is undefined and issues a warning.
1176+
1177+
Parameters
1178+
----------
1179+
axs : list of `.Axes`
1180+
If handles are not given explicitly, the artists in these Axes are
1181+
used as handles.
1182+
*args : tuple
1183+
Positional parameters passed to ``legend()``.
1184+
handles
1185+
The value of the keyword argument ``legend(handles=...)``, or *None*
1186+
if that keyword argument was not used.
1187+
labels
1188+
The value of the keyword argument ``legend(labels=...)``, or *None*
1189+
if that keyword argument was not used.
1190+
**kwargs
1191+
All other keyword arguments passed to ``legend()``.
1192+
1193+
Returns
1194+
-------
1195+
handles : list of `.Artist`
1196+
The legend handles.
1197+
labels : list of str
1198+
The legend labels.
1199+
extra_args : tuple
1200+
*args* with positional handles and labels removed.
1201+
kwargs : dict
1202+
*kwargs* with keywords handles and labels removed.
1203+
11661204
"""
11671205
log = logging.getLogger(__name__)
11681206

lib/matplotlib/tests/test_legend.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def test_multiple_keys():
107107
@image_comparison(['rgba_alpha.png'], remove_text=True,
108108
tol=0 if platform.machine() == 'x86_64' else 0.01)
109109
def test_alpha_rgba():
110-
fig, ax = plt.subplots(1, 1)
110+
fig, ax = plt.subplots()
111111
ax.plot(range(10), lw=5)
112112
leg = plt.legend(['Longlabel that will go away'], loc='center')
113113
leg.legendPatch.set_facecolor([1, 0, 0, 0.5])
@@ -116,7 +116,7 @@ def test_alpha_rgba():
116116
@image_comparison(['rcparam_alpha.png'], remove_text=True,
117117
tol=0 if platform.machine() == 'x86_64' else 0.01)
118118
def test_alpha_rcparam():
119-
fig, ax = plt.subplots(1, 1)
119+
fig, ax = plt.subplots()
120120
ax.plot(range(10), lw=5)
121121
with mpl.rc_context(rc={'legend.framealpha': .75}):
122122
leg = plt.legend(['Longlabel that will go away'], loc='center')
@@ -228,26 +228,26 @@ def test_legend_remove():
228228

229229
class TestLegendFunction:
230230
# Tests the legend function on the Axes and pyplot.
231-
def test_legend_handle_label(self):
231+
def test_legend_no_args(self):
232+
lines = plt.plot(range(10), label='hello world')
233+
with mock.patch('matplotlib.legend.Legend') as Legend:
234+
plt.legend()
235+
Legend.assert_called_with(plt.gca(), lines, ['hello world'])
236+
237+
def test_legend_positional_handles_labels(self):
232238
lines = plt.plot(range(10))
233239
with mock.patch('matplotlib.legend.Legend') as Legend:
234240
plt.legend(lines, ['hello world'])
235241
Legend.assert_called_with(plt.gca(), lines, ['hello world'])
236242

237-
def test_legend_handles_only(self):
243+
def test_legend_positional_handles_only(self):
238244
lines = plt.plot(range(10))
239245
with pytest.raises(TypeError, match='but found an Artist'):
240246
# a single arg is interpreted as labels
241247
# it's a common error to just pass handles
242248
plt.legend(lines)
243249

244-
def test_legend_no_args(self):
245-
lines = plt.plot(range(10), label='hello world')
246-
with mock.patch('matplotlib.legend.Legend') as Legend:
247-
plt.legend()
248-
Legend.assert_called_with(plt.gca(), lines, ['hello world'])
249-
250-
def test_legend_label_args(self):
250+
def test_legend_positional_labels_only(self):
251251
lines = plt.plot(range(10), label='hello world')
252252
with mock.patch('matplotlib.legend.Legend') as Legend:
253253
plt.legend(['foobar'])
@@ -267,20 +267,40 @@ def test_legend_handler_map(self):
267267
plt.legend(handler_map={'1': 2})
268268
handles_labels.assert_called_with([plt.gca()], {'1': 2})
269269

270-
def test_kwargs(self):
271-
fig, ax = plt.subplots(1, 1)
270+
def test_legend_kwargs_handles_only(self):
271+
fig, ax = plt.subplots()
272+
x = np.linspace(0, 1, 11)
273+
ln1, = ax.plot(x, x, label='x')
274+
ln2, = ax.plot(x, 2*x, label='2x')
275+
ln3, = ax.plot(x, 3*x, label='3x')
276+
with mock.patch('matplotlib.legend.Legend') as Legend:
277+
ax.legend(handles=[ln3, ln2]) # reversed and not ln1
278+
Legend.assert_called_with(ax, [ln3, ln2], ['3x', '2x'])
279+
280+
def test_legend_kwargs_labels_only(self):
281+
fig, ax = plt.subplots()
282+
x = np.linspace(0, 1, 11)
283+
ln1, = ax.plot(x, x)
284+
ln2, = ax.plot(x, 2*x)
285+
with mock.patch('matplotlib.legend.Legend') as Legend:
286+
ax.legend(labels=['x', '2x'])
287+
Legend.assert_called_with(ax, [ln1, ln2], ['x', '2x'])
288+
289+
def test_legend_kwargs_handles_labels(self):
290+
fig, ax = plt.subplots()
272291
th = np.linspace(0, 2*np.pi, 1024)
273-
lns, = ax.plot(th, np.sin(th), label='sin', lw=5)
274-
lnc, = ax.plot(th, np.cos(th), label='cos', lw=5)
292+
lns, = ax.plot(th, np.sin(th), label='sin')
293+
lnc, = ax.plot(th, np.cos(th), label='cos')
275294
with mock.patch('matplotlib.legend.Legend') as Legend:
295+
# labels of lns, lnc are overwritten with explict ('a', 'b')
276296
ax.legend(labels=('a', 'b'), handles=(lnc, lns))
277297
Legend.assert_called_with(ax, (lnc, lns), ('a', 'b'))
278298

279-
def test_warn_args_kwargs(self):
280-
fig, ax = plt.subplots(1, 1)
299+
def test_warn_mixed_args_and_kwargs(self):
300+
fig, ax = plt.subplots()
281301
th = np.linspace(0, 2*np.pi, 1024)
282-
lns, = ax.plot(th, np.sin(th), label='sin', lw=5)
283-
lnc, = ax.plot(th, np.cos(th), label='cos', lw=5)
302+
lns, = ax.plot(th, np.sin(th), label='sin')
303+
lnc, = ax.plot(th, np.cos(th), label='cos')
284304
with pytest.warns(UserWarning) as record:
285305
ax.legend((lnc, lns), labels=('a', 'b'))
286306
assert len(record) == 1

0 commit comments

Comments
 (0)
0