BhishanPoudel
BhishanPoudel

Reputation: 17164

How to show labels in Seaborn plots (No handles with labels found to put in legend.)?

I was trying to plot using seaborn, but the label was not showing up, even though it was assigned in the axis object.

How to show the label on the plot?

Here, is my code:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

dx = pd.DataFrame({'c0':range(5), 'c1':range(5,10)})
dx.index = list('abcde')

ax = sns.pointplot(x=dx.index,
                y="c0",
                data=dx, color="r",
                scale=0.5, dodge=True,
                capsize=.2, label="child")
ax = sns.pointplot(x=dx.index,
                y="c1",
                data=dx, color="g",
                scale=0.5, dodge=True,
                capsize=.2, label="teen")
ax.legend()
plt.show()

The legend gives error: No handles with labels found to put in legend.

Upvotes: 6

Views: 30745

Answers (4)

Ian Thompson
Ian Thompson

Reputation: 3305

If you're using seaborn you should try to use tidy (or "long") data rather than "wide". See this link about Organizing Datasets

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

dx = pd.DataFrame({'c0':range(5), 'c1':range(5,10)})
dx.index = list('abcde')

# reset the index and melt the remaining columns
dx1 = dx.reset_index().melt(id_vars='index')

print(dx1)

  index variable  value
0     a       c0      0
1     b       c0      1
2     c       c0      2
3     d       c0      3
4     e       c0      4
5     a       c1      5
6     b       c1      6
7     c       c1      7
8     d       c1      8
9     e       c1      9

You can now plot once rather than twice

# modified the "x" and "data" parameters
# added the "hue" parameter and removed the "color" parameter
ax = sns.pointplot(x='index',
                y="value",
                data=dx1,
                hue='variable',
                scale=0.5, dodge=True,
                capsize=.2)

# get handles and labels from the data so you can edit them
h,l = ax.get_legend_handles_labels()

# keep same handles, edit labels with names of choice
ax.legend(handles=h, labels=['child', 'teen'])

plt.show()

plot

Edit

As of pandas version 1.1.0, pd.melt has parameter ignore_index so we don't have to reset the index any more.

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

dx = pd.DataFrame({'c0':range(5), 'c1':range(5,10)})
dx.index = list('abcde')

dx = dx.melt(ignore_index=False)

ax = sns.pointplot(x=dx.index,
                y="value",
                data=dx, hue="variable",
                scale=0.5, dodge=True,
                capsize=.2)

h,l = ax.get_legend_handles_labels()

l = ["child", "teen"]

ax.legend(h, l)
plt.show()

new plot

Upvotes: 2

BhishanPoudel
BhishanPoudel

Reputation: 17164

After some practice, I found the solution using pandas itself,

dx.plot(kind='line',marker='o',xticks=range(5))

Gives the plot: enter image description here

Upvotes: 0

chryss
chryss

Reputation: 7519

sns.pointplot() isn't meant for just plotting multiple dataframe attributes in the same figure, but for visualizing relationships between them, in which case it will generate its own labels. You can override them by passing a labels argument to ax.legend() (see Add Legend to Seaborn point plot ), but once you make changes to your plot, chances are there is going to be some mess.

To produce your plots using seaborn esthetics, I would do this:

sns.set_style("white")
fig, ax = plt.subplots()
plt.plot(dx.index, dx.c0, "o-", ms=3,
            color="r", label='child')
plt.plot(dx.index, dx.c1, "o-", ms=3,
            color="g", label='teen')
ax.legend()

Result:

enter image description here

Upvotes: 6

zyxue
zyxue

Reputation: 8908

In your case, the ylabel is already set to c0, so a legend isn't necessary.

If you insist on legend, I suggest not using sns. Instead, try this using pandas' interface to matplotlib

dx = pd.DataFrame({'c0':range(5), 'c1':range(5,10)})
dx.set_index('c0').plot(marker='o', )

Or use matplotlib's API directly with more flexibility

plt.plot(dx.c0, dx.c1, marker='o', label='child')
plt.legend()

Upvotes: 1

Related Questions