diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 2ce27a810a43..0d0186e9f770 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -232,9 +232,35 @@ def is_color_like(c): def _has_alpha_channel(c): - """Return whether *c* is a color with an alpha channel.""" - # 4-element sequences are interpreted as r, g, b, a - return not isinstance(c, str) and len(c) == 4 + """ + Return whether *c* is a color with an alpha channel. + + If *c* is not a valid color specifier, then the result is undefined. + """ + # The following logic uses the assumption that c is a valid color spec. + # For speed and simplicity, we intentionally don't care about other inputs. + # Anything can happen with them. + + # if c is a hex, it has an alpha channel when it has 4 (or 8) digits after '#' + if isinstance(c, str): + if c[0] == '#' and (len(c) == 5 or len(c) == 9): + # example: '#fff8' or '#0f0f0f80' + return True + else: + # if c isn't a string, it can be an RGB(A) or a color-alpha tuple + # if it has length 4, it has an alpha channel + if len(c) == 4: + # example: [0.5, 0.5, 0.5, 0.5] + return True + + # if it has length 2, it's a color/alpha tuple + # if the second element isn't None or the first element has length = 4 + if len(c) == 2 and (c[1] is not None or _has_alpha_channel(c[0])): + # example: ([0.5, 0.5, 0.5, 0.5], None) or ('r', 0.5) + return True + + # otherwise it doesn't have an alpha channel + return False def _check_color_like(**kwargs): diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 139efbe17407..a70b047d3dfc 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -1231,10 +1231,18 @@ def test_colormap_reversing(name): def test_has_alpha_channel(): assert mcolors._has_alpha_channel((0, 0, 0, 0)) assert mcolors._has_alpha_channel([1, 1, 1, 1]) + assert mcolors._has_alpha_channel('#fff8') + assert mcolors._has_alpha_channel('#0f0f0f80') + assert mcolors._has_alpha_channel(('r', 0.5)) + assert mcolors._has_alpha_channel(([1, 1, 1, 1], None)) assert not mcolors._has_alpha_channel('blue') # 4-char string! assert not mcolors._has_alpha_channel('0.25') assert not mcolors._has_alpha_channel('r') assert not mcolors._has_alpha_channel((1, 0, 0)) + assert not mcolors._has_alpha_channel('#fff') + assert not mcolors._has_alpha_channel('#0f0f0f') + assert not mcolors._has_alpha_channel(('r', None)) + assert not mcolors._has_alpha_channel(([1, 1, 1], None)) def test_cn():