matplotlib 中的颜色变暗或变亮

Posted

技术标签:

【中文标题】matplotlib 中的颜色变暗或变亮【英文标题】:Darken or lighten a color in matplotlib 【发布时间】:2016-10-12 10:08:33 【问题描述】:

假设我在 Matplotlib 中有一种颜色。也许它是一个字符串 ('k') 或一个 rgb 元组 ((0.5, 0.1, 0.8)) 甚至是一些十六进制 (#05FA2B)。 Matplotlib 中是否有命令/便利功能可以让我变暗(或变亮)该颜色。

即有matplotlib.pyplot.darken(c, 0.1) 或类似的东西吗?我想我希望的是,在幕后,会采用一种颜色,将其转换为 HSL,然后将 L 值乘以某个给定因子(下限为 0,上限为 1)或显式设置 L value 为给定值并返回修改后的颜色。

【问题讨论】:

您是在询问alpha 的值吗? 没有。我不想让颜色变得或多或少透明,我想让它更暗(更黑)或更亮(更白)。 检查:matplotlib.org/api/… 和 matplotlib.org/api/… 【参考方案1】:

这是来自my gist 的函数,用于减轻我认为适用于matplotlib 已知的任何颜色格式的任何颜色。我认为设置数量 > 1 也可能会变暗。

def lighten_color(color, amount=0.5):
    """
    Lightens the given color by multiplying (1-luminosity) by the given amount.
    Input can be matplotlib color string, hex string, or RGB tuple.

    Examples:
    >> lighten_color('g', 0.3)
    >> lighten_color('#F034A3', 0.6)
    >> lighten_color((.3,.55,.1), 0.5)
    """
    import matplotlib.colors as mc
    import colorsys
    try:
        c = mc.cnames[color]
    except:
        c = color
    c = colorsys.rgb_to_hls(*mc.to_rgb(c))
    return colorsys.hls_to_rgb(c[0], 1 - amount * (1 - c[1]), c[2])

编辑:确实,它既变暗又变亮:

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(-1, 1, 100)
plt.plot(xs, 0 * xs, color='b', lw=3)
plt.plot(xs, xs**2, color=lighten_color('b', 0.4), lw=3)
plt.plot(xs, -xs**2, color=lighten_color('b', 1.6), lw=3)

编辑 2: 删除了函数中不需要的 numpy 依赖项。

编辑 3: 使用 @FLekschas 改进的函数修改

def adjust_lightness(color, amount=0.5):
    import matplotlib.colors as mc
    import colorsys
    try:
        c = mc.cnames[color]
    except:
        c = color
    c = colorsys.rgb_to_hls(*mc.to_rgb(c))
    return colorsys.hls_to_rgb(c[0], max(0, min(1, amount * c[1])), c[2])

【讨论】:

这在这里很好用。令人惊讶的是,python 甚至在标准库中具有针对不同颜色系统的函数! 对于darken,当amount的值太大时,rgb会出错,请修复... 真棒要点!我将返回值更改为return colorsys.hls_to_rgb(c[0], max(0, min(1, amount * c[1])), c[2]),这样amount > 1 时颜色会变亮,amount < 1 时颜色会变暗。我还将亮度限制为[0,1],因为外部的值没有意义。 感谢@FLekschas,如果我可以在编辑中添加任何其他内容,请告诉我。 @Sosi matplotlib.org/3.1.1/api/_as_gen/matplotlib.colors.to_hex.html【参考方案2】:

仅使用作为 python 标准库的一部分的colorsys,只需两行代码即可扩展光照度

如果您仍然想要传递非 rgb 值(如颜色名称或 HEX)的选项,您可以简单地使用 matplotlib.colors.ColorConverter.to_rgb("#ff0000")

此方法缩放 rgb 颜色的亮度

import colorsys

def scale_lightness(rgb, scale_l):
    # convert rgb to hls
    h, l, s = colorsys.rgb_to_hls(*rgb)
    # manipulate h, l, s values and return as rgb
    return colorsys.hls_to_rgb(h, min(1, l * scale_l), s = s)

一个简单的演示。有关更多详细信息,请查看旧示例。

import matplotlib
import seaborn as sns

color = matplotlib.colors.ColorConverter.to_rgb("navy")
rgbs = [scale_lightness(color, scale) for scale in [0, .5, 1, 1.5, 2]]
sns.palplot(rgbs)

旧答案

有一个Seaborn method,可以让你轻松控制亮度。 seaborn.set_hls_values() 将颜色作为 RGB-Tuple、HEX 或 HTML 名称,让您控制色调、亮度和饱和度。

缩放后的亮度应在01 之间,其中1 < scale 增加亮度,0 ≤ scale < 1 加深颜色。

from colorsys import rgb_to_hls
import seaborn as sns

color = (1.0, 0.0, 0.0)     # RGB

print(f"Input color:    \t Lightness:  rgb_to_hls(*color)[1]: .2g\t RGB:  color")

rgbs = []
for scale in [0, .5, 1, 1.5, 2]:

    # scale the lightness (The values should be between 0 and 1)
    lightness = min(1, rgb_to_hls(*color)[1] * scale)

    # manipulate h, l, s channel of a rgb color
    rgb = sns.set_hls_values(color = color, h = None, l = lightness, s = None)

    print(f"Scale factor: scale: .2g\t Lightness:  lightness: .2g  \t RGB:  rgb")
    rgbs.append(rgb)

sns.palplot(rgbs)

如果您想使用 RGB 以外的代码,则需要将颜色转换为 RGB。您可以使用以下命令。

color = "red"               # HTML name
color = "#ff0000"           # HEX
color = matplotlib.colors.ColorConverter.to_rgb(color)

返回值为 RGB-Tuples:

Input color:        Lightness:   0.5    RGB:  (1.0, 0.0, 0.0)

Scale factor:  0    Lightness:   0      RGB:  (0.0, 0.0, 0.0)  # Black
Scale factor:  0.5  Lightness:   0.25   RGB:  (0.5, 0.0, 0.0)
Scale factor:  1    Lightness:   0.5    RGB:  (1.0, 0.0, 0.0)  # Unchanged
Scale factor:  1.5  Lightness:   0.75   RGB:  (1.0, 0.5, 0.5)
Scale factor:  2    Lightness:   1      RGB:  (1.0, 1.0, 1.0)  # White

编辑:

感谢@fhgd!我更改了代码以实际缩放亮度,而不仅仅是设置它。

【讨论】:

当您查看sns.set_hls_values() 的代码时,它设置颜色的左值而不是缩放它,这是变亮/变暗所需的。您可以使用sns.set_hls_values([0.2, 0.2, 0.2], l=0.5) == [0.5, 0.5, 0.5] 对其进行测试,这不是 [0.2, 0.2, 0.2] 的原始颜色。 现在缩放工作了。您可以尝试使用例如。 color = "lime"color = "lightblue"color = [0.8, 0.8, 0.8] 等等…… 在一行中使用 numpy:colorsys.hls_to_rgb(*np.array(colorsys.rgb_to_hls(53, 255, 10)) * [1, .5, 1])【参考方案3】:

几个月前,我不得不解决这个问题。这个想法是让用户选择一种颜色(任何颜色),软件会自动生成一个颜色图(这是用于科学目的的软件包的一部分)。

无论如何,这里是我用来实现它的代码。您不需要对象的大部分功能,但它会满足您的要求:

import math

class Color():
    def __init__(self, color, fmt='rgb'):
        self.__initialize__(color, fmt)

    def __initialize__(self, color, fmt='rgb'):
        if fmt == 'rgb':
            self.rgb = (int(color[0]), int(color[1]), int(color[2]))
            self.hex = self._rgb2hex(self.rgb)
            self.hsv = self._rgb2hsv(self.rgb)
            self.rgb0 = self.rgb[0] / 255, self.rgb[1] / 255, self.rgb[2] / 255
        elif fmt == 'rgb0':
            self.rgb = (int(color[0] * 255), int(color[1] * 255), int(color[2] * 255))
            self.hex = self._rgb2hex(self.rgb)
            self.hsv = self._rgb2hsv(self.rgb)
            self.rgb0 = (color[0], color[1], color[2])
        elif fmt == 'hex':
            self.hex = color
            self.rgb = self._hex2rgb(self.hex)
            self.hsv = self._rgb2hsv(self.rgb)
            self.rgb0 = self.rgb[0] / 255, self.rgb[1] / 255, self.rgb[2] / 255
        elif fmt == 'hsv':
            self.hsv = color
            self.rgb = self._hsv2rgb(self.hsv)
            self.hex = self._rgb2hex(self.rgb)
            self.rgb0 = self.rgb[0] / 255, self.rgb[1] / 255, self.rgb[2] / 255
        self.__automaticPalette__()

    def __automaticPalette__(self):
        self.rgbColors = []
        self.hexColors = []
        self.hsvColors = []
        self.rgb0Colors = []
        hsv = self.hsv
        for i in range(255):
            new_hsv = hsv[0], hsv[1], (1 / 255) * i
            self.rgbColors.append(self._hsv2rgb(new_hsv))
            self.hexColors.append(self._rgb2hex(self.rgbColors[-1]))
            self.hsvColors.append(new_hsv)
            r, g, b = self.rgbColors[-1]
            self.rgb0Colors.append((r / 255, g / 255, b / 255))

    def _testPalette(self, o=1):
        from matplotlib import pyplot as plt
        from matplotlib.patches import Rectangle
        if o == 1:
            someX, someY = 0.5, 0.1
            plt.figure()
            s = 1
            currentAxis = plt.gca()
            for x in range(254):
                currentAxis.add_patch(Rectangle((x * s, someY), s, 0.1, alpha=1, color=self.rgb0Colors[x]))
            currentAxis.add_patch(Rectangle((5 * s, someY + 0.07), 30, 0.02, alpha=1, color=self.rgb0))

            plt.ylim(0.1, 0.2)
            plt.xlim(0, (x + 1) * s)
            plt.show()
        elif o == 2:
            local = self.rgb0Colors[90:190][0:-1:10]
            someX, someY = 0.5, 0.1
            plt.figure()
            s = 1
            currentAxis = plt.gca()
            for x in range(len(local)):
                currentAxis.add_patch(Rectangle((x * s, someY), s, 0.1, alpha=1, color=local[x]))
            currentAxis.add_patch(Rectangle((5 * s, someY + 0.07), 30, 0.02, alpha=1, color=self.rgb0))

            plt.ylim(0.1, 0.2)
            plt.xlim(0, (x + 1) * s)
            plt.show()

    def _hex2rgb(self, value):
        # http://***.com/questions/214359/converting-hex-color-to-rgb-and-vice-versa
        value = value.lstrip('#')
        lv = len(value)
        return tuple(int(value[i:i + int(lv / 3)], 16) for i in range(0, lv, int(lv / 3)))

    def _rgb2hex(self, rgb):
        # http://***.com/questions/214359/converting-hex-color-to-rgb-and-vice-versa
        r = rgb[0]
        g = rgb[1]
        b = rgb[2]
        return '#%02X%02X%02X' % (r, g, b)

    def _hsv2rgb(self, hsv):
        # http://code.activestate.com/recipes/576919-python-rgb-and-hsv-conversion/
        h, s, v = hsv
        h = float(h)
        s = float(s)
        v = float(v)
        h60 = h / 60.0
        h60f = math.floor(h60)
        hi = int(h60f) % 6
        f = h60 - h60f
        p = v * (1 - s)
        q = v * (1 - f * s)
        t = v * (1 - (1 - f) * s)
        r, g, b = 0, 0, 0
        if hi == 0:
            r, g, b = v, t, p
        elif hi == 1:
            r, g, b = q, v, p
        elif hi == 2:
            r, g, b = p, v, t
        elif hi == 3:
            r, g, b = p, q, v
        elif hi == 4:
            r, g, b = t, p, v
        elif hi == 5:
            r, g, b = v, p, q
        r, g, b = int(r * 255), int(g * 255), int(b * 255)
        return r, g, b

    def _rgb2hsv(self, rgb):
        # http://code.activestate.com/recipes/576919-python-rgb-and-hsv-conversion/
        r, g, b = rgb
        r, g, b = r / 255.0, g / 255.0, b / 255.0
        mx = max(r, g, b)
        mn = min(r, g, b)
        df = mx - mn
        if mx == mn:
            h = 0
        elif mx == r:
            h = (60 * ((g - b) / df) + 360) % 360
        elif mx == g:
            h = (60 * ((b - r) / df) + 120) % 360
        elif mx == b:
            h = (60 * ((r - g) / df) + 240) % 360
        if mx == 0:
            s = 0
        else:
            s = df / mx
        v = mx
        return h, s, v

    def getColor(self, fmt='rgb'):
        if fmt == 'rgb':
            return self.rgb
        elif fmt == 'hex':
            return self.hex
        elif fmt == 'rgb0':
            return self.rgb0
        elif fmt == 'hsv':
            return self.hsv

所以如果你这样称呼它:

c = Color((51, 153, 255))
# c = Color((0.5, 0.1, 0.8), fmt='rgb0') # It should work with rgb0
# c = Color('#05d4fa', fmt='hex')        # and hex but I don't remember if it was well tested so be careful (the conversions might be messy).
c._testPalette(1)
print(c.rgbColors)

它会返回给你:

,这个:

[(0, 0, 0), (0, 0, 1), (0, 1, 2), (0, 1, 3), (0, 2, 4), (0, 3, 5), (1, 3, 6), (1, 4, 7), (1, 4, 8), (1, 5, 9), (1, 6, 10), (2, 6, 11), (2, 7, 12), (2, 7, 13), (2, 8, 14), (2, 9, 15), (3, 9, 16), (3, 10, 17), (3, 10, 18), (3, 11, 19), (3, 12, 20), (4, 12, 21), (4, 13, 22), (4, 13, 23), (4, 14, 24), (4, 15, 25), (5, 15, 26), (5, 16, 27), (5, 16, 28), (5, 17, 29), (5, 18, 30), (6, 18, 31), (6, 19, 32), (6, 19, 32), (6, 20, 34), (6, 21, 35), (7, 21, 36), (7, 22, 36), (7, 22, 38), (7, 23, 39), (7, 24, 40), (8, 24, 40), (8, 25, 42), (8, 25, 43), (8, 26, 44), (8, 26, 44), (9, 27, 46), (9, 28, 47), (9, 28, 48), (9, 29, 48), (9, 30, 50), (10, 30, 51), (10, 31, 52), (10, 31, 52), (10, 32, 54), (10, 33, 55), (11, 33, 56), (11, 34, 56), (11, 34, 58), (11, 35, 59), (11, 36, 60), (12, 36, 60), (12, 37, 62), (12, 37, 63), (12, 38, 64), (12, 38, 65), (13, 39, 65), (13, 40, 67), (13, 40, 68), (13, 41, 69), (13, 42, 70), (14, 42, 71), (14, 43, 72), (14, 43, 73), (14, 44, 73), (14, 45, 75), (15, 45, 76), (15, 46, 77), (15, 46, 78), (15, 47, 79), (15, 48, 80), (16, 48, 81), (16, 49, 81), (16, 49, 83), (16, 50, 84), (16, 50, 85), (17, 51, 86), (17, 52, 87), (17, 52, 88), (17, 53, 89), (17, 53, 89), (18, 54, 91), (18, 55, 92), (18, 55, 93), (18, 56, 94), (18, 57, 95), (19, 57, 96), (19, 58, 97), (19, 58, 97), (19, 59, 99), (19, 60, 100), (20, 60, 101), (20, 61, 102), (20, 61, 103), (20, 62, 104), (20, 62, 105), (21, 63, 105), (21, 64, 107), (21, 64, 108), (21, 65, 109), (21, 66, 110), (22, 66, 111), (22, 67, 112), (22, 67, 113), (22, 68, 113), (22, 69, 115), (23, 69, 116), (23, 70, 117), (23, 70, 118), (23, 71, 119), (23, 72, 120), (24, 72, 121), (24, 73, 121), (24, 73, 123), (24, 74, 124), (24, 74, 125), (25, 75, 126), (25, 76, 127), (25, 76, 128), (25, 77, 129), (25, 77, 130), (26, 78, 131), (26, 79, 131), (26, 79, 133), (26, 80, 134), (26, 81, 135), (27, 81, 136), (27, 82, 137), (27, 82, 138), (27, 83, 139), (27, 84, 140), (28, 84, 141), (28, 85, 142), (28, 85, 143), (28, 86, 144), (28, 86, 145), (29, 87, 146), (29, 88, 147), (29, 88, 147), (29, 89, 149), (29, 90, 150), (30, 90, 151), (30, 91, 152), (30, 91, 153), (30, 92, 154), (30, 93, 155), (31, 93, 156), (31, 94, 157), (31, 94, 158), (31, 95, 159), (31, 96, 160), (32, 96, 161), (32, 97, 162), (32, 97, 163), (32, 98, 163), (32, 99, 165), (33, 99, 166), (33, 100, 167), (33, 100, 168), (33, 101, 169), (33, 101, 170), (34, 102, 171), (34, 103, 172), (34, 103, 173), (34, 104, 174), (34, 105, 175), (35, 105, 176), (35, 106, 177), (35, 106, 178), (35, 107, 179), (35, 107, 179), (36, 108, 181), (36, 109, 182), (36, 109, 183), (36, 110, 184), (36, 110, 185), (37, 111, 186), (37, 112, 187), (37, 112, 188), (37, 113, 189), (37, 114, 190), (38, 114, 191), (38, 115, 192), (38, 115, 193), (38, 116, 194), (38, 116, 195), (39, 117, 195), (39, 118, 197), (39, 118, 198), (39, 119, 199), (39, 120, 200), (40, 120, 201), (40, 121, 202), (40, 121, 203), (40, 122, 204), (40, 123, 205), (41, 123, 206), (41, 124, 207), (41, 124, 208), (41, 125, 209), (41, 125, 210), (42, 126, 211), (42, 127, 211), (42, 127, 213), (42, 128, 214), (42, 129, 215), (43, 129, 216), (43, 130, 217), (43, 130, 218), (43, 131, 219), (43, 132, 220), (44, 132, 221), (44, 133, 222), (44, 133, 223), (44, 134, 224), (44, 135, 225), (45, 135, 226), (45, 136, 227), (45, 136, 227), (45, 137, 229), (45, 138, 230), (46, 138, 231), (46, 139, 232), (46, 139, 233), (46, 140, 234), (46, 140, 235), (47, 141, 236), (47, 142, 237), (47, 142, 238), (47, 143, 239), (47, 144, 240), (48, 144, 241), (48, 145, 242), (48, 145, 243), (48, 146, 243), (48, 147, 245), (49, 147, 246), (49, 148, 247), (49, 148, 248), (49, 149, 249), (49, 149, 250), (50, 150, 251), (50, 151, 252), (50, 151, 253), (50, 152, 254)]

这是为创建该颜色图而生成的所有颜色的列表。不过它是自定义的,matplotlib 只是用来绘制它。

编辑: 只是说明这是如何实现的。 RGB 为您提供红色、绿色和蓝色的值。另一方面,HSL (HSV) 为您提供色调、饱和度和亮度(值)。因此,如果您将颜色从 RGB 转换为 HSL,然后运行整个亮度光谱,您将获得颜色的从暗到亮的值(例如,蓝色将始终保持蓝色,尽管更亮和更暗)。

【讨论】:

以上是关于matplotlib 中的颜色变暗或变亮的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式使飞镖中的十六进制颜色变亮或变暗

React Native之Touchable四组件

视图 x 位置的通知

scss 使颜色变亮/变暗

Android仿微信底部菜单栏+顶部菜单栏

在现代 CSS 中悬停时更改为相对颜色