generativepy.color module

By Martin McBride, 2022-06-04
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.

The color module also contains:

  • The make_colormap function that can be used to create a color map.
  • Several reusable colour schemes.

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

Also see the colour section of the tutorial.

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
light1 Color A new Color object that is lighter than the current color
light2 Color As above, even lighter
light3 Color As above, even lighter
dark1 Color A new Color object that is darker than the current color
dark2 Color As above, even darker
dark3 Color See above, even darker

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 created. 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.

The property light1 returns a new colour that is lighter than the original colour by a fixed factor. It is the equivalent of calling with_l() to increase the lightness (in the HSL model). However, light1 uses a fixed factor, so you don't need to decide how much to lighten the colour by. light2 creates an even lighter colour, and light3 even lighter still. Similarly, dark1 creates a darker version of the original colour, dark2 even darker, and dark3 even darker than that.

They are used like this:

yellow = Color(0.5, 0.5, 0) 
light_yellow = yellow.light1

Given a base colour and the lightX and darkX properties, you can easily create a palette of 7 colours that have different lightness's of the same colour.

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=None)
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, or None

The colors list must contain two or more Color objects.

The bands list, if present, must be a list of numbers, >=0. The length of thebands list must be exactly 1 less than the length if the colors list. If bands is None, all the bands will be equal length.

Here are some examples:

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

Creates a list containing 100 colours that vary smoothly from black to white. So for example, map[20] would be 20% grey.

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

Creates a list containing 256 colours that vary smoothly from red to yellow and then to black. Since no band is specified, 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.

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. Note that only the relative size of the bands matters. A band value of [6, 2] would give exactly the same result as [3, 1]. The first band will be three times larger than the second band.

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 the 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.

Colour schemes

A colour scheme is a set of named colour definitions that can be used across different projects. For example, you might be creating a set of related diagrams or animations using a consistent set of colours.

A colour scheme is simply a class that has a set of properties that return Color objects. The properties would typically be named using upper case colour names such as RED or GREEN. It allows you to easily use the same red or green every time.

This is a pattern rather than a concrete implementation. A couple of examples are included, but you can easily add your own using similar classes but including your own colour names and values.

The main intention of colour schemes is to be reusable. They are not necessarily interchangeable, because there is no requirement for different schemes to support the same set of colour names. If you wanted to create interchangeable colour schemes, you could do so, simply be designing a set of colour schemes that do share the same set of colour names.

Within a colour scheme, you can easily create lighter or darker versions of the base colours using light1, dark1, etc.

Currently, there are two colours schemes defined.

ArtisticColorScheme

This colour scheme provides 7 basic colours: RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, ORANGE.

It has 3 lighter colours: STEEL, CREAM, LIME.

It also provides BLACK, GREY, WHITE.

DarkColorScheme

This colour scheme is designed to be used as a dral theme. It provides a dark grey BACKGROUND colour that can be used as the background.

It provides 7 basic colours: RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, ORANGE.

It also provides BLACK, GREY, WHITE.

It also has a colour BACKGROUND that is suitable for use as a background for the dark colour scheme. This is a dark grey colour.

See also

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

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest