Hacker News new | past | comments | ask | show | jobs | submit login
How to Choose Colours Procedurally (devmag.org.za)
294 points by stesch on Sept 1, 2013 | hide | past | favorite | 30 comments



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

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

And here:

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

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.


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


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.


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]


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.


Brewer palettes (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.


I like the "HSP" color model a little bit better than HSV: http://alienryderflex.com/hsp.html


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.


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


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

http://boronine.com/husl/


Nice project. Do you know about HCL? http://hclcolor.com/.

There is also uniform perceptual LAB: 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.


Thanks! I could find little information on HCL, but based on this blog post [0] it seems that it is a cylindrical version of CIE LUV. This is the color space that HUSL is based on. What HUSL does is it replaces the chroma component with a saturation component that is defined as a percentage ranging from 0 to the maximum chroma for the given hue and lightness. To put it in another way, it stretches the chroma component to make it fit into a nice rectangle. This makes all components bounded and lets us pick color without stepping outside of the gamut.

UPLab looks cool, thanks for sharing.

[0] http://cscheid.net/blog/hcl_color_space_blues


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


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

Explain your "slightly rotated" comment?


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.


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)


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.


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


Long ago I did some UI design for the military, the only job I've ever done where I had to account for colorblindness. The main thing was just never to use color alone to indicate anything. It's OK to have color enhance the distinction between elements, just not to be the only distinction. What worked best was just to design the UI in monochrome and then add color to make things pop. I've found it to be a great principle to carry forward since it improves usability for those with or without full color vision, in all kinds of lighting scenarios.

(I realize this doesn't really answer the question, which is an interesting one. Just suggesting it may be solving the wrong problem.)


Nekorosu's reply is about how to simulate colorblindness (so you can test how accessible a design is), for which there are plenty of great tools. Recently, I've liked http://colororacle.org/

Yet that's not really an answer for how to optimize for color blindness. That I don't know and would be interested in an answer.


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.


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


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.


Oh, of course.

I didn't understand that. Thanks.


Try http://colorbrewer2.org/ - it has a setting for colorblind safe...


There is an answered stackoverflow question with some info on math and a working demo http://stackoverflow.com/questions/12168795/algorithm-to-sim...


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


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.


What language is your color library for?


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: