ggplot colours in Python

Tuesday 11 January 2022

ggplot colours in Python

In my post about multiple poses in NGLView I mention using ggplot colours in Python, here I revisit it in a bit more detail. Warning: Contains colour theory which may befuddle some viewers.

Computer screens generally use 3 colour channels each encoded by 8 bits, resulting in 24bit colours, called "True color"*. As a result there are 256 shades of grey, which is why colour theory is a lot more saucier than those books.

*) In images you have an alpha channel which is the opacity, and in older systems you have different colour schemes, such as 8bit (256) colours in an Atari. CYMK is a colourspace similar to RGB, but to do with subtractive colours —mixing paints and mixing coloured lights has different effects (black and white) respectively. But these are beyond the point here.

Humans seen in three primary colours (red, green, blue), so the most common colorspace, i.e. way to represent colours is with a system of three integers for these. A simple way to write these 24bits is as a 6 letters hexadecimal, where each 2 digits represent one of the channels. The hexadecimal 0xff is 255 in base 10, for example. In the web, these hexadecimals are written prefixed with a hash, so, for example #F8766D represents red=248, green=118, blue=109 and goes by the name of salmon. However, stuff gets complicated quickly to the point that there is even a "International Commission on Illumination" (CIE) to standardise things...

Firstly, most operations don't quite work as intended in RGB colourspace and instead one has to use a different colorspace one. A frequently used colourspace for transformations is HSV (also known as HSL), where the colours are encoded as hue (the rainbow position, see figure), saturation and value/luminance. Interestingly, Wikipedia has a lovely table naming the colours in the hue wheel in 15º increments, which is way nicer that the silly seven kindergarten names of the colours of the rainbow. Complementary colours, discrete colours and the lot are basically operations in a colourspace with hue.

Helmholtz–Kohlrausch effect
Top row colours with equal luminance
Bottom row, the same but desaturated

Unfortunately, humans do not see colours across the hue wheel with equal strength —cf. figure. Therefore extra corrections are required to have a colour space that does not give dull colours. As a result there are lots of other colour spaces. The R ggplots colours are rotations in HCL colourspace, where the Ch stands for chroma, which a projection to account for this. Salmon in this scheme is hue=15º, 100% chroma and 65% luminance.

Now, for python, the standard library module colorsys is handy for conversions between RGB and HSL, but does not do HCL colourspace. I had no success with the module "colorio", but I did with colorspace, which is not pip released (due to package name conflict), so needs installing via github:


pip install git+https://github.com/retostauffer/python-colorspace

With this simply doing the following will give an R-like colour pallette for salmon:

n = 3

import numpy as np
from colorspace.colorlib import HCL, hexcols

hues : np.ndarray = np.linspace(0,360, n+1)+15
hues[hues >= 360] -= 360

colors = HCL(H = hues[:-1], C = [100]*n, L = [65]*n)
colors.to('hex')
colors.colors()
The colours as a result are the following based on the number requested:
  1. #F8766D
  2. #F8766D #00BFC4
  3. #F8766D #00BA38 #619CFF
  4. #F8766D #7CAE00 #00BFC4 #C77CFF
  5. #F8766D #A3A500 #00BF7D #00B0F6 #E76BF3
  6. #F8766D #B79F00 #00BA38 #00BFC4 #619CFF #F564E3
  7. #F8766D #C49A00 #53B400 #00C094 #00B6EB #A58AFF #FB61D7
  8. #F8766D #CD9600 #7CAE00 #00BE67 #00BFC4 #00A9FF #C77CFF #FF61CC
  9. #F8766D #D39200 #93AA00 #00BA38 #00C19F #00B9E3 #619CFF #DB72FB #FF61C3
  10. #F8766D #D89000 #A3A500 #39B600 #00BF7D #00BFC4 #00B0F6 #9590FF #E76BF3 #FF62BC
  11. #F8766D #DB8E00 #AEA200 #64B200 #00BD5C #00C1A7 #00BADE #00A6FF #B385FF #EF67EB #FF63B6
  12. #F8766D #DE8C00 #B79F00 #7CAE00 #00BA38 #00C08B #00BFC4 #00B4F0 #619CFF #C77CFF #F564E3 #FF64B0
  13. #F8766D #E18A00 #BE9C00 #8CAB00 #24B700 #00BE70 #00C1AB #00BBDA #00ACFC #8B93FF #D575FE #F962DD #FF65AC
  14. #F8766D #E38900 #C49A00 #99A800 #53B400 #00BC56 #00C094 #00BFC4 #00B6EB #06A4FF #A58AFF #DF70F8 #FB61D7 #FF66A8
  15. #F8766D #E58700 #C99800 #A3A500 #6BB100 #00BA38 #00BF7D #00C0AF #00BCD8 #00B0F6 #619CFF #B983FF #E76BF3 #FD61D1 #FF67A4
  16. #F8766D #E68613 #CD9600 #ABA300 #7CAE00 #0CB702 #00BE67 #00C19A #00BFC4 #00B8E7 #00A9FF #8494FF #C77CFF #ED68ED #FF61CC #FF68A1
  17. #F8766D #E7851E #D09400 #B2A100 #89AC00 #45B500 #00BC51 #00C087 #00C0B2 #00BCD6 #00B3F2 #29A3FF #9C8DFF #D277FF #F166E8 #FF61C7 #FF689E
  18. #F8766D #E88526 #D39200 #B79F00 #93AA00 #5EB300 #00BA38 #00BF74 #00C19F #00BFC4 #00B9E3 #00ADFA #619CFF #AE87FF #DB72FB #F564E3 #FF61C3 #FF699C
  19. #F8766D #E9842C #D69100 #BC9D00 #9CA700 #6FB000 #00B813 #00BD61 #00C08E #00C0B4 #00BDD4 #00B5EE #00A7FF #7F96FF #BC81FF #E26EF7 #F863DF #FF62BF #FF6A9A
  20. #F8766D #EA8331 #D89000 #C09B00 #A3A500 #7CAE00 #39B600 #00BB4E #00BF7D #00C1A3 #00BFC4 #00BAE0 #00B0F6 #35A2FF #9590FF #C77CFF #E76BF3 #FA62DB #FF62BC #FF6A98

No comments:

Post a Comment