103

I'm using factorplot(kind="bar") with seaborn.

The plot is fine except the legend is misplaced: too much to the right, text goes out of the plot's shaded area.

How do I make seaborn place the legend somewhere else, such as in top-left instead of middle-right?

1
  • 7
    For seaborn >= 0.11.2 use .move_legend as shown in this answer Commented Oct 26, 2021 at 11:40

8 Answers 8

93

Building on @user308827's answer: you can use legend=False in factorplot and specify the legend through matplotlib:

import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="whitegrid")

titanic = sns.load_dataset("titanic")

g = sns.factorplot("class", "survived", "sex",
                   data=titanic, kind="bar",
                   size=6, palette="muted",
                   legend=False)
g.despine(left=True)
plt.legend(loc='upper left')
g.set_ylabels("survival probability")
  • plt acts on the current axes. To get axes from a FacetGrid use fig.
    • g.fig.get_axes()[0].legend(loc='lower left')
Sign up to request clarification or add additional context in comments.

1 Comment

This generally does not work for seaborn plots.
59
import matplotlib.pyplot as plt
import seaborn as sns

# load the data
penguins = sns.load_dataset('penguins', cache=False)

Figure Level Plot

g = sns.displot(penguins, x="bill_length_mm", hue="species", col="island", col_wrap=2, height=3)
sns.move_legend(g, "upper left", bbox_to_anchor=(.55, .45), title='Species')
plt.show()

enter image description here

Axes Level Plot

ax = sns.histplot(penguins, x="bill_length_mm", hue="species")
sns.move_legend(ax, "lower center", bbox_to_anchor=(.5, 1), ncol=3, title=None, frameon=False)
plt.show()

enter image description here

Comments

22

Check out the docs here: https://matplotlib.org/users/legend_guide.html#legend-location

adding this simply worked to bring legend out of the plot:

plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)

1 Comment

This generally does not work with seaborn generated figures.
22

Modifying the example here:

You can use legend_out = False

import seaborn as sns
sns.set(style="whitegrid")

titanic = sns.load_dataset("titanic")

g = sns.factorplot("class", "survived", "sex",
                    data=titanic, kind="bar",
                    size=6, palette="muted",
                   legend_out=False)
g.despine(left=True)
g.set_ylabels("survival probability")

enter image description here

Comments

9

This is how I was able to move the legend to a particular place inside the plot and change the aspect and size of the plot:

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
matplotlib.style.use('ggplot')
import seaborn as sns
sns.set(style="ticks")

figure_name = 'rater_violinplot.png'
figure_output_path = output_path + figure_name

viol_plot = sns.factorplot(x="Rater", 
                       y="Confidence", 
                       hue="Event Type", 
                       data=combo_df, 
                       palette="colorblind",
                       kind='violin',
                       size = 10,
                       aspect = 1.5,
                       legend=False)

viol_plot.ax.legend(loc=2)
viol_plot.fig.savefig(figure_output_path)  

Legend location changed

This worked for me to change the size and aspect of the plot as well as move the legend outside the plot area.

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
matplotlib.style.use('ggplot')
import seaborn as sns
sns.set(style="ticks")


figure_name = 'rater_violinplot.png'
figure_output_path = output_path + figure_name

viol_plot = sns.factorplot(x="Rater", 
                       y="Confidence", 
                       hue="Event Type", 
                       data=combo_df, 
                       palette="colorblind",
                       kind='violin',
                       size = 10,
                       aspect = 1.5,
                       legend_out=True)

viol_plot.fig.savefig(figure_output_path)  

violin plot with changed size, aspect and legend located outside

I figured this out from mwaskom's answer here and Fernando Hernandez's answer here.

Comments

4

it seems you can directly call:

g = sns.factorplot("class", "survived", "sex",
                data=titanic, kind="bar",
                size=6, palette="muted",
               legend_out=False)

g._legend.set_bbox_to_anchor((.7, 1.1))

Comments

1

If you wish to customize your legend, just use the add_legend method. It takes the same parameters as matplotlib plt.legend.

import seaborn as sns
sns.set(style="whitegrid")

titanic = sns.load_dataset("titanic")

g = sns.factorplot("class", "survived", "sex",
                    data=titanic, kind="bar",
                    size=6, palette="muted",
                   legend_out=False)
g.despine(left=True)
g.set_ylabels("survival probability")
g.add_legend(bbox_to_anchor=(1.05, 0), loc=2, borderaxespad=0.)

1 Comment

it seems this creates a new legend. In my code, I have other lines to adjust the legend (title, size, and transparency ..). If I call this to adjust the position, the following lines don't work then...
0

Using object oriented API:

fig,ax = plt.subplots(1,1)
sns.someplot(...,ax=ax)
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels,loc="upper left")

source: https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html

2 Comments

This does not work with current versions of seaborn. Figure-level plots result in an error, and axes-level plots don't result in an error, but the legend does not appear. The correct option is seaborn.move_legend
I just modified my answer. If you pass ax to the argument then it should work just fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.