Skip to content

Figure legend not keeping Line2D marker #9155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
anhiga opened this issue Sep 4, 2017 · 4 comments
Closed

Figure legend not keeping Line2D marker #9155

anhiga opened this issue Sep 4, 2017 · 4 comments

Comments

@anhiga
Copy link

anhiga commented Sep 4, 2017

Bug report

Bug summary

When retrieving handles used in legend, marker property is not kept.

Code for reproduction

import matplotlib.pyplot as plt

point = plt.Line2D([1],[1], marker='o')
legend = plt.gcf().legend(handles=[point], labels=['point'])

# First way
handles = legend.legendHandles
handles[0].get_marker()
# Second way
lines= legend.get_lines()
lines[0].get_marker()

Actual outcome

Out[1]: ''

Expected outcome
When plotting an Axes legend, get_legend_handles_labels() can be used, which does return the right marker. There isn't such a method in Figure, so when using Legend methods or properties such as legend.get_lines() or legend.legendHandles, line2D marker isn't kept.

Is there a better way of retrieving handles from a legend?
Am I doing something wrong?

Matplotlib version

  • Operating System: Windows 10
  • Matplotlib Version: 2.0.2
  • Python Version: 3.6.1

cc @juanlu001

@jklymak
Copy link
Member

jklymak commented Sep 5, 2017

Not sure what the issue is with figure legends, but you can achieve the same effect with an axes legend using something like:

ax.legend(loc='center top', bbox_to_anchor=(0.5, 0.))

(note center top in this case sets the vertical and horizontal justification; the actual location is in bbox_to_anchor.)

Maybe that is an acceptable workaround.

I am working on a way to make this automatically resize the parent axis but that'll be 2.2 or later (see #9082).

@astrojuanlu
Copy link

@jklymak thank you for your suggestion - however it is a limited workaround, since axes only support one legend whereas figures support more of them.

Above all, we are interested in finding out whether this is a bug or a feature :)

@jklymak
Copy link
Member

jklymak commented Sep 5, 2017

@Juanlu001 @anhiga

First, there is no difference between the axes and figure hadnling of the legend artists. ax.get_legend_handles_labels() is called before legend() to gather the needed artists from the axes. You could loop through all your axes as figure.legend does:

            for ax in self.axes:
                ax_handles, ax_labels = ax.get_legend_handles_labels()
                for h, l in zip(ax_handles, ax_labels):
                    if not in_handles(h, l):
                        handles.append(h)
                        labels.append(l)

The solution to your mystery, however, is contained in legend_handler.py, where it was decided that text and lines must correspond one-to-one. So if you want the handle to the marker, you can do:

for h in leg.get_lines():
    print(h._legmarker.get_marker())

This is pretty hacky, and the undrscore means it could go away.

Its a little strange to want the marker after the legend has been created. Why don't you just make the legend refer to something you've already drawn and keep track of what you've drawn? The legend doesn't seem like a good place to store the state of your plotting.

@anhiga
Copy link
Author

anhiga commented Sep 6, 2017

Thank you for your answers.
@jklymak I understand now the way get_legend_handles_labels() works.

Why don't you just make the legend refer to something you've already drawn and keep track of what you've drawn? The legend doesn't seem like a good place to store the state of your plotting.

You are right, we shouldn't rely on the legend to store our plotting state.

I'm closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants