Reputation: 372
I am calling sns.displot
to get a FacetGrid
g = sns.displot(
data=df_all,
x='a_number',
hue='a_condition',
row='a_factor',
col='another_factor',
stat="density",
common_norm=False,
element='step',
palette=palette,
)
Similar to this question, I want to place the automatically-generated legend on one of the axes, instead of outside them as a figure-level legend: How to put the legend on first subplot of seaborn.FacetGrid?
Just calling g.fig.axes[row][col].legend()
does not work:
No handles with labels found to put in legend.
So I should generate the handles and labels?
I looked at how Grid.add_legend
does this and it seems to be some magic that would require me knowing a lot more about how the class works to reproduce it (maybe I am wrong). There's also no _legend_data
I can use to dynamically recreate the legend in the same way that the Grid.add_legend
method does.
>>> g._legend_data
{}
The "easy" (lazy?) way would be if I could somehow copy the legend
instance, add that copy to the axes I want, and then call g.fig._legend.remove()
(unless anyone has any better ideas)
I can't figure out how to copy the legend and then assign it to a specific Axes
.
Upvotes: 1
Views: 541
Reputation: 372
It dawned on me I could just call g.legend.set_bbox_to_anchor()
as a workaround.
In this case the legend is still figure-level but it lets me get it where I want it.
edit:
@mwaskom replied with a link to this comment on a GitHub issue, that has a code snippet that does what I had in mind:
https://github.com/mwaskom/seaborn/issues/2280#issuecomment-692350136
for my purposes I tweaked it like so
def move_legend(g, ax, new_loc, **kws):
old_legend = g.legend
handles = old_legend.legendHandles
labels = [t.get_text() for t in old_legend.get_texts()]
title = old_legend.get_title().get_text()
ax.legend(handles, labels, loc=new_loc, title=title, **kws)
move_legend(g, g.fig.axes[-2], "upper right")
g.legend.remove()
relevant discussion of what's going on under the hood is on that issue
Upvotes: 1