9. color — Playing with colors.

This module holds the basic functionality for working with colors in pyFormex. The Color class represents a single color. It allows creation of a color from different inputs and conversion to many outputs. For working with large sets of colors, there is the colorArray, which collects many colors in a numpy.ndarray, allowing highly performant computation. There are functions to handle named colors, convert between color systems, compute lightness.

A number of legacy functions ar deprecated, as their functionlity can be achieved by using the Color class.

The following table shows the built-in colors, with their name, RGB values in 0..1 range and luminance.

>>> with floatformat('.1f'):
...     for k,v in PF_COLORS.items():
...         print(f"{k:>15s} = {v} -> {v.luminance():.3f} ({v.lightness():.3f})")
       darkgrey = (0.4, 0.4, 0.4) -> 0.133 (0.432)
            red = (1.0, 0.0, 0.0) -> 0.213 (0.532)
          green = (0.0, 1.0, 0.0) -> 0.715 (0.877)
           blue = (0.1, 0.1, 0.8) -> 0.053 (0.275)
           cyan = (0.0, 1.0, 1.0) -> 0.787 (0.911)
        magenta = (1.0, 0.0, 1.0) -> 0.285 (0.603)
         yellow = (1.0, 1.0, 0.0) -> 0.928 (0.971)
          white = (1.0, 1.0, 1.0) -> 1.000 (1.000)
          black = (0.0, 0.0, 0.0) -> 0.000 (0.000)
        darkred = (0.6, 0.0, 0.0) -> 0.068 (0.313)
      darkgreen = (0.0, 0.5, 0.0) -> 0.153 (0.461)
       darkblue = (0.1, 0.2, 0.6) -> 0.049 (0.264)
       darkcyan = (0.0, 0.6, 0.6) -> 0.251 (0.572)
    darkmagenta = (0.6, 0.0, 0.6) -> 0.091 (0.361)
     darkyellow = (0.6, 0.6, 0.0) -> 0.296 (0.613)
      lightgrey = (0.8, 0.8, 0.8) -> 0.604 (0.820)
     mediumgrey = (0.6, 0.6, 0.6) -> 0.319 (0.632)
  pyformex_pink = (1.0, 0.2, 0.4) -> 0.246 (0.567)
         orange = (1.0, 0.5, 0.0) -> 0.366 (0.670)
         purple = (0.6, 0.2, 1.0) -> 0.164 (0.474)
          brown = (0.6, 0.4, 0.2) -> 0.165 (0.476)
           gold = (1.0, 0.8, 0.0) -> 0.644 (0.842)
         orchid = (0.8, 0.4, 0.9) -> 0.280 (0.599)
 lightlightgrey = (0.9, 0.9, 0.9) -> 0.787 (0.911)
>>> Palette['default']
('darkgrey', 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'white',
 'black', 'darkred', 'darkgreen', 'darkblue', 'darkcyan', 'darkmagenta',
 'darkyellow', 'lightgrey', 'mediumgrey', 'pyformex_pink', 'orange', 'purple',
 'brown', 'gold', 'orchid', 'lightlightgrey')
>>> Palette['dark']
('darkgrey', 'blue', 'black', 'darkred', 'darkgreen', 'darkblue',
 'darkmagenta', 'purple', 'brown')
>>> Palette['light']
('red', 'green', 'cyan', 'magenta', 'yellow', 'white', 'darkcyan',
 'darkyellow', 'lightgrey', 'mediumgrey', 'pyformex_pink', 'orange', 'gold',
 'orchid', 'lightlightgrey')

9.1. Classes defined in module color

class color.Color(*color, alpha=None, clip=False)[source]

A class representing a color.

The Color class represents a single color, with or without transparency. The color is internally stored as a tuple of 3 (RGB) or 4 (RGBA) components. Each component is a float value in the range 0.0 to 1.0. Color instances can be initialized from a variety of inputs.

Parameters:
  • color

    One, three or four arguments specifying the color. If three or four arguments are given, they are handled as if a single argument tuple(*colors) was provided. If only one argument, it must be one of the following:

    • an int: an index into the Color.palette (modulo the palette length)

    • a float: a grey color with the given intensity

    • a string with the name of one of the built-in colorset(‘pf’)

    • a string specifying the X11 name of a color

    • a hex string ‘#rgb’ or ‘#rrggbb’ with 1 or 2 hexadecimal digits per color

    • a tuple or list of 3 or 4 integer values in the range 0..255

    • a tuple or list of 3 or 4 float values in the range 0.0..1.0

  • alpha (float, optional) – A float in the range 0.0 to 1.0. If provided, forces the creation of a 4-channel color, adding the provided value as the alpha channel if *color only contained 3 components. This will not overwrite the alpha channel if *color already contains 4 components. Overwriting alpha can be achieved with Color(*color[:3], alpha=value).

  • clip (bool) – If True, the final values will be clipped to the range 0.0..1.0. If False (default), values outside that range are allowed: OpenGL can make clever use of such values and clip them at render time.

Raises:

ValueError – If the input is not one of the accepted data.:

Examples

>>> Color(1.0, 1.0, 0.0) == Color([1.0, 1.0, 0.0])
True
>>> c = Color(1.0, 0.5, 0.2)
>>> c
Color(1.0, 0.5, 0.2)
>>> c.alpha
>>> c.rgb
(1.0, 0.5, 0.2)
>>> c.rgba
(1.0, 0.5, 0.2, 0.5)
>>> c.RGB
(255, 128, 51)
>>> c.RGBA
(255, 128, 51, 128)
>>> c.web
'#ff8033'
>>> c.gl
array([1. , 0.5, 0.2])
>>> c.gl4
array([1. , 0.5, 0.2, 0.5])
>>> c.name
'chocolate1'
>>> c.namediff()
('chocolate1', 0.03398...)
>>> c.luminance()
0.3681...
>>> Color(2)
Color(0.0, 1.0, 0.0)
>>> Color('red')
Color(1.0, 0.0, 0.0)
>>> Color('indianred')
Color(0.8039..., 0.3607..., 0.3607...)
>>> Color('grey90')
Color(0.8980...,  0.8980...,  0.8980...)
>>> Color('#ff0000')
Color(1.0, 0.0, 0.0)
>>> Color("zorro")
Traceback (most recent call last):
...
pyformex.color.InvalidColor: No color named 'zorro'
>>> red
Color(1.0, 0.0, 0.0)
>>> Color([200,200,255])
Color(0.7843..., 0.7843..., 1.0)
>>> Color(np.array([200,200,255], dtype=np.uint8))
Color(0.7843..., 0.7843..., 1.0)
>>> Color([1.,1.,1.])
Color(1.0, 1.0, 1.0)
>>> Color(0.6)
Color(0.6, 0.6, 0.6)
>>> Color(0.6, alpha=0.8)
Color(0.6, 0.6, 0.6, 0.8)
>>> Color(200, 200, 255, 128)
Color(0.7843..., 0.7843..., 1.0, 0.5...)
>>> Color(200, 200, 255, alpha=0.5)
Color(0.7843..., 0.7843..., 1.0, 0.5)
>>> Color(200, 200, 255, 255, alpha=0.5)
Color(0.7843..., 0.7843..., 1.0, 1.0)
clip(min=0.0, max=1.0)[source]

Clip the value to the specified range

property rgb

Return the red, green and blue component as a tuple

property rgba

Return a tuple (r,g,b,a)

property RGB

Return red, green and blue values as int values

property RGBA

Return RGBA int values

property gl

Return the red, green and blue components as a float array

property web

Convert a Color to hex RGB string (webcolor)

property name

Return a human name for the color

property fg

Return the ANSI escape sequence to set this color as foreground

property bg

Return the ANSI escape sequence to set this color as background

luminance(gamma=True)[source]

Compute the luminance of a color.

Returns:

float – A value in the range 0.0 (black) to 1.0 (white). The higher the luminance, the brighter the color appears to the human eye. The result is not linear for the human perception though: a luminance twice as high does not mean twice as light. Use lightness() if you need a linear response.

Examples

>>> print([f"{Color(c).luminance():0.2f}"
...     for c in ['black','red','green','blue']])
['0.00', '0.21', '0.72', '0.05']
lightness()[source]

Compute the perceived lightness of a color.

Returns:

float – A float in the range 0.0 (black) to 1.0 (white). A higher lightness means that the color appears brighter to the human eye. This can for example be used to derive a good contrasting foreground color to display text on a colored background. Values lower than 0.5 contrast well with white, larger value contrast better with black. The response is linear: a color with lightness twice as high, will appear twice as bright.

Notes

Traditionally, lightness is often returned on a scale of 0 to 100. We use 0 to 1, as it is more in line with the other color values.

rms_diff(color)[source]

Compute a scalar difference between two colors

closest_from(cset)[source]

Find the closest color from a colorset

namediff(colorsets=('pf', 'x11'))[source]

Find the closest color from all colorsets

classmethod grey(f)[source]

Return a grey color

classmethod setPalette(colors)[source]

Set the palette with a list of colors

class color.ansi[source]

Ansi escape sequences for colors

Contains attributes: reset, bold, dim, underline, reverse, invisible, crossout and erase_eol. Furthermore, there are two static functions to set foreground and background color: fg and bg, both taking a triple R,G,B values (0..255) as parameters.

static fg(r, g, b)[source]

Return the ANSI escape sequence to set a foreground color r,g,b

static bg(r, g, b)[source]

Return the ANSI escape sequence to set a background color r,g,b

9.2. Functions defined in module color

color.colorArray(colors)[source]

Create an array of colors.

When working with large collections of colors, colorArray provides important performance benefits over the use of individual Color instances.

Parameters:

colors (float or str array_like) – One or more colors defined by float tuples rgb or rgba (this includes Color instances) or by common color names.

Returns:

float ndarray – A float ndarray of shape (…, 3) or (…, 4), depending on the input.

Examples

>>> colorArray('red')
array([1., 0., 0.])
>>> colorArray('grey90')
array([0.898, 0.898, 0.898])
>>> colorArray(['red', 'green', 'blue'])
array([[1. , 0. , 0. ],
       [0. , 1. , 0. ],
       [0.1, 0.1, 0.8]])
>>> colorArray([['red', 'green', 'blue'], ['cyan', 'magenta', 'yellow']])
array([[[1. , 0. , 0. ],
        [0. , 1. , 0. ],
        [0.1, 0.1, 0.8]],
       [[0. , 1. , 1. ],
        [1. , 0. , 1. ],
        [1. , 1. , 0. ]]])
>>> colorArray((255, 128, 64))
Traceback (most recent call last):
...
pyformex.color.InvalidColor: colorArray does not accept integer input
color.GLcolor(color)[source]

Convert color input to a tuple (r,g,b)

This is like Color(color), but invalid colors return (0., 0., 0.)

color.GLcolor4(color, alpha=0.5)[source]

Like GLcolor with alpha.

color.GREY(val, alpha=1.0)[source]

Returns a grey OpenGL color of given intensity (0..1)

color.RGBAcolor(color)[source]

Return an RGBA (0-255) array for a color.

color.RGB_rgb(RGB)[source]

Convert int255 rgb values to float

color.RGB_web(R, G, B)[source]

Convert a tuple(R,G,B) to hex RGB string (webcolor)

Examples

>>> RGB_web(255, 128, 64)
'#ff8040'
color.RGBcolor(color)[source]

Return an RGB (0-255) array for a color

color.WEBcolor(color)[source]

Return the web color name for a color

color.clipit(value, minvalue=None, maxvalue=None)[source]

Clip a float value

>>> clipit(1.7)
1.7
>>> clipit(1.7, minvalue=2.0)
2.0
color.colorName(color)

Return the web color name for a color

color.colornames(cset=None)[source]

Return a list of color names in specified colorset(s).

If cset is str: return pure names If cset is list of str: return prefixed names If cset is None: cset = [all colorsets]

>>> colornames('x11')[0]
'aliceblue'
>>> colornames('pf')[0]
'darkgrey'
>>> colornames(['pf', 'x11'])[0]
'pf:darkgrey'
color.colorset(cset)[source]

Return a colorset

This provides lazy loading of the colorsets. They are only loaded when used.

>>> d = colorset('x11')
>>> type(_COLORSETS_['x11'])
<class 'dict'>
color.colorsets()[source]

Return names of available colorsets

>>> colorsets()
('pf', 'x11', 'xkcd')
color.download_file(url, filename=None)[source]

Download a file from a given url

color.gamma(c)[source]

Apply gamma correction to an rgb channel

Computes the sRGB from a linearized RGB value

See also

https

//en.wikipedia.org/wiki/SRGB

color.inv_gamma(c)[source]

Apply inverse gamma correction to an rgb channel

This is also known as linearizing (or gamma-expanding) the channel

See also

https

//en.wikipedia.org/wiki/SRGB

color.lightness(Y)[source]

Compute perceived lightness L* from linear luminance between 0.0 and 1.0

Returns:

float – A float in the range 0.0 (black) to 1.0 (white).

Examples

>>> lightness(luminance(red))
array(0.5323)
>>> lightness(luminance(['black','red','green','blue']))
array([0.    , 0.5323, 0.8774, 0.2754])
>>> lightness(luminance([black,red,green,blue]))
array([0.    , 0.5323, 0.8774, 0.2754])
color.luminance(color, gamma=True)[source]

Compute the luminance of a color.

Returns:

float | float array – A value in the range 0.0 (black) to 1.0 (white). The higher the luminance, the brighter the color appears to the human eye. The result is not linear for the human perception though: a luminance twice as high does not mean twice as light. Use lightness() to map luminance to perceived lightness.

Examples

>>> luminance(red)
0.2126
>>> luminance(['black','red','green','blue'])
array([0.    , 0.2126, 0.7152, 0.0529])
>>> luminance([black, mediumgrey, lightgrey, white])
array([0.    , 0.3185, 0.6038, 1.    ])
color.named_color(name)[source]

Find the webcolor value for the named color

Parameters:

name (str) – The common name for the color, e.g. ‘darkgreen’. The name may be prefixed by the colorset where the name is to be found. Known colorsets are ‘pf’, ‘x11’, ‘xkcd’. A colorset string part must be followed by a ‘:’. Thus, ‘x11:darkgreen’ is the dark green from the x11 colorset. Multiple colorsets can be specified, like ‘xkcd:x11:darkgreen’, and will be looked up in that order until the first match. No prefix is equivalent to ‘pf:x11:xkcd:’.

Returns:

str | None – A string with the webcolor designation of the named color or None if no color with that name is found.

Examples

>>> named_color('darkgreen')
Color(0.0, 0.5, 0.0)
>>> named_color('pf:darkgreen')
Color(0.0, 0.5, 0.0)
>>> named_color('x11:darkgreen')
Color(0.0, 0.3921..., 0.0)
>>> named_color('xkcd:darkgreen')
Color(0.01960..., 0.2862..., 0.02745...)
>>> named_color('banana')
Color(1.0, 1.0, 0.4941...)
>>> named_color('x11:banana')   # no such color
color.normalize_color_name(col)[source]

Normalize a color name.

Different sources use different styles to name colors. This functions normalizes color names by removing spaces and special characters, converting everything to lower case, and converting ‘gray’ to ‘grey’.

Examples

>>> normalize_color_name('DarkGray')
'darkgrey'
>>> normalize_color_name(' dark gray')
'darkgrey'
>>> normalize_color_name('dark_gray-blue')
'dark_greyblue'
color.printc(*args, sep=' ', end='\n', file=None, flush=False, color=None, bgcolor=None)[source]

Print in color on an ANSI terminal

This is functionally equivalent with Python’s builtin print function, but has two extra parameters that allow printing in color on an ANSI compatible terminal. When the file parameter is used, color is disabled. When color is used, flush is forced to True.

Parameters:
  • color (color_like) – The color to be used for the displayed text

  • bgcolor (color_like) – The backgropund color to be used for the displayed text.

color.read_webcolors(filename)[source]

Read a webcolors file

A webcolors file is a text file where each line contains two strings: a webcolor string in the format #RRGGBB, and a common name for the color. Lines not starting with a ‘#’ are ignored.

Returns:

dict – A dict with the color names as keys and the webcolors as values.

color.rgb_RGB(rgb)[source]

Convert float rgb values to int255

color.rgb_srgb(rgb)[source]

Compute srgb from linear rgb

color.rgb_xyz(rgb)[source]

Convert RGB to CIEXYZ

The rgb values are the linearized rgb values

See also

https

//en.wikipedia.org/wiki/SRGB

color.srgb_rgb(srgb)[source]

Compute linear rgb from srgb

color.web_RGB(color)[source]

Convert a webcolor ‘#RRGGBB’ or ‘#RGB’ to (R,G,B) tuple

Examples

>>> web_RGB('#ff6633')
(255, 102, 51)
>>> web_RGB('#af3')
(170, 255, 51)
color.xyz_lab(xyz)[source]

Convert CIEXYZ to CIELAB

Notes

Lstar is the perceived lightness

See also

https

//en.wikipedia.org/wiki/CIELAB_color_space

color.xyz_rgb(xyz)[source]

Convert CIEXYZ to linear RGB

Notes

Y is the luminance

See also

https

//en.wikipedia.org/wiki/SRGB