I\'m trying to graphically display a graph of N lines and I\'m trying to find a way to dynamically assign distinct colors based on how many lines I have. The values in RGB rang
for r from 0 to 255 step (255*3/N):
for g from 0 to 255 step (255*3/N):
for b from 0 to 255 step (255*3/N):
...
My preferred method for doing this is to find n
evenly-spaced points along the colour wheel.
We represent the colour wheel as a range of values between 0 and 360. Thus, the values we will use are 360 / n * 0
, 360 / n * 1
, ..., 360 / n * (n - 1)
. In doing this, we've defined the hue of each of our colours. We can describe each of these colours as Hue-Saturation-Value (HSV) colours by setting saturation to 1 and lightness to 1.
(A higher saturation means the colour is more "rich"; a lower saturation means the colour is closer to gray. A higher lightness means the colour is "brighter"; a lower lightness means the colour is "darker".)
Now, a simple calculation gives us the RGB values of each of these colours.
http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_HSV_to_RGB
Note that the equations given can be simplified:
Note: This is intentionally a horribly inefficient implementation. The point of giving this example in Python is essentially so I can give executable pseudocode.
import math
def uniquecolors(n):
"""Compute a list of distinct colors, each of which is represented as an RGB 3-tuple."""
hues = []
# i is in the range 0, 1, ..., n - 1
for i in range(n):
hues.append(360.0 / i)
hs = []
for hue in hues:
h = math.floor(hue / 60) % 6
hs.append(h)
fs = []
for hue in hues:
f = hue / 60 - math.floor(hue / 60)
fs.append(f)
rgbcolors = []
for h, f in zip(hs, fs):
v = 1
p = 0
q = 1 - f
t = f
if h == 0:
color = v, t, p
elif h == 1:
color = q, v, p
elif h == 2:
color = p, v, t
elif h == 3:
color = p, q, v
elif h == 4:
color = t, p, v
elif h == 5:
color = v, p, q
rgbcolors.append(color)
return rgbcolors
import math
v = 1.0
s = 1.0
p = 0.0
def rgbcolor(h, f):
"""Convert a color specified by h-value and f-value to an RGB
three-tuple."""
# q = 1 - f
# t = f
if h == 0:
return v, f, p
elif h == 1:
return 1 - f, v, p
elif h == 2:
return p, v, f
elif h == 3:
return p, 1 - f, v
elif h == 4:
return f, p, v
elif h == 5:
return v, p, 1 - f
def uniquecolors(n):
"""Compute a list of distinct colors, ecah of which is
represented as an RGB three-tuple"""
hues = (360.0 / n * i for i in range(n))
hs = (math.floor(hue / 60) % 6 for hue in hues)
fs = (hue / 60 - math.floor(hue / 60) for hue in hues)
return [rgbcolor(h, f) for h, f in zip(hs, fs)]
I wrote this code once to solve exactly the problem you describe (the background was also white). It's the same idea as yours, only generalized. It should be easy to adapt from OCaml to your language.
Usage
You don't need to tell the function how many colors you will need. Call the function with 1, 2, ... to get color number 1, number 2, ... The colors from small numbers are wide apart, the latter colors of course become closer and closer to each other.
Code
lsl
is "logical shift left", lsr
"logical shift right", and !
simply means "access a reference". In OCaml RGB colors are represented in a single integer, with one byte per color.
let number_to_color n = let color = ref 0 in let number = ref n in for i = 0 to 7 do color := (!color lsl 1) + (if !number land 1 <> 0 then 1 else 0) + (if !number land 2 <> 0 then 256 else 0) + (if !number land 4 <> 0 then 65536 else 0); number := !number lsr 3 done; !color