remove legend handles and labels completely

Question:

Some plotting tools such as seaborn automatically label plots and add a legend. Removing the legend is fairly easy with ax.get_legend().remove(), but the handles and labels are still stored somewhere in the axes object. Thus when adding another line or other plot type, for which I want to have a legend, the "old" legend handles and labels are also displayed. In other words: ax.get_legend_handles_labels() still returns the labels and handles introduced by f.i. seaborn.

Is there any way to completely remove the handles and labels to be used for a legend from an axis?
Such that ax.get_legend_handles_labels() returns ([], [])?

I know that I can set sns.lineplot(..., legend=False) in seaborn. I am just using seaborn to produce a nice example. The question is how to remove existing legend labels and handles in general.

Here is a minimum working example:

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

df = pd.DataFrame(data={
    'x': [0, 1, 0, 1], 
    'y': [7.2, 10., 11.2, 3.],
    'id': [4, 4, 7, 7]
})
# get mean per x location:
grpd = df.groupby('x').mean()

ax = sns.lineplot(data=df, x='x', y='y', hue='id', palette=['b', 'g'])
ax.get_legend().remove()

# this still returns the handles and labels:
print(ax.get_legend_handles_labels())
# Out: 
# ([<matplotlib.lines.Line2D at 0x17c1c208f88>,
#   <matplotlib.lines.Line2D at 0x17c1c1f8888>,
#   <matplotlib.lines.Line2D at 0x17c1c20af88>],
#  ['id', '4', '7'])

# plot some other lines, for which I want to have a legend:
ax.plot(grpd.index, grpd['y'], label='mean')
# add legend, ONLY FOR MEAN, if possible:
ax.legend()

I tried manipulating the axes ax.get_legend() and ax.legend_ objects, f.i. with ax.legend_.legendHandles = [], setting the labels, texts and everything else, but the "old" seaborn entries keep reappiering each time.

Since this is meant to be used within a module, it is not applicable to explicitly set a legend only containing the "mean"-entry. I need to "clear" everything happening in the backend to provide a clean API to the user.

Asked By: JE_Muc

||

Answers:

Change:

ax = sns.lineplot(data=df, x='x', y='y', hue='id', palette=['b', 'g'])

to:

ax = sns.lineplot(data=df, x='x', y='y', hue='id', palette=['b', 'g'], legend=False)

That way you also don’t need to make the call to remove the legend as none is created in the first place.

EDIT UPDATE:

If you want to clear the legend handles and label, I think you’ll have to do something like:

for line in ax.lines: # put this before you call the 'mean' plot function.
    line.set_label(s='')

This will loop over the lines draw on the plot and then set their label to be empty. That way the legend doesn’t consider them and the print(ax.get_legend_handles_labels()) will return empty iterables.

Answered By: mullinscr

Thanks at mullinscr for the answer considering line plots. To remove legend labels in general, the labels of lines, collections (f.i. scatter plots), patches (boxplots etc) and images (imshow etc.) must be cleared:

for _artist in ax.lines + ax.collections + ax.patches + ax.images:
    _artist.set_label(s=None)

Please tell me, if I forgot to mention a specific kind of plot.

Answered By: JE_Muc

Another option is to do the following:

ax.legend(handles=[], labels= [])

In this case, everything will be removed.

If for example you would like to only remove the first handle, you can do the following:

  1. fetch the handles and labels of your plot:
h, l = ax.get_legend_handles_labels()*
  1. select the ones you want (here all except the first):
ax.legend(handles=[item for item in h[1:], labels= [item for item in l[1:])

This way, you can sort out the things you want.

Answered By: Sphagnum_pr0g
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.