0

I have created a barplot with hatches with the code below:

import matplotlib.pyplot as plt
import seaborn as sns

tips = sns.load_dataset("tips")

hatches = ['\\\\', '//']

fig, ax = plt.subplots(figsize=(6,3))
sns.barplot(data=tips, x="day", y="total_bill", hue="time")

# loop through days
for hues, hatch in zip(ax.containers, hatches):
    # set a different hatch for each time
    for hue in hues:
        hue.set_hatch(hatch)

# add legend with texture
plt.legend()

plt.show()

And it outputs the following plot:

enter image description here

If I try to modify the legend to (a) add a title and (b) change the hue labels, the code breaks down, and I lose the color and hatches from the legend:

import matplotlib.pyplot as plt
import seaborn as sns

tips = sns.load_dataset("tips")

hatches = ['\\\\', '//']

fig, ax = plt.subplots(figsize=(6,3))
sns.barplot(data=tips, x="day", y="total_bill", hue="time")

# loop through days
for hues, hatch in zip(ax.containers, hatches):
    # set a different hatch for each time
    for hue in hues:
        hue.set_hatch(hatch)

# add legend with texture
plt.legend(title='My Title', labels=['Lunch_1','Dinner_2'], loc=1)

plt.show()

enter image description here

So my questions is: How do I add a title and modify the labels without losing the color and hatches from the legend?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Ernesto
  • 187
  • 1
  • 8

2 Answers2

3

You need to call legend with the signature legend(handles, labels) after retrieving the original ones with get_legend_handles_labels :

handles, _ = ax.get_legend_handles_labels()

plt.legend(handles, ["Lunch_1", "Dinner_2"], title="My Title", loc=1)

Output :

enter image description here

Timeless
  • 22,580
  • 4
  • 12
  • 30
2
  • It's a best practice to clean the data in a DataFrame prior to plotting, and analysis. As such, the easiest way to deal with legend labels/titles, and axis labels, is to clean associated columns.
    • Update the column name used for hue (the legend title), with .rename or .str methods, and the categorical column values (the legend labels) with .map.
  • Move seaborn plot legend to a different position shows how to move seaborn axes level legends with plt.legend (implicit), ax.legend (explicit), and the preferred sns.move_legend.
    • However, in this case, plt.legend or ax.legend must be used for the hatches to show up on the legend handles, which requires resetting the legend title.
    • Now the legend labels don't need to be updated, so it's not necessary to pass extracted handles.
  • Tested in python 3.11.2, pandas 2.0.1, matplotlib 3.7.1, seaborn 0.12.2
import seaborn as sns
import matplotlib.pyplot as plt

tips = sns.load_dataset('tips')

# change column names for better presentation of axis labels and titles
tips.columns = tips.columns.str.replace('_', ' ').str.title()

# change a specific column name
tips = tips.rename({'Time': 'Hobbit Meals', 'Day': 'Shire Days'}, axis=1)

# change values in the column to have a better value
tips['Hobbit Meals'] = tips['Hobbit Meals'].map({'Dinner': 'Supper', 'Lunch': 'Elevensies'})
tips['Shire Days'] = tips['Shire Days'].map({'Thur': 'Trewsday', 'Fri': 'Hevensday', 'Sat': 'Mersday', 'Sun': 'Highday'})

fig, ax = plt.subplots(figsize=(6, 3))
sns.barplot(data=tips, x='Shire Days', y='Total Bill', hue='Hobbit Meals', ax=ax)

# loop through axes bar containers
for c, hatch in zip(ax.containers, ['\\\\', '//']):
    # iterate through each patch in the container
    for patch in c:
        patch.set_hatch(hatch)

# in order to have the hatches appear on the legend hanles, the lengend method must me called
ax.legend(title=tips.columns[5], bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)

# remove the spines for some additionaly cosmetic changes
ax.spines[['right', 'top']].set_visible(False)

enter image description here

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158