Skip to content

Cannot change the color of markers in a legend #8807

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
saintsfan342000 opened this issue Jun 26, 2017 · 6 comments
Closed

Cannot change the color of markers in a legend #8807

saintsfan342000 opened this issue Jun 26, 2017 · 6 comments

Comments

@saintsfan342000
Copy link

Bug report

Bug summary

Markers colors in a legend cannot be changed if the markers were added via plt.plot. Apparently, however, they can be if marker was added via plt.scatter().

Code for reproduction

import matplotlib.pyplot as plt
plt.scatter([1],[1], c = 'r', label='scatter') # Scatter red
plt.plot([0],[0], 'ko', label='plot') # Plot black
leg = plt.legend()
for marker in leg.legendHandles:
    marker.set_color('b')
plt.show()

Actual outcome
download

Expected outcome
I expected the marker labeled "plot" in the legend, which was added via plt.plot, to be blue.

Matplotlib version

  • Operating System: Windows 7
  • Matplotlib Version: 2.0.0
  • Python Version: 3.6.0
  • Jupyter Version (if applicable): 4.3.1

Matplotlib, Python, Jupyter, and everything installed directly from the Anaconda installer downloaded directly from the Continuum website.

Also occurs on an older linux machine that runs matplotlib version 1.3.1 which was most likely installed via pip3.

@tacaswell
Copy link
Member

Why do you want to do this?

@tacaswell tacaswell added this to the 2.2 (next next feature release) milestone Jun 26, 2017
@saintsfan342000
Copy link
Author

saintsfan342000 commented Jun 26, 2017

Does that matter? To be clear, I almost never use scatter. I just included it to demonstrate that the method works for one but not the other. I often, however, use plot to plot an experimental response and then plot again to make a marker that points out a significant moment.

@tacaswell
Copy link
Member

The reason for this is a bit obscure. There are actually 2 artists (and in general N) and some reason only the first artist makes it into the legendHandles (probably to preserve back-compatibility when the ability to have compound artists was added ?). If you plot a line with a linestyle you will see it change color (but not the marker). The full set of artists is only accessible via a deeply nested set of private attributes that manage the layout of the legend.

To control exactly what is in the legend I suggest having a look at https://matplotlib.org/users/legend_guide.html#creating-artists-specifically-for-adding-to-the-legend-aka-proxy-artists Doing it this way you will also be able to hold onto a reference to the handles and you can change them however you wish.

@saintsfan342000
Copy link
Author

Thanks. Indeed, I was thinking about this and came up with several ways to demonstrate the complicated behavior of markers in a legend. Surely you can at least imagine why someone might want to increase the handle linewidth, or analogously, the marker size.

import matplotlib.pyplot as plt
plt.plot([0,1],[0,0],'r', label='LH[0]')
plt.plot([0,.4],[-.1,-.1],'go', label='LH[1]')
plt.plot([0,.4],[-.2,-.2],'k^', label='LH[2]') 
plt.plot([0,.4],[-.3,-.3],'bs', label='LH[3]') 
plt.plot([0,.4],[-.4,-.4],'D', mfc='c', label='LH[4]')
plt.scatter([0,.4],[-.5,-.5],c='m', label='LH[5]')
leg = plt.legend(loc='right', labelspacing=2)
LH = leg.legendHandles
LH[0].set_linewidth(8)  # Works
LH[1].set_color('y') # No change
LH[2].set_ms(15)    # No change
LH[3].set_marker('*')  # Stars added to left and right!
LH[3].set_color('r')   # Stars now change color
LH[4].set_color('w')   # No change
LH[5].set_alpha(0.5)  # Well-behaved scatter

download

@tacaswell
Copy link
Member

Right, the artist in legendHandles is the 'line' part of the legend handle (not the marker), the changes are having an effect on the internal state, the line is just draw with out a line style and without markers.

If you want complete control of the legend, use the proxy artist path.

Unfortunately, to expose more of the automatic legend internals would require a pretty big over-haul of the legend generation code.

This is a very long standing issue (for example, see #2532 ).

@tacaswell tacaswell modified the milestones: unassigned, 2.2 (next next feature release) Jun 27, 2017
@zaccharieramzi
Copy link

I encoutered this issue recently.
My dirty-fix was provided to me by @tomMoral:

ax_legend = fig.add_subplot(g[3, 0])
ax_legend.axis('off')
handles_markers = []
markers_labels = []
for marker_name, marker_style in markers_style.items():
    pts = plt.scatter([0], [0], marker=marker_style, c='black', label=marker_name)
    handles_markers.append(pts)
    markers_labels.append(marker_name)
    pts.remove()
ax_legend.legend(handles_markers, markers_labels, loc='center', ncol=len(markers_labels), handlelength=1.5, handletextpad=.1)

where markers_style would be a dict mapping your markers' labels to their shape.

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

No branches or pull requests

3 participants