Skip to content

Commit 15ef029

Browse files
dvreed77jklymak
authored andcommitted
ENH: color brightening utility
1 parent 14d68df commit 15ef029

File tree

4 files changed

+121
-1
lines changed

4 files changed

+121
-1
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Color brightening
2+
----------------------
3+
4+
Often we would like the ability add subtle color variation to our plots,
5+
especially when similar element are plotted in close proximity to one another.
6+
`matplotlib.colors.brighten_color` can be used to take an existing color and
7+
brighten or darken it, by giving a positive or negative fraction.
8+
9+
.. plot:: mpl_examples/color/color_brighten_demo.py

examples/color/color_brighten_demo.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
===================
3+
Brighten color demo
4+
===================
5+
6+
Demo of `~.brighten_color` utility.
7+
8+
"""
9+
10+
import matplotlib.pyplot as plt
11+
import matplotlib.colors as mcolors
12+
import numpy as np
13+
14+
fig, ax = plt.subplots()
15+
16+
lightfacs = [-1., -0.5, 0., 0.5, 0.75, 1.0]
17+
N = len(lightfacs)
18+
y = np.linspace(0., 1., N+1) * N - 0.5
19+
for n, lightfac in enumerate(lightfacs):
20+
brightened_color = mcolors.brighten_color('blue', lightfac)
21+
ax.fill_between([0, 1], [y[n], y[n]], [y[n+1], y[n+1]],
22+
facecolor=brightened_color, edgecolor='k')
23+
24+
ax.set_yticklabels([''] + lightfacs)
25+
26+
ax.set_xlim([0, 1])
27+
ax.set_ylim(np.min(y), np.max(y))
28+
ax.set_ylabel('Brightening Fraction')
29+
ax.set_xticks([])
30+
ax.set_title('Brightening of Color Blue')
31+
plt.show()

lib/matplotlib/colors.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@
5151
from six.moves import zip
5252

5353
from collections import Sized
54+
import colorsys
5455
import itertools
5556
import re
5657
import warnings
5758

5859
import numpy as np
5960
import matplotlib.cbook as cbook
61+
6062
from ._color_data import BASE_COLORS, TABLEAU_COLORS, CSS4_COLORS, XKCD_COLORS
6163

6264

@@ -1992,3 +1994,49 @@ def from_levels_and_colors(levels, colors, extend='neither'):
19921994

19931995
norm = BoundaryNorm(levels, ncolors=n_data_colors)
19941996
return cmap, norm
1997+
1998+
1999+
def brighten_color(color, frac):
2000+
"""A color helper utility to either darken or brighten the given color.
2001+
2002+
This function first converts the given color to RGB using
2003+
`~.colorConverter` and then to
2004+
HSL using `colorsys.rgb_to_hsl`. The lightness is modified according
2005+
to the given fraction, clipped to be between 0 and 1, and then converted
2006+
back to RGB using `colorsys.hsl_to_rgb`:
2007+
L = np.clip(L0 * (1.0 + frac), 0., 1.), where L0 is the original
2008+
lighness of the color in HSL space.
2009+
2010+
Parameters
2011+
----------
2012+
color : string, list, hexvalue
2013+
Any acceptable Matplotlib color value, such as 'red',
2014+
'slategrey', '#FFEE11', (1,0,0)
2015+
2016+
frac : float
2017+
The amount by which to darken or brighten the color. Negative
2018+
darkens, positive brightens. Lowest valid negative value is -1.
2019+
Highest positive value is 1/L of the original color, where L is
2020+
the lightness in HSL space. Entries outside this range are allowed,
2021+
but the resulting lightness is clipped between 0. and 1.
2022+
2023+
Returns
2024+
-------
2025+
color : tuple of floats
2026+
tuple representing converted rgb values
2027+
2028+
"""
2029+
2030+
frac = float(frac)
2031+
if not np.isfinite(frac):
2032+
raise ValueError('argument frac must be a finite float')
2033+
2034+
rgb = colorConverter.to_rgb(color)
2035+
2036+
h, l, s = colorsys.rgb_to_hls(*rgb)
2037+
2038+
l *= 1. + frac
2039+
2040+
l = np.clip(l, 0., 1.)
2041+
2042+
return colorsys.hls_to_rgb(h, l, s)

lib/matplotlib/tests/test_colors.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import numpy as np
1111
import pytest
1212

13-
from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
13+
from numpy.testing.utils import (assert_array_equal,
14+
assert_array_almost_equal, assert_equal)
1415

1516
from matplotlib import cycler
1617
import matplotlib
@@ -715,3 +716,34 @@ def __add__(self, other):
715716
else:
716717
assert len(recwarn) == 0
717718
recwarn.clear()
719+
720+
721+
def _brighten_test_helper(color, shade, expected):
722+
sc = mcolors.brighten_color(color, shade)
723+
assert_equal(sc, expected)
724+
725+
726+
def test_color_brightening():
727+
test_colors = (
728+
'red',
729+
'red',
730+
'red',
731+
'red',
732+
'red',
733+
[0, .5, .9],
734+
'slategrey',
735+
)
736+
test_brighten = (0, 0.50, 1.00, -0.50, -1.00, 0.20, -0.20)
737+
known_brighten_result = (
738+
(1.0, 0.0, 0.0),
739+
(1.0, 0.5, 0.5),
740+
(1.0, 1.0, 1.0),
741+
(0.5, 0.0, 0.0),
742+
(0.0, 0.0, 0.0),
743+
(0.080000000000000071, 0.59111111111111092, 1.0),
744+
(0.35097730430754981, 0.40156862745098038, 0.45215995059441105)
745+
)
746+
for color, brighten, expected in zip(test_colors,
747+
test_brighten,
748+
known_brighten_result):
749+
_brighten_test_helper(color, brighten, expected)

0 commit comments

Comments
 (0)