seaborn icon indicating copy to clipboard operation
seaborn copied to clipboard

Notes on ongoing legend challenges

Open mwaskom opened this issue 5 years ago • 3 comments

Here are some notes about legends, which are an area of future work.

Challenges with legends include:

Multi-variable legends

When multiple semantic mappings exist (currently only possible in the relational plots), the legends use a hack that adds a legend entry with an invisible artist handle to serve as a "subtitle". This is not ideal. Matplotlib legends do not have any concept of a "subtitle". It's possible to add multiple legends to a plot. But it's not possible to add multiple legends that both use loc="best"; they will be placed in the same location. Because loc="best" is determined at draw-time, it's also not possible how to but one legend in the "best" location and then stick the other one next to or under it. It would also be better if it were possible to assign the sub-legends to e.g. different columns). See #1519 for some related work.

Numeric semantic mappings

When using a numeric semantic mapping, a set of handles is added to the legend with evenly-spaced labels. This is intended to act like a "colorbar", but it doesn't look that much like a colorbar, and it's an ongoing source of confusion. Ideally, there would be something that looks like a colorbar inside the legend itself.

No consistent approach to legend creation

Most plotting functions add proxy artists with label attributes to the axes and then call legend() to pick them up. This has the advantage that legend() can be called again with new kwargs (e.g. a different location) and it will be recreated. But it adds a lot of extraneous artists to the legend, which is confusing when trying to do deep customization. The new distribution plots create proxy artists but just pass them directly to legend(). The disadvantage is that calling legend() again will erase these artists. And in general, this should be predictable, and users should have access to the legends and their handles should they need to modify them.

Legends are not very customizable

For numeric mappings, there's no way to specify exactly which labels to use. And in general, plotting functions don't take a legend_kws dict, but probably they should.

Seaborn legend creation is a mess

The code that creates legends in seaborn is distributed and complicated, especially in the case of multi-variable legends in the relational module. While the semantic mappers could own the logic of determining what values to show in the legend, the plotting objects/functions know what artist to use and which attributes to modify.

Existing legends don't use matplotlib kwargs to show artists

Most of the existing legends represent the semantic mapping, but don't always correspond directly to the artists in the figure. e.g. if you make a scatterplot and pass marker="x", the legend will still have dots representing the color or size. And not using the linewidth/edgecolor parameters causes problems for how the size variable is represented (#1763, #2355, #2852).

Matplotlib legend API has limitations

Some of these problems exist because the matplotlib legend API has some limitations, both for users and for seaborn. Some of these problems would be less painful if it were easier to modify a legend after plotting, e.g. to move it or to add new entries to it. Moving a legend seems basically impossible through the public API, adding entries doesn't seem possible either. Some aspects of the legends can be modified in-place, but not through obvious methods. And the legend code uses a lot of private attributes and functions, so extending it (i.e. through subclassing) is not really possible

Unclear at this point whether the best path forward is to try and get an enhanced legend API from matplotlib or to fork the legend code and adapt to get what we need in seaborn itself.

mwaskom avatar Aug 28 '20 22:08 mwaskom

Changed marker style in sns.scatterplot and the legend did not update the marker style. Any suggestions?

alualex avatar May 26 '21 21:05 alualex

@alualex Same here.

Also legends for scatter plots can be customised, but for histplots this is not possible. I'm unable to change font sizes for simple histplots through ax.legend method.

shivendra90 avatar Aug 05 '21 08:08 shivendra90

https://matplotlib.org/devdocs/users/next_whats_new/set_loc.html Seems things are moving in the right direction on the matplotlib side. This may at least help with moving around the legend.

thuiop avatar Sep 18 '23 08:09 thuiop