somewhat OT: function to produce n as distinct colors as possible

E

Edvard Majakari

Ok, not strictly Python related: I wonder if any of you graphical Python
folks have run accross some handy resource for the given topic.

The problem is that of producing histograms, where n distinct items can be
plotted simultaneously. However, when n goes over 6 it is not very easy to
make up colors that are easily distinguishable from each other. So, now
I'm thinking of two alternatives:

1. Create an algorithm distinct_colors(n, bg), which produces n-1 as
distinct colors as possible (where bg is one of the colors) and returns
those colors in RGB color model as tuple of decimals (r, g, b).

Eg. distinct_colors(4, (255, 255, 255)) would return

((255, 0, 0), (0, 255, 0), (0, 0, 255))

assuming that "pure-rgb" red, green and blue are visually the three as
distinct colors as possible from white.

2. Find a color palette containing say, 8 or 10 colors as visually far apart
from each other as possible

The first one would be more nice, but I doubt I can produce it myself
without any knowledge of psychology and physics related to phenomenon.

Using google it seemed like there's demand for the algorithm. I'll
probably publish the code in Python Cookbook or similar if I end up with
something nice.

--
# Edvard Majakari Software Engineer
# PGP PUBLIC KEY available Soli Deo Gloria!
One day, when he was naughty, Mr Bunnsy looked over the hedge into Farmer
Fred's field and it was full of fresh green lettuces. Mr Bunnsy, however, was
not full of lettuces. This did not seem fair. --Mr Bunnsy has an adventure
 
M

Mitja

Edvard Majakari said:
Ok, not strictly Python related: I wonder if any of you graphical
Python folks have run accross some handy resource for the given topic.

The problem is that of producing histograms, where n distinct items
can be plotted simultaneously. However, when n goes over 6 it is not
very easy to make up colors that are easily distinguishable from each
other. So, now
I'm thinking of two alternatives:

1. Create an algorithm distinct_colors(n, bg), which produces n-1 as
distinct colors as possible (where bg is one of the colors) and
returns those colors in RGB color model as tuple of decimals (r,
g, b).

Eg. distinct_colors(4, (255, 255, 255)) would return

((255, 0, 0), (0, 255, 0), (0, 0, 255))

assuming that "pure-rgb" red, green and blue are visually the three
as distinct colors as possible from white.

I'd start with the HSI (aka HSL) model and distribute hues evenly. Don't
know if that's the best solution what with all the stuff going on in our
brain mangling our perception, but it should be close.
Have a look at google for the HSI model and its conversion to RGB.
 
C

Christos TZOTZIOY Georgiou

Ok, not strictly Python related: I wonder if any of you graphical Python
folks have run accross some handy resource for the given topic.
The problem is that of producing histograms, where n distinct items can be
plotted simultaneously. However, when n goes over 6 it is not very easy to
make up colors that are easily distinguishable from each other. So, now
I'm thinking of two alternatives:
1. Create an algorithm distinct_colors(n, bg), which produces n-1 as
distinct colors as possible (where bg is one of the colors) and returns
those colors in RGB color model as tuple of decimals (r, g, b).

Eg. distinct_colors(4, (255, 255, 255)) would return

((255, 0, 0), (0, 255, 0), (0, 0, 255))

assuming that "pure-rgb" red, green and blue are visually the three as
distinct colors as possible from white.

[snip]

I think the algorithm would be easier in the (hue, saturation,
brightness) domain instead of the (red, green, blue) one. Try selecting
colours evenly spaced in the hue axis.

The colorsys module shall be your good friend for conversions to and fro
:)
 
E

Edvard Majakari

Mitja said:
I'd start with the HSI (aka HSL) model and distribute hues evenly. Don't
know if that's the best solution what with all the stuff going on in our
brain mangling our perception, but it should be close.
Have a look at google for the HSI model and its conversion to RGB.

Thanks for the tip. After a little fiddling I ended up with a very simple
algorithm which uses hsv color model (hue, saturation and value). The
python module colorsys uses floats in the range [0..1.0], so I started
with all values at 1, and decrement h and v by step (1.0 / n, where n =
number of distinct colors) every turn. Note that I don't touch value
component.

I get quite nice values when n < 10. After that it gets worse, but at n =
20 colors it is still possible, if not easy, to separate a color from
another.

But the algorithm could be better for sure. For one thing, I don't see
dark brown anywhere, and it would be easy to separate from other colors
(even when n = 20).

# simple test for producing n different colors. Prints out a very simple
# (and probably not valid) web page with differently colored table cells.

import colorsys
import sys

def float2dec(color):
return int(color*255)

def dec2hex_str(rgb):
return "%06x" % (rgb[0]*256**2+rgb[1]*256+rgb[2])

def distinct_colors(n):
colors = []
step = 1.0/n
h, s, v = (1, 1, 1)

for i in range(n):
r, g, b = map(float2dec, colorsys.hsv_to_rgb(h, s, v))
colors.append((r, g, b))

h, s, v = (h-step, s-step, v)

if h < 0:
h = 0
if s < 0:
s = 0
if v < 0:
v = 0

return map(dec2hex_str, colors)

# main

color_count = int(sys.argv[1])

print """\
<html>
<title>%s</title>
<body>
<table>
\t<tr>\
""" % "Printing %d distinct colors" % color_count
i = 0
for color in distinct_colors(color_count):
i += 1
if i % 8 == 0:
print '\t\t<td bgcolor="#%s">test area</td>\n\t</tr>\n\t<tr>' % color
else:
print '\t\t<td bgcolor="#%s">test area</td>' % color
print """\
\t</tr>
</table>
</body>
</html>\
"""
--
# Edvard Majakari Software Engineer
# PGP PUBLIC KEY available Soli Deo Gloria!

"Debugging is twice as hard as writing the code in the firstplace. Therefore, if
you write the code as cleverly as possible, you are, by definition, not smart
enough to debug it." -- Brian W. Kernighan
 
M

Mitja

Edvard Majakari said:
Mitja said:
I'd start with the HSI (aka HSL) model and distribute hues evenly.
Don't know if that's the best solution what with all the stuff going
on in our brain mangling our perception, but it should be close.
Have a look at google for the HSI model and its conversion to RGB.

Thanks for the tip. After a little fiddling I ended up with a very
simple algorithm which uses hsv color model (hue, saturation and
value). The
python module colorsys uses floats in the range [0..1.0], so I started
with all values at 1, and decrement h and v by step (1.0 / n, where n
= number of distinct colors) every turn. Note that I don't touch value
component.

That is "descrement h and s", of course.
I get quite nice values when n < 10. After that it gets worse, but at
n = 20 colors it is still possible, if not easy, to separate a color
from another.

But the algorithm could be better for sure. For one thing, I don't see
dark brown anywhere, and it would be easy to separate from other
colors (even when n = 20).

That's bluffing on my side again, but I'd leave saturation as it is, and
then make colors by equally distributing hues (as you already did), except
that with say 12 colors I'd make 3 sets, each of them with different VALUE,
and each of them with equally distributed hues.

Guess you found a description before, but the HSV model is very intuitive
and made with humans in mind. Hue is the actual color - red, green, blue,
violet, ... Intensity varies from 1 (very intensive, vivid color) to 0 (no
color at all, just grey). Value is brightness.

So with what I described above, you'd get say blue, darker blue, very dark
blue, red, darker red, etc. To get dark brown, you'd have to play around
with saturation a bit.
# simple test for producing n different colors. Prints out a very
simple # (and probably not valid) web page with differently colored
table cells.

import colorsys
import sys

def float2dec(color):
return int(color*255)

def dec2hex_str(rgb):
return "%06x" % (rgb[0]*256**2+rgb[1]*256+rgb[2])

def distinct_colors(n):
colors = []
step = 1.0/n
h, s, v = (1, 1, 1)

for i in range(n):
r, g, b = map(float2dec, colorsys.hsv_to_rgb(h, s, v))
colors.append((r, g, b))

h, s, v = (h-step, s-step, v)

if h < 0:
h = 0
if s < 0:
s = 0
if v < 0:
v = 0

return map(dec2hex_str, colors)

# main

color_count = int(sys.argv[1])

print """\
<html>
<title>%s</title>
<body>
<table>
\t<tr>\
""" % "Printing %d distinct colors" % color_count
i = 0
for color in distinct_colors(color_count):
i += 1
if i % 8 == 0:
print '\t\t<td bgcolor="#%s">test area</td>\n\t</tr>\n\t<tr>'
% color else:
print '\t\t<td bgcolor="#%s">test area</td>' % color
print """\
\t</tr>
</table>
</body>
</html>\
"""
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top