Source code for colorseq.distinctcolors

import random
import colorsys

from .helperfcts import (
        next_gr_value,
        set_vals,
        generate_vals
        )
"""
"""


[docs]class DistinctColors(object): r""" Class that allows to generate sequences of distinct colours. Attributes ========== n: int (default=0) number of distinct colours to generate. If not specified then :obj:`~.DistinctColors.get_colors` will return a new generator allowing to draw an undetermined number of values. h: float, tuple(float, float) (default=(0, 1)) determine the spectrum of hues used to generate colours. If a single value is provided then only this hue is used. s: float, tuple(float, float) (default=1.0) determine the spectrum of saturations used to generate colours. If a single value is provided then only this saturation is used. v: float, tuple(float, float) (default=1.0) determine the spectrum of values used to generate colours. If a single value is provided then only this colour value is used. \**kwargs optional parameter: mode: str (default='gr') Determines how to generate the colour sequence. By default, ``mode='gr'``, the golden angle is exploited to create a sequence of values in [0, 1] that is relatively evenly distributed. .. todo:: Implement a geometric approach. h_init: float (default=:ref:`~.DistinctColor.rd.random`) initial value for the hue. s_init: float (default=:ref:`~.DistinctColor.rd.random`) initial value for the saturation. v_init: float (default=:ref:`~.DistinctColor.rd.random`) initial value for the colour value. """ def __init__(self, n=0, h=(0, 1), s=1.0, v=1.0, **kwargs): mode = kwargs.get('mode', 'gr') if mode == 'gr': self.next_gen = next_gr_value else: raise AttributeError("mode='{0}' is not implemented".format(mode)) # useless as initiation will happen elsewhere # seed = kwargs.get('seed', None) # rd_state = kwargs.get('random_state', None) self.rd = random.Random() # if seed is not None: # self.rd.seed(seed) # if isinstance(rd_state, tuple): # self.rd.setstate(rd_state) # # save the initial state of the random number generator # self._rd_initial = self.rd.getstate() self.n = n self.h = h self.s = s self.v = v self.h_init_val = kwargs.get('h_init', self.rd.random()) self.s_init_val = kwargs.get('s_init', self.rd.random()) self.v_init_val = kwargs.get('v_init', self.rd.random()) if self.n: self._h_shuffler = None self._s_shuffler = None self._v_shuffler = None if kwargs.get('h_shuffle', False): self._h_shuffler = self.rd.shuffle if kwargs.get('s_shuffle', False): self._s_shuffler = self.rd.shuffle if kwargs.get('v_shuffle', False): self._v_shuffler = self.rd.shuffle self._init_vals() def _init_vals(self): if self.n: self.h_vals = set_vals( self.next_gen, self.n, self.h, self.h_init_val, self._h_shuffler ) self.s_vals = set_vals( self.next_gen, self.n, self.s, self.s_init_val, self._s_shuffler ) self.v_vals = set_vals( self.next_gen, self.n, self.v, self.v_init_val, self._v_shuffler ) else: self.h_vals = generate_vals(self.next_gen, self.h, self.h_init_val) self.s_vals = generate_vals(self.next_gen, self.s, self.s_init_val) self.v_vals = generate_vals(self.next_gen, self.v, self.v_init_val) self._new_vals = True # def get_rd_initial(self): # """ # Returns the initial state of the used random number generator. # """ # return self._rd_initial
[docs] def get_colors(self, ): """ Returns ======= RGB-colours: list, generator If :attr:`~.DistinctColors.n` is set, then a list of colors with this length is returned. If :attr:`~.DistinctColors.n` is unset, i.e. ``n=0`` then a generator is returned allowing to draw new colours continuously. """ if not self._new_vals: self._init_vals() if self.n: def _get_colors(): return [ colorsys.hsv_to_rgb(*dc) for dc in zip(self.h_vals, self.s_vals, self.v_vals) ] else: def _get_colors(): while True: yield colorsys.hsv_to_rgb( *map( next, (self.h_vals, self.s_vals, self.v_vals) ) ) self._new_vals = False return _get_colors()