Skip to content

New textcolor kwarg for legend #15898

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

Merged
merged 1 commit into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions doc/users/next_whats_new/2019-12-09-legend-labelcolor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Text color for legend labels
----------------------------

The text color of legend labels can now be set by passing a parameter
``labelcolor`` to `~.axes.Axes.legend`. The ``labelcolor`` keyword can be:

* A single color (either a string or RGBA tuple), which adjusts the text color
of all the labels.
* A list or tuple, allowing the text color of each label to be set
individually.
* ``linecolor``, which sets the text color of each label to match the
corresponding line color.
* ``markerfacecolor``, which sets the text color of each label to match the
corresponding marker face color.
* ``markeredgecolor``, which sets the text color of each label to match the
corresponding marker edge color.
42 changes: 40 additions & 2 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
information.
"""

import itertools
import logging
import time

import numpy as np

import matplotlib as mpl
from matplotlib import cbook, docstring
from matplotlib import cbook, docstring, colors
from matplotlib.artist import Artist, allow_rasterization
from matplotlib.cbook import silent_list
from matplotlib.font_manager import FontProperties
Expand Down Expand Up @@ -172,6 +173,12 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
absolute font size in points. String values are relative to the current
default font size. This argument is only used if *prop* is not specified.

labelcolor : str or list
Sets the color of the text in the legend. Can be a valid color string
(for example, 'red'), or a list of color strings. The labelcolor can
also be made to match the color of the line or marker using 'linecolor',
'markerfacecolor' (or 'mfc'), or 'markeredgecolor' (or 'mec').

numpoints : int, default: :rc:`legend.numpoints`
The number of marker points in the legend when creating a legend
entry for a `.Line2D` (line).
Expand Down Expand Up @@ -293,7 +300,8 @@ def __init__(self, parent, handles, labels,
scatterpoints=None, # number of scatter points
scatteryoffsets=None,
prop=None, # properties for the legend texts
fontsize=None, # keyword to set font size directly
fontsize=None, # keyword to set font size directly
labelcolor=None, # keyword to set the text color

# spacing & pad defined as a fraction of the font-size
borderpad=None, # the whitespace inside the legend border
Expand Down Expand Up @@ -505,6 +513,36 @@ def __init__(self, parent, handles, labels,
self.set_title(title, prop=tprop)
self._draggable = None

# set the text color

color_getters = { # getter function depends on line or patch
'linecolor': ['get_color', 'get_facecolor'],
'markerfacecolor': ['get_markerfacecolor', 'get_facecolor'],
'mfc': ['get_markerfacecolor', 'get_facecolor'],
'markeredgecolor': ['get_markeredgecolor', 'get_edgecolor'],
'mec': ['get_markeredgecolor', 'get_edgecolor'],
}
if labelcolor is None:
pass
elif isinstance(labelcolor, str) and labelcolor in color_getters:
getter_names = color_getters[labelcolor]
for handle, text in zip(self.legendHandles, self.texts):
for getter_name in getter_names:
try:
color = getattr(handle, getter_name)()
text.set_color(color)
break
except AttributeError:
pass
elif np.iterable(labelcolor):
for text, color in zip(self.texts,
itertools.cycle(
colors.to_rgba_array(labelcolor))):
text.set_color(color)
else:
raise ValueError("Invalid argument for labelcolor : %s" %
str(labelcolor))

def _set_artist_props(self, a):
"""
Set the boilerplate props for artists added to axes.
Expand Down
60 changes: 60 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,66 @@ def test_legend_title_fontsize():
assert leg.get_title().get_fontsize() == 22


def test_legend_labelcolor_single():
# test labelcolor for a single color
fig, ax = plt.subplots()
ax.plot(np.arange(10), np.arange(10)*1, label='#1')
ax.plot(np.arange(10), np.arange(10)*2, label='#2')
ax.plot(np.arange(10), np.arange(10)*3, label='#3')

leg = ax.legend(labelcolor='red')
for text in leg.get_texts():
assert mpl.colors.same_color(text.get_color(), 'red')


def test_legend_labelcolor_list():
# test labelcolor for a list of colors
fig, ax = plt.subplots()
ax.plot(np.arange(10), np.arange(10)*1, label='#1')
ax.plot(np.arange(10), np.arange(10)*2, label='#2')
ax.plot(np.arange(10), np.arange(10)*3, label='#3')

leg = ax.legend(labelcolor=['r', 'g', 'b'])
for text, color in zip(leg.get_texts(), ['r', 'g', 'b']):
assert mpl.colors.same_color(text.get_color(), color)


def test_legend_labelcolor_linecolor():
# test the labelcolor for labelcolor='linecolor'
fig, ax = plt.subplots()
ax.plot(np.arange(10), np.arange(10)*1, label='#1', color='r')
ax.plot(np.arange(10), np.arange(10)*2, label='#2', color='g')
ax.plot(np.arange(10), np.arange(10)*3, label='#3', color='b')

leg = ax.legend(labelcolor='linecolor')
for text, color in zip(leg.get_texts(), ['r', 'g', 'b']):
assert mpl.colors.same_color(text.get_color(), color)


def test_legend_labelcolor_markeredgecolor():
# test the labelcolor for labelcolor='markeredgecolor'
fig, ax = plt.subplots()
ax.plot(np.arange(10), np.arange(10)*1, label='#1', markeredgecolor='r')
ax.plot(np.arange(10), np.arange(10)*2, label='#2', markeredgecolor='g')
ax.plot(np.arange(10), np.arange(10)*3, label='#3', markeredgecolor='b')

leg = ax.legend(labelcolor='markeredgecolor')
for text, color in zip(leg.get_texts(), ['r', 'g', 'b']):
assert mpl.colors.same_color(text.get_color(), color)


def test_legend_labelcolor_markerfacecolor():
# test the labelcolor for labelcolor='markerfacecolor'
fig, ax = plt.subplots()
ax.plot(np.arange(10), np.arange(10)*1, label='#1', markerfacecolor='r')
ax.plot(np.arange(10), np.arange(10)*2, label='#2', markerfacecolor='g')
ax.plot(np.arange(10), np.arange(10)*3, label='#3', markerfacecolor='b')

leg = ax.legend(labelcolor='markerfacecolor')
for text, color in zip(leg.get_texts(), ['r', 'g', 'b']):
assert mpl.colors.same_color(text.get_color(), color)


def test_get_set_draggable():
legend = plt.legend()
assert not legend.get_draggable()
Expand Down