generativepy.color module


Martin McBride, 2020-07-27
Tags colour
Categories generativepy generative art

generativepy uses Color objects to represent colours.

Colours are stored as 4 values representing the red, green, blue and transparency (rgba). Each value has a range of 0.0 to 1.0, that represents the amount of that colour that is present:

  • An r value of 0.0 means that colour contains no red.
  • An r value of 1.0 means that colour contains the full intensity red.
  • An r value of 0.25 means that colour contains a 25% of full intensity red.
  • Similar for b and g, allowing any colour can be created using the r, g, b values.

For the alpha value, a:

  • An a value of 0.0 means that colour is fully transparent (ie it can't be seen at all).
  • An a value of 1.0 means that colour is fully opaque. It will completely hide anything behind it.
  • An a value of 0.25 means that colour is partially transparent. It will partly hide anything behind it, creating a colour that is 75% of the background colour mixed with 25% of the foreground colour.
  • The way foreground and background colours mix can be changed using Pycairo compositing operators if you wish.

Color can be used to represent various types of colour, but all are stored internally as rgba values (see the constructor section below for more details).

Color objects are immutable - you cannot change a Color object once it has been created. However there are various factory methods available for creating new colours that are based on an existing colour (for example you can create a new colour that is 20% more red, or 50% less saturated, based on an existing colour).

Color objects behave as immutable sequences (similar to tuples) so you can index, unpack, and loop over a Color.

There are a number of examples of using Color in the /examples/color folder on github.

The color module also contains the make_colormap function that can be used to create a color map.

Constructor

The Color constructor creates an rgba colour object. It accepts between 1 and 4 parameters.

All numerical input values are clamped in the range 0.0 to 1.0 (values less than 0.0 are replaced with 0.0, values greater than 1.0 are replaced with 1.0).

Monochrome (grey) colour

Color(k)
Parameter Type Description
k float The grey value for the colour

Creates a grey colour with a value between 0.0 (black) and 1.0 (white).

Internally this is represented as an rgba colour with the r, g and b values equal to k, and the a value to 1.

CSS named colour

Color(name)
Parameter Type Description
name string The CSS name of the colour

Creates a colour based on a CSS name. There are 158 named colours, commonly used in web design but very useful in other areas. The list includes a complete range of colours in different shades that are mainly quite visually pleasing, and can be a good source of colour ideas. There are colour charts available on various websites.

Internally this is represented as an rgba colour with the r, g and b set from a dictionary, the a value to 1.

Transparent monochrome (grey) colour

Color(k, a)
Parameter Type Description
k float The grey value for the colour
a float The alpha value for the colour

Creates a transparent grey colour.

Internally this is represented as an rgba colour with the r, g and b values equal to k, and the alpha value set to a.

Transparent CSS named colour

(name, a)
Parameter Type Description
name string The CSS name of the colour
a float The alpha value for the colour

Creates a transparent colour based on a CSS name.

Internally this is represented as an rgba colour with the r, g and b set from a dictionary, the alpha value set to 1.

RGB colour

Color(r, g, b)
Parameter Type Description
r float The red value for the colour
g float The green value for the colour
b float The blue value for the colour

Creates an rgb colour.

Internally this is represented as an rgba colour based on the r, g and b values, with the a value to 1.

RGBA colour

Color(r, g, b)
Parameter Type Description
r float The red value for the colour
g float The green value for the colour
b float The blue value for the colour
a float The alpha value for the colour

Creates a transparent rgba colour.

Internally this is represented as an rgba colour based on the r, g, b and a values.

HSL colour

Color.of_hsl(h, s, l)
Parameter Type Description
h float The hue value for the colour
s float The saturation value for the colour
l float The lightness value for the colour

Creates an HSL colour.

HSL colours are defined by 3 values:

  • The hue value controls the position of the colour the colour wheel.
  • The saturation controls how pure the colour is. For a particular hue, reducing the saturation creates a greyed out version of the same colour.
  • The lightness controls how light the colour is. Varying the lightness creates a lighter or darker version of the same colour.

HSL is very useful because it allows you to control colours more intuitively.

Internally the colour is still represented as an rgba colour. The h, s and l values are converted to rgb, with the a value to 1.

HSLA colour

Color.of_hsla(h, s, l, a)
Parameter Type Description
h float The hue value for the colour
s float The saturation value for the colour
l float The lightness value for the colour
a float The alpha value for the colour

Creates an HSLA colour.

Internally the colour is still represented as an rgba colour. The h, s and l values are converted to rgb, with the a added to set the transparency.

Properties

Color objects have the following properties:

Property Type Description
r float The red value of the colour
g float The green value of the colour
b float The blue value of the colour
a float The alpha value of the colour
rgb tuple A tuple of the (r, g, b) values of the colour
rgba tuple A tuple of the (r, g, b, ) values of the colour
h float The hue value of the colour
s float The saturation value of the colour
l float The lightness value of the colour

Properties are used like this:

color = Color(1, 0, 0)   # rgb colour
print(color.b)           # The blue value of color

All these properties are available no matter how the colour was create. So for example if the colour was created as an rgb colour, you can still get the h property. The h, s, l values are calculated from the rgba colour as needed.

Getters

The as_rgbstr method returns the rgb values of the colour as a string in the format rgb(0, 128, 255). The three values represent r, g and b and integers in the range 0 to 255.

The as_rgb_bytes method returns the rgb values of the colour a tuple of 3 integer values. The three values represent r, g and b as integers in the range 0 to 255.

The as_rgba_bytes method returns the rgba values of the colour a tuple of 4 integer values. The three values represent r, g, b and a as integers in the range 0 to 255.

Indexing

A Color object can be indexed similar to a tuple (r, g, b, a). For example:

color = Color(0.1, 0.2, 0.3)   # rgb colour
print(color[1])                # 0.2, the g value

The Color object always behaves as a 4-tuple of RGBA values, no matter how it was created.

Setting a colour channel

You can create a new colour with a different red value like this:

color1 = Color(0.1, 0.2, 0.3)   # rgb colour
color2 = color1.with_r(0.8)     # color2 is rgba(0.8, 0.2, 0.3)

color2 is the same as color1 but with a new red value.

You can use with_g(), with_b(), with_a(), with_h(), with_s(), with_l(), to set the other channels.

For hue, this works by first converting the rgb to HSL values, then updating the hue value, then converting back to rgb. If you alter the hue, you will usually find that the r, g and b values all change. Similar for saturation and lightness.

Multiplying a colour channel

You can create a new colour with the red value multiplied by a factor, like this:

color1 = Color(0.5, 0.2, 0.3)          # rgb colour
color2 = color1.with_r_factor(1.2)     # color2 is rgba(0.6, 0.2, 0.3)

color2 is the same as color1 but with its red value multiplied by 1.2. You can think of it as making the colour 20% more red. The multiplier can also be less than 1, for example a factor of 0.7 would make the colour 30% less red.

You can use with_g_factor(), with_b_factor(), with_a_factor(), with_h_factor(), with_s_factor(), with_l_factor(), to set the other channels.

lerp

The lerp method creates a new colour by linear interpolation between two existing colours.

lerp(other, factor)
Parameter Type Description
other Color The second colour
factor float The interpolation factor

Here is an example:

color1 = Color(0.4, 0.8, 0)            # rgb colour1
color2 = Color(0, 0.4, 0.8)            # rgb colour2
color3 = color1.lerp(color2, 0.25)     # color3 is rgba(0.3, 0.7, 0.2, 1.0)

A good way to visualise this is to image a gradient that gradually changes colour from color1 to color2. With a lerp factor of 0.25, it means we have moved a quarter of the way between color1 to color2. Our new colour is 75% color1 mixed with 25% color2.

make_colormap

A color map is a list that maps integers 0 to n-1 onto set of different colours. It can be used to colorise an image that contains greyscale values.

The make_colormap function creates a colormap of a specified size, containing one or more sections of varying colour.

make_colormap(length, colors, bands)
Parameter Type Description
length int The required length of the colour map
colors a list of Colors Colours to use in the map
bands a list of numbers Relative size of each band

The colors list must contain two or more Color objects.

Here are some examples:

map = make_colormap(100,
                    [Color(`black`), Color('white')],
                    [1])

Creates a list containing 100 colours that vary smoothly from black to white. So for example, map[20] would be 20% grey. The bands array has one element, the exact value doesn't matter but it must be > 0.

map = make_colormap(256,
                    [Color(`red`), Color('yellow'), Color('black')],
                    [1, 1])

Creates a list containing 256 colours that vary smoothly from red to yellow and then to black. Since the band value is [1, 1], the two bands are equal size - the first 128 elements of the map vary smoothly from red to yellow, the next 128 elements vary smoothly from yellow to black. Note that only the relative size of each band matters. A band value of [10, 10] would give an identical result.

map = make_colormap(256,
                    [Color(`red`), Color('yellow'), Color('black')],
                    [3, 1])

Again, creates a list containing 256 colours that vary smoothly from red to yellow and then to black. This time the band value is [3, 1], the first band is three times bigger than the second bad - the first 192 elements of the map vary smoothly from red to yellow, the next 64 elements vary smoothly from yellow to black.

map = make_colormap(256,
                    [Color(`red`), Color('yellow'), Color('blue'), Color('green')],
                    [1, 0, 1])

This time the map has 4 colours, so you might expect there to be 3 bands. But notice that the band values are [1, 0, 1], so teh central band has zero length.

This means that the first 128 elements of the map vary smoothly from red to yellow, then there is a step change in colour to blue. The next 128 elements vary smoothly from blue to green.

If you found this article useful, you might be interested in the book Computer Graphics in Python or other books by the same author.

Prev

Popular tags

2d arrays abstract data type alignment and animation arc array arrays bezier curve built-in function callable object circle classes close closure cmyk colour comparison operator comprehension context context manager conversion creational pattern data types design pattern device space dictionary drawing duck typing efficiency else encryption enumerate fill filter font font style for loop function function composition function plot functools game development generativepy tutorial generator geometry gif gradient greyscale higher order function hsl html image image processing imagesurface immutable object index inner function input installing iter iterable iterator itertools l system lambda function len line linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map monad mutability named parameter numeric python numpy object open operator optional parameter or partial application path polygon positional parameter print pure function pycairo radial gradient range recipes rectangle recursion reduce rgb rotation scaling sector segment sequence singleton slice slicing sound spirograph sprite square str stream string stroke subpath symmetric encryption template text text metrics tinkerbell fractal transform translation transparency tuple turtle unpacking user space vectorisation webserver website while loop zip