Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add legend.labelcolor in rcParams #20084

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
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
25 changes: 25 additions & 0 deletions doc/users/next_whats_new/rcparams_legend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
New rcParams for legend: set legend labelcolor globally
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A new :rc:`legend.labelcolor` sets the default *labelcolor* argument for
`.Figure.legend`. The special values 'linecolor', 'markerfacecolor'
(or 'mfc'), or 'markeredgecolor' (or 'mec') will cause the legend text to match
the corresponding color of marker.


.. plot::

plt.rcParams['legend.labelcolor'] = 'linecolor'

# Make some fake data.
a = np.arange(0, 3, .02)
c = np.exp(a)
d = c[::-1]

fig, ax = plt.subplots()
ax.plot(a, c, 'g--', label='Model length')
ax.plot(a, d, 'r:', label='Data length')

ax.legend()

plt.show()
12 changes: 9 additions & 3 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,15 @@ 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
labelcolor : str or list, default: :rc:`legend.labelcolor`
The color of the text in the legend. Either 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').

Labelcolor can be set globally using :rc:`legend.labelcolor`. If None,
use :rc:`text.color`.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to be picky, bit this should go in as

labelcolor : str or list, default: :rc:`legend.labelcolor`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review.
But when the rcParams[legend.labelcolor] is None(the default value(, should the docs say that it just uses the rcParams['text.color'] value?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that should be specified in the description of the parameter if it is not already

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine w/ me now. @tacaswell you have a block on this...

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 @@ -539,8 +542,11 @@ def __init__(self, parent, handles, labels,
'mec': ['get_markeredgecolor', 'get_edgecolor'],
}
if labelcolor is None:
pass
elif isinstance(labelcolor, str) and labelcolor in color_getters:
if mpl.rcParams['legend.labelcolor'] is not None:
labelcolor = mpl.rcParams['legend.labelcolor']
else:
labelcolor = mpl.rcParams['text.color']
if 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:
Expand Down
1 change: 1 addition & 0 deletions lib/matplotlib/mpl-data/matplotlibrc
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@
#legend.scatterpoints: 1 # number of scatter points
#legend.markerscale: 1.0 # the relative size of legend markers vs. original
#legend.fontsize: medium
#legend.labelcolor: None
#legend.title_fontsize: None # None sets to the same as the default axes.

## Dimensions as fraction of font size:
Expand Down
23 changes: 23 additions & 0 deletions lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,27 @@ def validate_color_for_prop_cycle(s):
return validate_color(s)


def _validate_color_or_linecolor(s):
if cbook._str_equal(s, 'linecolor'):
return s
elif cbook._str_equal(s, 'mfc') or cbook._str_equal(s, 'markerfacecolor'):
return 'markerfacecolor'
elif cbook._str_equal(s, 'mec') or cbook._str_equal(s, 'markeredgecolor'):
return 'markeredgecolor'
elif s is None:
return None
elif isinstance(s, str) and len(s) == 6 or len(s) == 8:
stmp = '#' + s
if is_color_like(stmp):
return stmp
if s.lower() == 'none':
return None
elif is_color_like(s):
return s

raise ValueError(f'{s!r} does not look like a color arg')


def validate_color(s):
"""Return a valid color arg."""
if isinstance(s, str):
Expand Down Expand Up @@ -1017,6 +1038,8 @@ def _convert_validator_spec(key, conv):
"legend.scatterpoints": validate_int,
"legend.fontsize": validate_fontsize,
"legend.title_fontsize": validate_fontsize_None,
# color of the legend
"legend.labelcolor": _validate_color_or_linecolor,
# the relative size of legend markers vs. original
"legend.markerscale": validate_float,
"legend.shadow": validate_bool,
Expand Down
79 changes: 79 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,85 @@ def test_legend_labelcolor_markerfacecolor():
assert mpl.colors.same_color(text.get_color(), color)


@pytest.mark.parametrize('color', ('red', 'none', (.5, .5, .5)))
def test_legend_labelcolor_rcparam_single(color):
# test the rcParams legend.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')

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


def test_legend_labelcolor_rcparam_linecolor():
# test the rcParams legend.labelcolor for a 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')

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


def test_legend_labelcolor_rcparam_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')

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


def test_legend_labelcolor_rcparam_markeredgecolor_short():
# 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')

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


def test_legend_labelcolor_rcparam_markerfacecolor():
# test the labelcolor for labelcolor='markeredgecolor'
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')

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


def test_legend_labelcolor_rcparam_markerfacecolor_short():
# test the labelcolor for labelcolor='markeredgecolor'
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')

mpl.rcParams['legend.labelcolor'] = 'mfc'
leg = ax.legend()
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
12 changes: 12 additions & 0 deletions lib/matplotlib/tests/test_rcparams.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
validate_bool,
validate_color,
validate_colorlist,
_validate_color_or_linecolor,
validate_cycler,
validate_float,
validate_fontweight,
Expand Down Expand Up @@ -329,6 +330,17 @@ def generate_validator_testcases(valid):
('(0, 1, "0.5")', ValueError), # last one not a float
),
},
{'validator': _validate_color_or_linecolor,
'success': (('linecolor', 'linecolor'),
('markerfacecolor', 'markerfacecolor'),
('mfc', 'markerfacecolor'),
('markeredgecolor', 'markeredgecolor'),
('mec', 'markeredgecolor')
),
'fail': (('line', ValueError),
('marker', ValueError)
)
},
{'validator': validate_hist_bins,
'success': (('auto', 'auto'),
('fd', 'fd'),
Expand Down