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

Skip to content

Commit ee241ad

Browse files
ENH: Change logging to warning when creating a legend with no labels (#27172)
* ENH: Change logging to warning when creating a legend with no labels Fixes #27145 Also add test_legend_nolabels_warning() * TST: Add mock labels to mock data. * DOC: Note warning in legend() documentation * DOC: Correct examples to no longer raise UserWarning With modified explanation where appropriate * TST: Add test for drawing empty legend() * TST: Test legend for specific warning when no labels present Also: DOC: Correct Axes docstring when no labels in legend. * TST: Filter no labels warning by message. Also assert that a legend is at least created
1 parent 379989e commit ee241ad

File tree

5 files changed

+59
-42
lines changed

5 files changed

+59
-42
lines changed

galleries/examples/text_labels_and_annotations/custom_legends.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@
2828
# Fixing random state for reproducibility
2929
np.random.seed(19680801)
3030

31+
# %%
3132
N = 10
3233
data = (np.geomspace(1, 10, 100) + np.random.randn(N, 100)).T
3334
cmap = plt.cm.coolwarm
3435
mpl.rcParams['axes.prop_cycle'] = cycler(color=cmap(np.linspace(0, 1, N)))
3536

3637
fig, ax = plt.subplots()
3738
lines = ax.plot(data)
38-
ax.legend()
3939

4040
# %%
41-
# Note that no legend entries were created.
41+
# Since the data does not have any labels, creating a legend requires
42+
# us to define the icons and labels.
4243
# In this case, we can compose a legend using Matplotlib objects that aren't
4344
# explicitly tied to the data that was plotted. For example:
4445

lib/matplotlib/axes/_axes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ def legend(self, *args, **kwargs):
239239
selection by using a label starting with an underscore, "_".
240240
A string starting with an underscore is the default label for all
241241
artists, so calling `.Axes.legend` without any arguments and
242-
without setting the labels manually will result in no legend being
243-
drawn.
242+
without setting the labels manually will result in a ``UserWarning``
243+
and an empty legend being drawn.
244244
245245
246246
**2. Explicitly listing the artists and labels in the legend**

lib/matplotlib/legend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,7 +1360,7 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs):
13601360
elif len(args) == 0: # 0 args: automatically detect labels and handles.
13611361
handles, labels = _get_legend_handles_labels(axs, handlers)
13621362
if not handles:
1363-
log.warning(
1363+
_api.warn_external(
13641364
"No artists with labels found to put in legend. Note that "
13651365
"artists whose label start with an underscore are ignored "
13661366
"when legend() is called with no argument.")

lib/matplotlib/tests/test_legend.py

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ def test_handler_numpoints():
636636
def test_text_nohandler_warning():
637637
"""Test that Text artists with labels raise a warning"""
638638
fig, ax = plt.subplots()
639+
ax.plot([0], label="mock data")
639640
ax.text(x=0, y=0, s="text", label="label")
640641
with pytest.warns(UserWarning) as record:
641642
ax.legend()
@@ -703,7 +704,7 @@ def test_legend_title_empty():
703704
# it comes back as an empty string, and that it is not
704705
# visible:
705706
fig, ax = plt.subplots()
706-
ax.plot(range(10))
707+
ax.plot(range(10), label="mock data")
707708
leg = ax.legend()
708709
assert leg.get_title().get_text() == ""
709710
assert not leg.get_title().get_visible()
@@ -736,7 +737,7 @@ def test_window_extent_cached_renderer():
736737

737738
def test_legend_title_fontprop_fontsize():
738739
# test the title_fontsize kwarg
739-
plt.plot(range(10))
740+
plt.plot(range(10), label="mock data")
740741
with pytest.raises(ValueError):
741742
plt.legend(title='Aardvark', title_fontsize=22,
742743
title_fontproperties={'family': 'serif', 'size': 22})
@@ -747,27 +748,27 @@ def test_legend_title_fontprop_fontsize():
747748

748749
fig, axes = plt.subplots(2, 3, figsize=(10, 6))
749750
axes = axes.flat
750-
axes[0].plot(range(10))
751+
axes[0].plot(range(10), label="mock data")
751752
leg0 = axes[0].legend(title='Aardvark', title_fontsize=22)
752753
assert leg0.get_title().get_fontsize() == 22
753-
axes[1].plot(range(10))
754+
axes[1].plot(range(10), label="mock data")
754755
leg1 = axes[1].legend(title='Aardvark',
755756
title_fontproperties={'family': 'serif', 'size': 22})
756757
assert leg1.get_title().get_fontsize() == 22
757-
axes[2].plot(range(10))
758+
axes[2].plot(range(10), label="mock data")
758759
mpl.rcParams['legend.title_fontsize'] = None
759760
leg2 = axes[2].legend(title='Aardvark',
760761
title_fontproperties={'family': 'serif'})
761762
assert leg2.get_title().get_fontsize() == mpl.rcParams['font.size']
762-
axes[3].plot(range(10))
763+
axes[3].plot(range(10), label="mock data")
763764
leg3 = axes[3].legend(title='Aardvark')
764765
assert leg3.get_title().get_fontsize() == mpl.rcParams['font.size']
765-
axes[4].plot(range(10))
766+
axes[4].plot(range(10), label="mock data")
766767
mpl.rcParams['legend.title_fontsize'] = 20
767768
leg4 = axes[4].legend(title='Aardvark',
768769
title_fontproperties={'family': 'serif'})
769770
assert leg4.get_title().get_fontsize() == 20
770-
axes[5].plot(range(10))
771+
axes[5].plot(range(10), label="mock data")
771772
leg5 = axes[5].legend(title='Aardvark')
772773
assert leg5.get_title().get_fontsize() == 20
773774

@@ -1071,6 +1072,7 @@ def test_legend_labelcolor_rcparam_markerfacecolor_short():
10711072
assert mpl.colors.same_color(text.get_color(), color)
10721073

10731074

1075+
@pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend")
10741076
def test_get_set_draggable():
10751077
legend = plt.legend()
10761078
assert not legend.get_draggable()
@@ -1289,74 +1291,75 @@ def test_loc_invalid_tuple_exception():
12891291
fig, ax = plt.subplots()
12901292
with pytest.raises(ValueError, match=('loc must be string, coordinate '
12911293
'tuple, or an integer 0-10, not \\(1.1,\\)')):
1292-
ax.legend(loc=(1.1, ))
1294+
ax.legend(loc=(1.1, ), labels=["mock data"])
12931295

12941296
with pytest.raises(ValueError, match=('loc must be string, coordinate '
12951297
'tuple, or an integer 0-10, not \\(0.481, 0.4227, 0.4523\\)')):
1296-
ax.legend(loc=(0.481, 0.4227, 0.4523))
1298+
ax.legend(loc=(0.481, 0.4227, 0.4523), labels=["mock data"])
12971299

12981300
with pytest.raises(ValueError, match=('loc must be string, coordinate '
12991301
'tuple, or an integer 0-10, not \\(0.481, \'go blue\'\\)')):
1300-
ax.legend(loc=(0.481, "go blue"))
1302+
ax.legend(loc=(0.481, "go blue"), labels=["mock data"])
13011303

13021304

13031305
def test_loc_valid_tuple():
13041306
fig, ax = plt.subplots()
1305-
ax.legend(loc=(0.481, 0.442))
1306-
ax.legend(loc=(1, 2))
1307+
ax.legend(loc=(0.481, 0.442), labels=["mock data"])
1308+
ax.legend(loc=(1, 2), labels=["mock data"])
13071309

13081310

13091311
def test_loc_valid_list():
13101312
fig, ax = plt.subplots()
1311-
ax.legend(loc=[0.481, 0.442])
1312-
ax.legend(loc=[1, 2])
1313+
ax.legend(loc=[0.481, 0.442], labels=["mock data"])
1314+
ax.legend(loc=[1, 2], labels=["mock data"])
13131315

13141316

13151317
def test_loc_invalid_list_exception():
13161318
fig, ax = plt.subplots()
13171319
with pytest.raises(ValueError, match=('loc must be string, coordinate '
13181320
'tuple, or an integer 0-10, not \\[1.1, 2.2, 3.3\\]')):
1319-
ax.legend(loc=[1.1, 2.2, 3.3])
1321+
ax.legend(loc=[1.1, 2.2, 3.3], labels=["mock data"])
13201322

13211323

13221324
def test_loc_invalid_type():
13231325
fig, ax = plt.subplots()
13241326
with pytest.raises(ValueError, match=("loc must be string, coordinate "
13251327
"tuple, or an integer 0-10, not {'not': True}")):
1326-
ax.legend(loc={'not': True})
1328+
ax.legend(loc={'not': True}, labels=["mock data"])
13271329

13281330

13291331
def test_loc_validation_numeric_value():
13301332
fig, ax = plt.subplots()
1331-
ax.legend(loc=0)
1332-
ax.legend(loc=1)
1333-
ax.legend(loc=5)
1334-
ax.legend(loc=10)
1333+
ax.legend(loc=0, labels=["mock data"])
1334+
ax.legend(loc=1, labels=["mock data"])
1335+
ax.legend(loc=5, labels=["mock data"])
1336+
ax.legend(loc=10, labels=["mock data"])
13351337
with pytest.raises(ValueError, match=('loc must be string, coordinate '
13361338
'tuple, or an integer 0-10, not 11')):
1337-
ax.legend(loc=11)
1339+
ax.legend(loc=11, labels=["mock data"])
13381340

13391341
with pytest.raises(ValueError, match=('loc must be string, coordinate '
13401342
'tuple, or an integer 0-10, not -1')):
1341-
ax.legend(loc=-1)
1343+
ax.legend(loc=-1, labels=["mock data"])
13421344

13431345

13441346
def test_loc_validation_string_value():
13451347
fig, ax = plt.subplots()
1346-
ax.legend(loc='best')
1347-
ax.legend(loc='upper right')
1348-
ax.legend(loc='best')
1349-
ax.legend(loc='upper right')
1350-
ax.legend(loc='upper left')
1351-
ax.legend(loc='lower left')
1352-
ax.legend(loc='lower right')
1353-
ax.legend(loc='right')
1354-
ax.legend(loc='center left')
1355-
ax.legend(loc='center right')
1356-
ax.legend(loc='lower center')
1357-
ax.legend(loc='upper center')
1348+
labels = ["mock data"]
1349+
ax.legend(loc='best', labels=labels)
1350+
ax.legend(loc='upper right', labels=labels)
1351+
ax.legend(loc='best', labels=labels)
1352+
ax.legend(loc='upper right', labels=labels)
1353+
ax.legend(loc='upper left', labels=labels)
1354+
ax.legend(loc='lower left', labels=labels)
1355+
ax.legend(loc='lower right', labels=labels)
1356+
ax.legend(loc='right', labels=labels)
1357+
ax.legend(loc='center left', labels=labels)
1358+
ax.legend(loc='center right', labels=labels)
1359+
ax.legend(loc='lower center', labels=labels)
1360+
ax.legend(loc='upper center', labels=labels)
13581361
with pytest.raises(ValueError, match="'wrong' is not a valid value for"):
1359-
ax.legend(loc='wrong')
1362+
ax.legend(loc='wrong', labels=labels)
13601363

13611364

13621365
def test_legend_handle_label_mismatch():
@@ -1375,3 +1378,16 @@ def test_legend_handle_label_mismatch_no_len():
13751378
labels=iter(["pl1", "pl2", "pl3"]))
13761379
assert len(legend.legend_handles) == 2
13771380
assert len(legend.get_texts()) == 2
1381+
1382+
1383+
def test_legend_nolabels_warning():
1384+
plt.plot([1, 2, 3])
1385+
with pytest.raises(UserWarning, match="No artists with labels found"):
1386+
plt.legend()
1387+
1388+
1389+
@pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend")
1390+
def test_legend_nolabels_draw():
1391+
plt.plot([1, 2, 3])
1392+
plt.legend()
1393+
assert plt.gca().get_legend() is not None

lib/matplotlib/tests/test_pickle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def _generate_complete_test_figure(fig_ref):
9090
plt.legend(loc='upper left')
9191

9292
plt.subplot(3, 3, 9)
93-
plt.errorbar(x, x * -0.5, xerr=0.2, yerr=0.4)
93+
plt.errorbar(x, x * -0.5, xerr=0.2, yerr=0.4, label='$-.5 x$')
9494
plt.legend(draggable=True)
9595

9696
fig_ref.align_ylabels() # Test handling of _align_label_groups Groupers.

0 commit comments

Comments
 (0)