22# This software may be modified and distributed under the terms of the
33# Released under the terms of the BSD 3-Clause License
44
5+ from __future__ import annotations
6+
57from enum import Enum
68
79
@@ -19,63 +21,86 @@ def __init__(self):
1921
2022
2123class Color :
22- """
23- Color class to handle color in different formats
24- """
24+ """Utility class representing a colour with handy conversions."""
2525
26- def __init__ (self , hex = "#000000" ):
26+ def __init__ (self , hex : str = "#000000" ):
2727 self .hex = hex
2828
29- def as_hex (self ):
29+ def as_hex (self ) -> str :
3030 return self .hex
3131
32- def as_rgb (self ):
32+ def as_rgb (self ) -> tuple [ int , int , int ] :
3333 return self .hex_to_rgb (self .hex )
3434
35- def as_normalized_rgb (self ):
35+ def as_normalized_rgb (self ) -> tuple [ float , float , float ] :
3636 return self .get_to_normalized_rgb (self .hex )
3737
3838 @staticmethod
39- def hex_to_rgb (hex ) :
39+ def hex_to_rgb (hex_value : str ) -> tuple [ int , int , int ] :
4040 # https://stackoverflow.com/questions/29643352/converting-hex-to-rgb-value-in-python
41- hex = hex .lstrip ("#" )
42- hlen = len (hex )
43- return tuple (int (hex [i : i + hlen // 3 ], 16 ) for i in range (0 , hlen , hlen // 3 ))
41+ hex_value = hex_value .lstrip ("#" )
42+ hlen = len (hex_value )
43+ return tuple (
44+ int (hex_value [i : i + hlen // 3 ], 16 )
45+ for i in range (0 , hlen , hlen // 3 )
46+ )
4447
4548 @staticmethod
46- def get_to_normalized_rgb (hex ) :
47- rgb = Color .hex_to_rgb (hex )
49+ def get_to_normalized_rgb (hex_value : str ) -> tuple [ float , float , float ] :
50+ rgb = Color .hex_to_rgb (hex_value )
4851 return (rgb [0 ] / 255.0 , rgb [1 ] / 255.0 , rgb [2 ] / 255.0 )
4952
5053
54+ DEFAULT_COLOR_CYCLE = (
55+ "#1f77b4" , # blue
56+ "#ff7f0e" , # orange
57+ "#2ca02c" , # green
58+ "#d62728" , # red
59+ "#9467bd" , # purple
60+ "#8c564b" , # brown
61+ "#e377c2" , # pink
62+ "#7f7f7f" , # gray
63+ "#bcbd22" , # olive
64+ "#17becf" , # cyan
65+ )
66+
67+
5168class ColorPalette :
52- """
53- Color palette class to handle color palette.
54- The user can get a color from the palette and the palette will automatically
55- cycle through the colors.
69+ """Cycling palette yielding :class:`Color` objects.
70+
71+ Args:
72+ colors: Optional iterable of colour specifications (hex strings or
73+ :class:`Color` instances). When omitted, ``DEFAULT_COLOR_CYCLE`` is
74+ used.
5675 """
5776
58- def __init__ (self ):
59- # use matlab color palette
77+ def __init__ (self , colors = None ):
78+ palette = colors or DEFAULT_COLOR_CYCLE
79+
6080 self ._color_palette = [
61- Color ("#0072BD" ),
62- Color ("#D95319" ),
63- Color ("#EDB120" ),
64- Color ("#7E2F8E" ),
65- Color ("#77AC30" ),
66- Color ("#4DBEEE" ),
67- Color ("#A2142F" ),
68- Color ("#7E2F8E" ),
69- Color ("#77AC30" ),
70- Color ("#4DBEEE" ),
71- Color ("#A2142F" ),
81+ color if isinstance (color , Color ) else Color (str (color ))
82+ for color in palette
7283 ]
84+
85+ if not self ._color_palette :
86+ raise ValueError ("ColorPalette requires at least one colour" )
87+
7388 self ._index = 0
7489
7590 def __iter__ (self ):
91+ self ._index = 0
7692 return self
7793
78- def __next__ (self ):
94+ def __next__ (self ) -> Color :
7995 color = self ._color_palette [self ._index ]
8096 self ._index = (self ._index + 1 ) % len (self ._color_palette )
8197 return color
98+
99+ def __len__ (self ) -> int :
100+ return len (self ._color_palette )
101+
102+ def __call__ (self , index : int ) -> Color :
103+ return self ._color_palette [index % len (self ._color_palette )]
104+
105+ def reset (self ) -> None :
106+ self ._index = 0
0 commit comments