Gabriel
Gabriel

Reputation: 42349

Manually set color of points in legend

I'm making a scatter plot which looks like this:

enter image description here

(MWE at bottom of question)

As can be seen in the image above the colors of the points in the legend are set to blue automatically by matplotlib. I need to set this points to some other color not present in the colormap (ie: black) so they won't generate confusion with the colors associated with said colormap.

I looked around but the matplotlib.legend module does not seem to accept a color keyword. Is there any way to do this?


Here's the MWE:

import matplotlib.pyplot as plt
import numpy as np

def rand_data():
    return np.random.uniform(low=0., high=1., size=(100,))

# Generate data.
x, y, x2, x3 = [rand_data() for i in range(4)]
# This data defines the markes and labels used.
x1 = np.random.random_integers(7, 9, size=(100,))

# Order all lists so smaller points are on top.
order = np.argsort(-np.array(x2))
# Order x and y.
x_o, y_o = np.take(x, order), np.take(y, order)
# Order list related to markers and labels.
z1 = np.take(x1, order)
# Order list related to sizes.
z2 = np.take(x2, order)
# Order list related to colors.
z3 = np.take(x3, order)

plt.figure()
cm = plt.cm.get_cmap('RdYlBu')

# Scatter plot where each value in z1 has a different marker and label
# assigned.
mrk = {7: ('o', '7'), 8: ('s', '8'), 9: ('D', '9')}
for key, value in mrk.items():

    s1 = (z1 == key)
    plt.scatter(x_o[s1], y_o[s1], marker=value[0], label=value[1],
        s=z2[s1] * 100., c=z3[s1], cmap=cm, lw=0.2)

# Plot colorbar
plt.colorbar()

# Plot legend.
plt.legend(loc="lower left", markerscale=0.7, scatterpoints=1, fontsize=10)

plt.show()

Upvotes: 57

Views: 124565

Answers (5)

Saullo G. P. Castro
Saullo G. P. Castro

Reputation: 58915

You can obtain the legend handles and change their colors individually.

Thanks for the comments of @OrOrg and @Reinderien that led me to update this answer.

ax = plt.gca()
leg = ax.get_legend()
leg.legend_handles[0].set_facecolor('red')
leg.legend_handles[0].set_edgecolor('red')

leg.legend_handles[1].set_facecolor('yellow')
leg.legend_handles[1].set_edgecolor('yellow')

Upvotes: 80

JAdel
JAdel

Reputation: 1616

Regarding to the answer of @Saullo G. P. Castro :

MatplotlibDeprecationWarning: The legendHandles attribute was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use legend_handles instead.


Future usage:

ax = plt.gca()
leg = ax.get_legend()
leg.legend_handles[0].set_color('red')
leg.legend_handles[1].set_color('yellow')

Upvotes: 2

Zaccharie Ramzi
Zaccharie Ramzi

Reputation: 2316

While I found that the solution with legendHandles[i].set_color did not work for errorbar, I managed to do the following workaround:

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)

See this GitHub issue as well.

Upvotes: 1

M. Ali
M. Ali

Reputation: 2396

Adding to the other answers – I've had trouble in the past changing color of legend markers with set_color. An alternate approach is to build the legend yourself:

import matplotlib.lines as mlines

eight = mlines.Line2D([], [], color='blue', marker='s', ls='', label='8')
nine = mlines.Line2D([], [], color='blue', marker='D', ls='', label='9')
# etc etc
plt.legend(handles=[eight, nine])

Building legends from scratch can sometimes save the hassle of dealing with the obscure internals of an already built legend. More information in Matplotlib docs here.

Upvotes: 10

apteryx
apteryx

Reputation: 1141

You can retrieve the label of each legend handle with lh.get_label() if you want to map colors to specific labels.

For my purposes it worked best to create a dict from legendHandles and change the colors like so:

ax = plt.gca()
leg = ax.get_legend()
hl_dict = {handle.get_label(): handle for handle in leg.legendHandles}
hl_dict['9'].set_color('red')
hl_dict['8'].set_color('yellow')

Upvotes: 3

Related Questions