This is a snapshot of some ongoing colour R&D, mostly for the chart-svg library. The development repo can be found at GitHub - tonyday567/color-adjust. The readme.org there is runnable and contains the code used to create the examples below.
:r
:set prompt "> "
:set -XOverloadedStrings
:set -XOverloadedLabels
:set -Wno-name-shadowing
:set -XTupleSections
:set -Wno-type-defaults
import Data.Word
import qualified Data.Text as Text
import Data.Bifunctor
import Chart
import Data.Colour.Adjust
import Optics.Core
cs = palette1 <$> [0..3] :: [Colour]
lchs = review lcha2colour' <$> cs :: [LCHA]
A new color space model, oklab, has been introduced to the CSS standards.
The basic idea is that this color space is ok with respect to human perception of graduated changes in colour. The LCH version of oklab consists of three element:
- lightness, from 0 (black) to 1 (white)
- chromacity, from 0 (grey) to a point at which the colour goes out of RGB gamut (it varies but typically 0.25 to 0.33)
- hue, from 0 to 360, representing colour as a rainbow circle in degrees.
Adding in an alpha channel, which is a graduated model of colour opacity, we create a 4 element type, LCHA:
Channel | Range | Description |
---|---|---|
l | [0, 1] | Lightness |
c | [0, 0.322]≈ | Chroma |
h | [0, 360) | Hue |
a | [0, 1] | Alpha |
We take some colours from the chart-svg palette and convert them to LCHA:
[Colour 0.02 0.73 0.80 1.00,Colour 0.02 0.29 0.48 1.00,Colour 0.66 0.07 0.55 1.00,Colour 0.96 0.60 0.92 1.00]
LCHA 0.720 0.123 207 1.000 LCHA 0.400 0.100 246 1.000 LCHA 0.500 0.210 338 1.000 LCHA 0.800 0.150 331 1.000
The swatches below decompose these colours into LCH components, by setting each component to constant values:
The chart below plots these 4 colours versus a 2-D slice of the oklab space (a 3-D one) with constant lightness.
Note that the light blue color (LCHA 0.720 0.123 207 1.000) is well outside the gamut for the wheel lightness chosen. This is a common occurence and the shape of the chroma range varies considerably with both hue and lightness.
view lcha2colour' (LCHA 0.6 0.123 207 1.000)
Colour -0.50 0.58 0.65 1.00
Clipping this result to 0 results in significant hue shift.
Compare the shape of gamuts for lightnesses of 0.3 and 0.7
Mixing of colours resulting in the interpolated colour being out of gamut is the major drawwback of the oklch space. Otherwise, the mixing of colours is quite pleasing from this human’s perspective:
c = Colour 0.72 0.34 0.04 1
ok = view (re lcha2colour') c
print c
Colour 0.72 0.34 0.04 1.00
fade to white (LCH 0 0 50 1)
fade to grey (LCH 0.566 0 50 1)
fade to hue=0 (LCH 0.566 0.146 0 1)
lightness 0 to 1
The red drift is due to being out of gamut.
chroma 0 to 0.25
hue 0 to 360
Whatever the relative success of oklab in providing pleasing human perceptions of consistent colour change, inclusion in the CSS standards are likely to provide a leg up to its usage going forward.
Full palette1 mapping for chart-svg.
x1 =[LCHA 0.72 0.123 207 1, LCHA 0.40 0.10 246 1, LCHA 0.50 0.21 338 1, LCHA 0.8 0.15 331 1, LCHA 0.83 0.14 69 1, LCHA 0.57 0.15 50 1, LCHA 0.38 0.085 128 1, LCHA 0.60 0.08 104 1] :: [LCHA]
cs = trimColour <$> view lcha2colour' <$> x1
csu = view lcha2colour' <$> x1
print csu
import Data.FormatN
import qualified Data.Text.IO as Text
sequence_ $ Text.putStrLn . prettyLCHA <$> x1
LCHA 0.720 0.123 207 1.000 LCHA 0.400 0.100 246 1.000 LCHA 0.500 0.210 338 1.000 LCHA 0.800 0.150 331 1.000 LCHA 0.830 0.140 69 1.000 LCHA 0.570 0.150 50 1.000 LCHA 0.380 0.085 128 1.000 LCHA 0.600 0.080 104 1.000
paletteR
provides random colours, without being too dark or light to use in a chart.
cs = (\x -> paletteR !! x) <$> ([0..7] :: [Int])
print cs
- CSS colors are defined as sRGB - Wikipedia, with D65 illuminate.
- A perceptual color space for image processing
- CSS Color Module Level 5
- CSS Color Module Level 4
- CSS Color Module Level 3
- CIELAB color space - Wikipedia
- https://observablehq.com/@fil/oklab-color-space
<style> .swatch { border-radius:20%; display: inline-block; margin:10px; width: 20px; height: 20px; overflow: hidden; font-size: 0px; } .swatch:hover { margin: 0; width: 40px; height: 40px; line-height: 40px; font-size: 6px; color: rgb(12 12 12); text-align: center; overflow: hidden; } </style>