Theodor
Theodor

Reputation: 5656

Color handling in Python

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.

Upvotes: 3

Views: 4015

Answers (5)

unwind
unwind

Reputation: 399743

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.

Upvotes: 2

Daren Thomas
Daren Thomas

Reputation: 70314

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] 

Upvotes: 2

Andrew Cox
Andrew Cox

Reputation: 10988

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)

Upvotes: 2

Chinmay Kanchi
Chinmay Kanchi

Reputation: 65853

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.

Upvotes: 0

Muhammad Alkarouri
Muhammad Alkarouri

Reputation: 24652

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)

Upvotes: 7

Related Questions