
How to Choose Colours Procedurally - stesch
http://devmag.org.za/2012/07/29/how-to-choose-colours-procedurally-algorithms/
======
cortesi
I'm somewhat late to the party, but I spent some time playing with procedural
colour picking using space-filling curves (the Hilbert curve in particular). I
describe the basic technique here:

[http://corte.si/posts/code/hilbert/portrait/index.html](http://corte.si/posts/code/hilbert/portrait/index.html)

And you can see what this looks like when used to visualize sorting algorithms
at large scale here:

[http://corte.si/posts/code/sortvis-
fruitsalad/index.html](http://corte.si/posts/code/sortvis-
fruitsalad/index.html)

And here:

[http://sortvis.org/](http://sortvis.org/)

I've also published an Open Source project that might be useful to anyone who
wants to play with these ideas:

[https://github.com/cortesi/scurve](https://github.com/cortesi/scurve)

There are some limitations to the process as described - most obviously the
fact that I'm using the RGB color space which is not the best match for human
color perception. RGB is convenient because it is a regular cube and therefore
easy to map onto the Hilbert curve, but with a little work the process could
be generalized.

~~~
justinpombrio
Thank you for the explanations! I learned about Hilbert curves in part from
your website before constructing a "color clock" some time ago:

[http://justinpombrio.net/show/color-
clock.html](http://justinpombrio.net/show/color-clock.html)

------
rcfox
One thing the article doesn't mention: getting a set of maximally visually
distinct colours. The best algorithm I'm familiar with for this is to
iteratively choose colours as far away as possible from each other in Lab
space (while still being able to map into RGB). You can also make sure that
the colours stand out against your background by pre-seeding the space with
your background colour.

However, it's not a fast algorithm. The more colours you choose, the slower
each iteration gets, since you have to calculate the distances from a growing
set of colours. Also, after ~10, the distinctness seems to drop off pretty
quickly. Lastly, assuming you're seeding with the same colours, you'll always
get the same result, so it's really best to do the calculations once and then
cache them.

~~~
jacobolus
That's not the worst method you could choose, but just be warned:

CIELAB space was designed with the goal that any pair of colors separated by
about 1 unit (i.e. ΔE = 1) would have a similar degree of apparent difference.
However, apparent color differences are a highly non-linear property, and so
by the point ΔE gets past 5 or 10, a specific color difference in one
direction or one part of the color space will be substantially different than
a same-distance color difference in another part of the space.

Often, the reason you want to carefully pick a color scheme is to make sure
that two areas of a graphic are easily visually distinguishable along an edge.
Because human vision mainly uses a monochromatic color signal for
distinguishing shape, texture, and the finest details, the most important
difference to make between a pair or set of colors is to separate them in the
lightness (in CIELAB, that's L) dimension. If you have sufficient lightness
contrast, then any particular choices of a and b (or hue and chroma) will work
fine. If you don’t have sufficient lightness contrast, changing the other
color components won’t help much: even if you maximally separate them in the
color space, they’ll just appear to mush together in a clashing way along
edges.

[edit: removed asterisks from L*, etc. because HN thinks they should be for
italicizing]

~~~
taliesinb
To supplement your point about L being the most important ordinate for
distinguishing bordering colors: that is certainly true, but there are three
other properties one wants for data visualization:

1\. Once you've seen a colored element in the graphic, you want to quickly
match it to its corresponding element in a legend (or vice versa). Having
distinct hue and chroma is more important for this, because lightness is so
vulnerable to your brain's tendency to 'correct' it based on contextual cues.

2\. Hues should be aesthetically pleasing.

3\. Lightness tends to impart connotations to an visualization: class X is
more important than other classes if it is substantially darker or lighter.
Same goes for chroma. So one wants to bound lightness and chroma to within a
specific range when using them for class labeling.

Another deep complication is color impossibility, which is another way of
saying that for any reasonably perceptually uniform color space like CIELAB,
there is no straight-forward parametrization of the space that is both linear
and avoids impossible colors.

My gut instinct is that space-filling curves could play a greater role in
parameterizing the valid portions of such color spaces. Desiderata 3 is
suggestive: we want some parameter that 'wiggles' within the allowed range of
lightness and chroma to achieve both good distinction between nearby
parameterized colors, and good global uniformity of color and chroma.

This wiggling could also 'absorb' the 'nooks and crannies' that color
impossibility produces.

Still a research project, though.

------
takeoutweight
Brewer palettes
([http://mkweb.bcgsc.ca/brewer/](http://mkweb.bcgsc.ca/brewer/)) are hand-
picked colour ranges that were originally meant for cartography but are useful
for general data viz, where it is important to maintain perceptual regularity
while displaying quantitative data.

There are Brewer palettes geared for sequential data, where you further need
to express proportionality along a scale; and "diverging" data that has a
natural zero point with two extremes where you need to present a spectrum. In
all these cases it's important that one category doesn't appear "heavier" than
another, and that subjective notions like "about twice as intense" reflect the
underlying data.

------
AnthonBerg
I like the "HSP" color model a little bit better than HSV:
[http://alienryderflex.com/hsp.html](http://alienryderflex.com/hsp.html)

------
afhof
The golden ratio method looks neat; but I think it can be forked into two
algorithms. In the site version, they know ahead of time how many colors are
needed. If you need n colors, you could use the multiplicative inverse mod n
to pick angles along the color wheel. This results in every color being unique
and as far away as the other colors as possible.

In the case you don't know how many colors you will need at the time of first
picking you can use the golden ratio method to pick colors.

~~~
taliesinb
We use this trick in Mathematica, for what it's worth

------
boronine
Plug: I made a color space derived from CIE LUV to help generate colors
procedurally.

[http://boronine.com/husl/](http://boronine.com/husl/)

~~~
taliesinb
Nice project. Do you know about HCL?
[http://hclcolor.com/](http://hclcolor.com/).

There is also uniform perceptual LAB:
[http://www.brucelindbloom.com/index.html?UPLab.html](http://www.brucelindbloom.com/index.html?UPLab.html)
which is a slight tweak to LAB to reduce the 'blue -> purple' effect that
happens when you tweak chroma.

~~~
jacobolus
UPLab is not a “slight tweak” of CIELAB. It’s a lookup table for going back
and forth between CIELAB and a slightly rotated version of Munsell space,
[https://en.wikipedia.org/wiki/Munsell_color_system](https://en.wikipedia.org/wiki/Munsell_color_system)

~~~
taliesinb
You can look at it that way. You can also see it as a modification of
cylindrical LAB.

Explain your "slightly rotated" comment?

~~~
jacobolus
From Lindbloom’s site: “The mapping was done such that Munsell hue 2.5RP has a
UP Lab hue angle of zero degrees. This particular rotation was chosen to allow
greater chroma encoding of blue colors in the lower right quadrant of the a/b
plane.”

Also, to be completely precise, it should be noted that the lightness
dimension of UPLab was left the same as CIELAB’s lightness, rather than using
Munsell value. Only a and b were adjusted to reflect Munsell hue/chroma.

------
tripzilch
I read this article a while ago. I was very excited to _finally_ see a use for
the Golden Ratio in graphics design that actually makes any sense at all :)

(there is no proof that humans perceive phi as a more pleasing proportional
ratio than others, and it's not really that ubiquitous in Nature either)

~~~
sp332
I once used a Golden Ratio to space out a bunch of overlapping rectangles.
Each one was put 1/phi of the total space away from the last. That gave me the
least probability of rectangles overlapping.

------
officialjunk
how would one optimize this for color blindness? Say, for red/green color
blind individuals as an example...

~~~
Jongseong
One thing I noticed as someone with red-green colour blindness is that while
the article claims that "darker magentas are more distinguishable than lighter
ones", I saw lighter magentas as being more distinguishable than darker ones.
So the perceptual distances between colours are probably different for us.

If high contrast between colours is desired, you could take some further
precautions in some of the suggested algorithms, e.g. if you're choosing
certain hues as a basis of your palette, then making sure that none of the
pairs are problematic. If your algorithm checks the distance between colours
to generate high-contrast pairs, then you could add in a check for problematic
pairs as part of that step.

~~~
marcosdumay
> I saw lighter magentas as being more distinguishable than darker ones.

How do you know that? How do you know you are looking to equivalent
distributions of lighter and darker magentas?

I have some uncommon kind of color blindness, I have problems with blue and
green. I don't even know what colors I can't see, I'd love to know the
procedures for that.

~~~
Jongseong
I was looking at the sample image provided on the linked article for hue
differentiation where for each of the three rows, the strips of colour differ
by 5%. The three rows differ by brightness only. The article used this image
to illustrate that "lighter blues is more distinguishable than darker blues,
while darker magentas are more distinguishable than lighter ones", but to me
both lighter blues and lighter magentas were more distinguishable than the
darker counterparts.

~~~
marcosdumay
Oh, of course.

I didn't understand that. Thanks.

------
rbhatia
[http://tools.medialab.sciences-
po.fr/iwanthue/index.php](http://tools.medialab.sciences-
po.fr/iwanthue/index.php) is another great resource for picking optimally
distinct colors.

------
jere
Great article. I'm working on a procedural (but stable) color library right
now and I'm hoping it's useful for somebody. Color perception is a lot more
complicated than I could have ever imagined.

~~~
sleazebreeze
What language is your color library for?

~~~
jere
JavaScript. I was thinking it would be neat to have some sort of library that
hashes (for lack of a better term) keys into colors. That way you don't have
to pick the colors or store them, but they are stable. For a given key, you'll
always get back the same color.

Generating colors is not hard; the hard part, as evidenced by this article, is
getting them to look decent and getting them to appear distinct.

