tags:

views:

85

answers:

5

For my clustering gui, I am currently using random colors for the clusters, since I won't know before hand how many clusters I will end up with.

In python, this looks like:

import random
def randomColor():
    return (random.random(),random.random(),random.random())

However, when I update things, the colors change. So what I would favor is to have a function which has an input argument i such as

def nonrandomColor(i):
   ...
   return color

would always return the same color for the same i, while keeping the ability to generate arbitrarily many colors.

Answer does not have to be formulated in python, it's more the general layout I'm interested in.

+1  A: 

You want to store the colors in a dictionary or a list:

colors = {} # int -> color
def nonrandomColor(i):
   if i not in colors:
      colors[i] = randomColor()
   return colors[i] 
Daren Thomas
+5  A: 

One way is to use caching. Use a defaultdict:

>>> import random
>>> def randomColor():
...    return (random.random(),random.random(),random.random())
... 
>>> from collections import defaultdict
>>> colors = defaultdict(randomColor)
>>> colors[3]
(0.10726172906719755, 0.97327604757295705, 0.58935794305308264)
>>> colors[1]
(0.48991106537516382, 0.77039712435566876, 0.73707003166893892)
>>> colors[3]
(0.10726172906719755, 0.97327604757295705, 0.58935794305308264)
Muhammad Alkarouri
Setting the first few entries of the dict to easily distinguishable colors (red, yellow, green, blue) up front will decrease your chance of producing a graph with lines in blue, blue, blue, and blue.
Jason Orendorff
@Jason: your idea is useful. The risk of the colors being various shades of blue is not high, but having the first few colors static also makes the graph more understandable.
Muhammad Alkarouri
+3  A: 

Just set the seed of the random generator to the index, this might be cheaper than storing the colors.

random.seed(i)

Note that this will make random numbers way less random than before. If that is a problem, e.g. if your application uses random numbers elsewhere, you might want to look into the caching options suggested by other answers.

unwind
This did the trick. Nice with a one line extention.
Theodor
-1 because frequently setting your random seed causes your random number generator to be highly non-random. This would be a bad idea if your program also uses random numbers for anything else.
Jason Orendorff
@Jason: agreed, I'll add some words to point that out.
unwind
One way to avoid messing with your random number generator is to use a specialised one for the colors. `color_rnd = random.Random(); color_rnd.seed(i)`
Muhammad Alkarouri
A: 

You can use i to seed the random number generator. So, as long as the seed remains the same, you get the same value.

>>> import random
>>> random.seed(12)
>>> random.randint(0,255), random.randint(0,255), random.randint(0,255)
(121, 168, 170)
>>> random.seed(12)
>>> random.randint(0,255), random.randint(0,255), random.randint(0,255)
(121, 168, 170)
>>> random.seed(10)
>>> random.randint(0,255), random.randint(0,255), random.randint(0,255)
(146, 109, 147)
>>> random.seed(10)
>>> random.randint(0,255), random.randint(0,255), random.randint(0,255)
(146, 109, 147)

Depending on the number of colours you're likely to generate (i.e., 10 or a million), the caching method might be better than the seed() method.

Chinmay Kanchi
+1  A: 

If you want repeatable non colliding colors then you could use something like the function below. It sections the number into 1, 10, 100 and then uses them as the RGB parts of the color.

def color(i):
  r = i % 10
  g = (i//10) % 10
  b = (i//100) % 10
  return(r*25, g*25, b*25)

For example:

color(1) == (25,0,0)
color(10) == (0,25,0)
color(999) = (225,225,255)
Andrew Cox