Skip to content

Legend shadow color #18668

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
wants to merge 15 commits into from
Closed
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
8 changes: 8 additions & 0 deletions doc/api/next_api_changes/behavior/18668-LL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Shadow parameter for Legend can be colorlike or bool
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The *shadow* parameter can now be any colorlike in addition to
a bool. If it is neither, a ValueError is thrown.

An accessory validation function `~.rcsetup.validate_color_or_bool`
has also been added, which preferentially returns a color.
12 changes: 12 additions & 0 deletions doc/users/next_whats_new/explicit_shadow_color.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Legend shadow colors can be explicitly defined
----------------------------------------------

The *shadow* parameter for the Legend constructor now
accepts both color and bool. If it is a bool, the
behavior is exactly the same as before.
Any colorlike value sets the shadow to that color,
subject to the same transparency effect that the default
facecolor undergoes.

An accessory validation function `~.rcsetup.validate_color_or_bool`
has also been added, which preferentially returns a color.
13 changes: 10 additions & 3 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from matplotlib import _api, docstring, colors
from matplotlib.artist import Artist, allow_rasterization
from matplotlib.cbook import silent_list
from matplotlib.colors import is_color_like
from matplotlib.font_manager import FontProperties
from matplotlib.lines import Line2D
from matplotlib.patches import (Patch, Rectangle, Shadow, FancyBboxPatch,
Expand Down Expand Up @@ -208,8 +209,9 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
Whether round edges should be enabled around the `~.FancyBboxPatch` which
makes up the legend's background.

shadow : bool, default: :rc:`legend.shadow`
shadow : bool or color, default: :rc:`legend.shadow`
Whether to draw a shadow behind the legend.
If value is a color, a shadow of that color will be applied.

framealpha : float, default: :rc:`legend.framealpha`
The alpha transparency of the legend's background.
Expand Down Expand Up @@ -514,7 +516,6 @@ def __init__(self, parent, handles, labels,
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'],
Expand Down Expand Up @@ -607,8 +608,14 @@ def draw(self, renderer):
self.legendPatch.set_bounds(bbox.x0, bbox.y0, bbox.width, bbox.height)
self.legendPatch.set_mutation_scale(fontsize)

if self.shadow:
if is_color_like(self.shadow):
Shadow(self.legendPatch, 2, -2, color=self.shadow).draw(renderer)
elif self.shadow is True:
Shadow(self.legendPatch, 2, -2).draw(renderer)
elif self.shadow is False:
pass
else:
raise ValueError('Shadow must be a valid color or bool.')

self.legendPatch.draw(renderer)
self._legend_box.draw(renderer)
Expand Down
14 changes: 13 additions & 1 deletion lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,18 @@ def validate_bool(b):
raise ValueError('Could not convert "%s" to bool' % b)


def validate_color_or_bool(c):
"""Convert c to color (preferentially) or bool"""
try:
return validate_color(c)
except ValueError:
pass
try:
return validate_bool(c)
except ValueError:
raise ValueError(f'Could not convert {c} to color or bool.')


@_api.deprecated("3.3")
def validate_bool_maybe_none(b):
"""Convert b to ``bool`` or raise, passing through *None*."""
Expand Down Expand Up @@ -1229,7 +1241,7 @@ def _convert_validator_spec(key, conv):
"legend.title_fontsize": validate_fontsize_None,
# the relative size of legend markers vs. original
"legend.markerscale": validate_float,
"legend.shadow": validate_bool,
"legend.shadow": validate_color_or_bool,
# whether or not to draw a frame around legend
"legend.frameon": validate_bool,
# alpha value of the legend frame
Expand Down
Loading