简体   繁体   中英

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.

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)

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, eg if your application uses random numbers elsewhere, you might want to look into the caching options suggested by other answers.

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] 

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)

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 (ie, 10 or a million), the caching method might be better than the seed() method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM