Closed MJKirk closed 2 years ago
Hi @MJKirk thank you for reporting and investigating!
I took a quick look and it seems like set_label
is a method of artist.Artist
from which both LineCollection
and PathCollection
inherit this method. So I don't really understand why the behavior of this method should be different. And in both cases, a label is actually added. Just in the second case, obviously the colored line is missing.
So I've investigated a bit more - LineCollection
has a get_color
method (which seems to be used when creating the legend (see https://github.com/matplotlib/matplotlib/blob/b80bc91827e4b49caa90027ec00e6a8eacf18214/lib/matplotlib/legend_handler.py#L391-L407)
while PathCollection
has get_edgecolor
(which has the colour we want in the legend) and get_facecolor
(which gives an empty array). PathCollection
seems to be mostly used for scatterplots, which do seem to be able to get sensible legends - I'm guessing maybe what's really being drawn is a zero size circle or something.
Maybe there is some way to alter what is being drawn...
This issue https://github.com/matplotlib/matplotlib/issues/11134 also like it might contain something useful I'm enjoying my matplotlib code dive, so I'll keep playing
Just using the comments as a notebook, I think this is useful: https://stackoverflow.com/a/57030843 and https://stackoverflow.com/a/57030414
So after some playing around, I still don't understand why the new PathCollection
doesn't draw a legend marker properly here, while it does when e.g. using plt.scatter
.
However, using the legend_elements()
method I learnt about from https://github.com/matplotlib/matplotlib/issues/11134, plus inspiration from the solution of https://stackoverflow.com/questions/57024194/how-to-create-an-ax-legend-method-for-contourf-plots-that-doesnt-require-pass/57030414#57030414, I have a solution that works nicely, in both matplotlib v3.4.3 and v3.5.0 - see this commit.
The legend_elements
function returns a LineCollection
for each of the contours drawn, plus default labels with the contour value. They are designed to be added to the legend manually I think (see the matplotlib issue).
To make it automatic, I do a little hack by adding the LineCollection
to the list of the current axes containers. This list gets checked for things with labels to add to the legend when plt.legend
is called, so then everything works as expected.
This is a bit nasty - I suspect this is not how the container list is supposed to be used, and I don't understand enough of the architecture of matplotlib to really be sure whether this is liable to break in the future.
@peterstangl, shall I make my fix into a pull request? It's not perfect, but I think it's good enough
@peterstangl, shall I make my fix into a pull request? It's not perfect, but I think it's good enough
@MJKirk, I think it looks good and it would be nice if you would put it into a PR. Thanks!
When using a version of matplotlib >= 3.5.0, the contour plot legends from flavio don't show up correctly (see attached photos)
I suspect the relevant change is that in v3.4.3, contour returned a
LineCollection
but now returns aPathCollection
(see https://matplotlib.org/stable/api/prev_api_changes/api_changes_3.5.0.html?highlight=pathcollection#contourset-always-use-pathcollection), and soset_label
as called here: https://github.com/flav-io/flavio/blob/b7ac308ac83cd7168d80c3382b5d65415bc64679/flavio/plots/plotfunctions.py#L698 has different behaviour, but that's as far as I got investigating (for now at least - happy to keep digging around).