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

Skip to content

ENH: Change logging to warning when creating a legend with no labels #27172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@
# Fixing random state for reproducibility
np.random.seed(19680801)

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

fig, ax = plt.subplots()
lines = ax.plot(data)
ax.legend()

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

Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ def legend(self, *args, **kwargs):
selection by using a label starting with an underscore, "_".
A string starting with an underscore is the default label for all
artists, so calling `.Axes.legend` without any arguments and
without setting the labels manually will result in no legend being
drawn.
without setting the labels manually will result in a ``UserWarning``
and an empty legend being drawn.


**2. Explicitly listing the artists and labels in the legend**
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs):
elif len(args) == 0: # 0 args: automatically detect labels and handles.
handles, labels = _get_legend_handles_labels(axs, handlers)
if not handles:
log.warning(
_api.warn_external(
"No artists with labels found to put in legend. Note that "
"artists whose label start with an underscore are ignored "
"when legend() is called with no argument.")
Expand Down
88 changes: 52 additions & 36 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ def test_handler_numpoints():
def test_text_nohandler_warning():
"""Test that Text artists with labels raise a warning"""
fig, ax = plt.subplots()
ax.plot([0], label="mock data")
ax.text(x=0, y=0, s="text", label="label")
with pytest.warns(UserWarning) as record:
ax.legend()
Expand Down Expand Up @@ -703,7 +704,7 @@ def test_legend_title_empty():
# it comes back as an empty string, and that it is not
# visible:
fig, ax = plt.subplots()
ax.plot(range(10))
ax.plot(range(10), label="mock data")
leg = ax.legend()
assert leg.get_title().get_text() == ""
assert not leg.get_title().get_visible()
Expand Down Expand Up @@ -736,7 +737,7 @@ def test_window_extent_cached_renderer():

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

fig, axes = plt.subplots(2, 3, figsize=(10, 6))
axes = axes.flat
axes[0].plot(range(10))
axes[0].plot(range(10), label="mock data")
leg0 = axes[0].legend(title='Aardvark', title_fontsize=22)
assert leg0.get_title().get_fontsize() == 22
axes[1].plot(range(10))
axes[1].plot(range(10), label="mock data")
leg1 = axes[1].legend(title='Aardvark',
title_fontproperties={'family': 'serif', 'size': 22})
assert leg1.get_title().get_fontsize() == 22
axes[2].plot(range(10))
axes[2].plot(range(10), label="mock data")
mpl.rcParams['legend.title_fontsize'] = None
leg2 = axes[2].legend(title='Aardvark',
title_fontproperties={'family': 'serif'})
assert leg2.get_title().get_fontsize() == mpl.rcParams['font.size']
axes[3].plot(range(10))
axes[3].plot(range(10), label="mock data")
leg3 = axes[3].legend(title='Aardvark')
assert leg3.get_title().get_fontsize() == mpl.rcParams['font.size']
axes[4].plot(range(10))
axes[4].plot(range(10), label="mock data")
mpl.rcParams['legend.title_fontsize'] = 20
leg4 = axes[4].legend(title='Aardvark',
title_fontproperties={'family': 'serif'})
assert leg4.get_title().get_fontsize() == 20
axes[5].plot(range(10))
axes[5].plot(range(10), label="mock data")
leg5 = axes[5].legend(title='Aardvark')
assert leg5.get_title().get_fontsize() == 20

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


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

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

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


def test_loc_valid_tuple():
fig, ax = plt.subplots()
ax.legend(loc=(0.481, 0.442))
ax.legend(loc=(1, 2))
ax.legend(loc=(0.481, 0.442), labels=["mock data"])
ax.legend(loc=(1, 2), labels=["mock data"])


def test_loc_valid_list():
fig, ax = plt.subplots()
ax.legend(loc=[0.481, 0.442])
ax.legend(loc=[1, 2])
ax.legend(loc=[0.481, 0.442], labels=["mock data"])
ax.legend(loc=[1, 2], labels=["mock data"])


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


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


def test_loc_validation_numeric_value():
fig, ax = plt.subplots()
ax.legend(loc=0)
ax.legend(loc=1)
ax.legend(loc=5)
ax.legend(loc=10)
ax.legend(loc=0, labels=["mock data"])
ax.legend(loc=1, labels=["mock data"])
ax.legend(loc=5, labels=["mock data"])
ax.legend(loc=10, labels=["mock data"])
with pytest.raises(ValueError, match=('loc must be string, coordinate '
'tuple, or an integer 0-10, not 11')):
ax.legend(loc=11)
ax.legend(loc=11, labels=["mock data"])

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


def test_loc_validation_string_value():
fig, ax = plt.subplots()
ax.legend(loc='best')
ax.legend(loc='upper right')
ax.legend(loc='best')
ax.legend(loc='upper right')
ax.legend(loc='upper left')
ax.legend(loc='lower left')
ax.legend(loc='lower right')
ax.legend(loc='right')
ax.legend(loc='center left')
ax.legend(loc='center right')
ax.legend(loc='lower center')
ax.legend(loc='upper center')
labels = ["mock data"]
ax.legend(loc='best', labels=labels)
ax.legend(loc='upper right', labels=labels)
ax.legend(loc='best', labels=labels)
ax.legend(loc='upper right', labels=labels)
ax.legend(loc='upper left', labels=labels)
ax.legend(loc='lower left', labels=labels)
ax.legend(loc='lower right', labels=labels)
ax.legend(loc='right', labels=labels)
ax.legend(loc='center left', labels=labels)
ax.legend(loc='center right', labels=labels)
ax.legend(loc='lower center', labels=labels)
ax.legend(loc='upper center', labels=labels)
with pytest.raises(ValueError, match="'wrong' is not a valid value for"):
ax.legend(loc='wrong')
ax.legend(loc='wrong', labels=labels)


def test_legend_handle_label_mismatch():
Expand All @@ -1375,3 +1378,16 @@ def test_legend_handle_label_mismatch_no_len():
labels=iter(["pl1", "pl2", "pl3"]))
assert len(legend.legend_handles) == 2
assert len(legend.get_texts()) == 2


def test_legend_nolabels_warning():
plt.plot([1, 2, 3])
with pytest.raises(UserWarning, match="No artists with labels found"):
plt.legend()


@pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend")
def test_legend_nolabels_draw():
plt.plot([1, 2, 3])
plt.legend()
assert plt.gca().get_legend() is not None
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def _generate_complete_test_figure(fig_ref):
plt.legend(loc='upper left')

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

fig_ref.align_ylabels() # Test handling of _align_label_groups Groupers.
Expand Down