99import json
1010import math
1111import os
12+ from typing import Dict , List , Optional , Sequence , Tuple , Union
1213
1314from jinja2 import Template
1415
1516from branca .element import ENV , Figure , JavascriptLink , MacroElement
1617from branca .utilities import legend_scaler
1718
18- rootpath = os .path .abspath (os .path .dirname (__file__ ))
19+ rootpath : str = os .path .abspath (os .path .dirname (__file__ ))
1920
2021with open (os .path .join (rootpath , "_cnames.json" )) as f :
21- _cnames = json .loads (f .read ())
22+ _cnames : Dict [ str , str ] = json .loads (f .read ())
2223
2324with open (os .path .join (rootpath , "_schemes.json" )) as f :
24- _schemes = json .loads (f .read ())
25+ _schemes : Dict [ str , List [ str ]] = json .loads (f .read ())
2526
2627
27- def _is_hex (x ):
28+ TypeRGBInts = Tuple [int , int , int ]
29+ TypeRGBFloats = Tuple [float , float , float ]
30+ TypeRGBAInts = Tuple [int , int , int , int ]
31+ TypeRGBAFloats = Tuple [float , float , float , float ]
32+ TypeAnyColorType = Union [TypeRGBInts , TypeRGBFloats , TypeRGBAInts , TypeRGBAFloats , str ]
33+
34+
35+ def _is_hex (x : str ) -> bool :
2836 return x .startswith ("#" ) and len (x ) == 7
2937
3038
31- def _parse_hex (color_code ) :
39+ def _parse_hex (color_code : str ) -> TypeRGBAFloats :
3240 return (
33- int (color_code [1 :3 ], 16 ),
34- int (color_code [3 :5 ], 16 ),
35- int (color_code [5 :7 ], 16 ),
41+ _color_int_to_float (int (color_code [1 :3 ], 16 )),
42+ _color_int_to_float (int (color_code [3 :5 ], 16 )),
43+ _color_int_to_float (int (color_code [5 :7 ], 16 )),
44+ 1.0 ,
3645 )
3746
3847
39- def _parse_color (x ):
48+ def _color_int_to_float (x : int ) -> float :
49+ """Convert an integer between 0 and 255 to a float between 0. and 1.0"""
50+ return x / 255.0
51+
52+
53+ def _color_float_to_int (x : float ) -> int :
54+ """Convert a float between 0. and 1.0 to an integer between 0 and 255"""
55+ return int (x * 255.9999 )
56+
57+
58+ def _parse_color (x : Union [tuple , list , str ]) -> TypeRGBAFloats :
4059 if isinstance (x , (tuple , list )):
41- color_tuple = tuple (x ) [:4 ]
42- elif isinstance (x , ( str , bytes ) ) and _is_hex (x ):
43- color_tuple = _parse_hex (x )
44- elif isinstance (x , ( str , bytes ) ):
60+ return tuple (tuple ( x ) + ( 1.0 ,)) [:4 ] # type: ignore
61+ elif isinstance (x , str ) and _is_hex (x ):
62+ return _parse_hex (x )
63+ elif isinstance (x , str ):
4564 cname = _cnames .get (x .lower (), None )
4665 if cname is None :
4766 raise ValueError (f"Unknown color { cname !r} ." )
48- color_tuple = _parse_hex (cname )
67+ return _parse_hex (cname )
4968 else :
5069 raise ValueError (f"Unrecognized color code { x !r} " )
51- if max (color_tuple ) > 1.0 :
52- color_tuple = tuple (u / 255.0 for u in color_tuple )
53- return tuple (map (float , (color_tuple + (1.0 ,))[:4 ]))
5470
5571
56- def _base (x ) :
72+ def _base (x : float ) -> float :
5773 if x > 0 :
5874 base = pow (10 , math .floor (math .log10 (x )))
5975 return round (x / base ) * base
@@ -78,15 +94,15 @@ class ColorMap(MacroElement):
7894 Maximum number of legend tick labels
7995 """
8096
81- _template = ENV .get_template ("color_scale.js" )
97+ _template : Template = ENV .get_template ("color_scale.js" )
8298
8399 def __init__ (
84100 self ,
85- vmin = 0.0 ,
86- vmax = 1.0 ,
87- caption = "" ,
88- text_color = "black" ,
89- max_labels = 10 ,
101+ vmin : float = 0.0 ,
102+ vmax : float = 1.0 ,
103+ caption : str = "" ,
104+ text_color : str = "black" ,
105+ max_labels : int = 10 ,
90106 ):
91107 super ().__init__ ()
92108 self ._name = "ColorMap"
@@ -95,9 +111,9 @@ def __init__(
95111 self .vmax = vmax
96112 self .caption = caption
97113 self .text_color = text_color
98- self .index = [vmin , vmax ]
114+ self .index : List [ float ] = [vmin , vmax ]
99115 self .max_labels = max_labels
100- self .tick_labels = None
116+ self .tick_labels : Optional [ Sequence [ Union [ float , str ]]] = None
101117
102118 self .width = 450
103119 self .height = 40
@@ -127,7 +143,7 @@ def render(self, **kwargs):
127143 name = "d3" ,
128144 ) # noqa
129145
130- def rgba_floats_tuple (self , x ) :
146+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
131147 """
132148 This class has to be implemented for each class inheriting from
133149 Colormap. This has to be a function of the form float ->
@@ -137,37 +153,37 @@ def rgba_floats_tuple(self, x):
137153 """
138154 raise NotImplementedError
139155
140- def rgba_bytes_tuple (self , x ) :
156+ def rgba_bytes_tuple (self , x : float ) -> TypeRGBAInts :
141157 """Provides the color corresponding to value `x` in the
142158 form of a tuple (R,G,B,A) with int values between 0 and 255.
143159 """
144- return tuple (int ( u * 255.9999 ) for u in self .rgba_floats_tuple (x ))
160+ return tuple (_color_float_to_int ( u ) for u in self .rgba_floats_tuple (x )) # type: ignore
145161
146- def rgb_bytes_tuple (self , x ) :
162+ def rgb_bytes_tuple (self , x : float ) -> TypeRGBInts :
147163 """Provides the color corresponding to value `x` in the
148164 form of a tuple (R,G,B) with int values between 0 and 255.
149165 """
150166 return self .rgba_bytes_tuple (x )[:3 ]
151167
152- def rgb_hex_str (self , x ) :
168+ def rgb_hex_str (self , x : float ) -> str :
153169 """Provides the color corresponding to value `x` in the
154170 form of a string of hexadecimal values "#RRGGBB".
155171 """
156172 return "#%02x%02x%02x" % self .rgb_bytes_tuple (x )
157173
158- def rgba_hex_str (self , x ) :
174+ def rgba_hex_str (self , x : float ) -> str :
159175 """Provides the color corresponding to value `x` in the
160176 form of a string of hexadecimal values "#RRGGBBAA".
161177 """
162178 return "#%02x%02x%02x%02x" % self .rgba_bytes_tuple (x )
163179
164- def __call__ (self , x ) :
180+ def __call__ (self , x : float ) -> str :
165181 """Provides the color corresponding to value `x` in the
166182 form of a string of hexadecimal values "#RRGGBBAA".
167183 """
168184 return self .rgba_hex_str (x )
169185
170- def _repr_html_ (self ):
186+ def _repr_html_ (self ) -> str :
171187 """Display the colormap in a Jupyter Notebook.
172188
173189 Does not support all the class arguments.
@@ -264,14 +280,14 @@ class LinearColormap(ColorMap):
264280
265281 def __init__ (
266282 self ,
267- colors ,
268- index = None ,
269- vmin = 0.0 ,
270- vmax = 1.0 ,
271- caption = "" ,
272- text_color = "black" ,
273- max_labels = 10 ,
274- tick_labels = None ,
283+ colors : Sequence [ TypeAnyColorType ] ,
284+ index : Optional [ Sequence [ float ]] = None ,
285+ vmin : float = 0.0 ,
286+ vmax : float = 1.0 ,
287+ caption : str = "" ,
288+ text_color : str = "black" ,
289+ max_labels : int = 10 ,
290+ tick_labels : Optional [ Sequence [ float ]] = None ,
275291 ):
276292 super ().__init__ (
277293 vmin = vmin ,
@@ -280,7 +296,7 @@ def __init__(
280296 text_color = text_color ,
281297 max_labels = max_labels ,
282298 )
283- self .tick_labels = tick_labels
299+ self .tick_labels : Optional [ Sequence [ float ]] = tick_labels
284300
285301 n = len (colors )
286302 if n < 2 :
@@ -289,9 +305,9 @@ def __init__(
289305 self .index = [vmin + (vmax - vmin ) * i * 1.0 / (n - 1 ) for i in range (n )]
290306 else :
291307 self .index = list (index )
292- self .colors = [_parse_color (x ) for x in colors ]
308+ self .colors : List [ TypeRGBAFloats ] = [_parse_color (x ) for x in colors ]
293309
294- def rgba_floats_tuple (self , x ) :
310+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
295311 """Provides the color corresponding to value `x` in the
296312 form of a tuple (R,G,B,A) with float values between 0. and 1.
297313 """
@@ -308,20 +324,20 @@ def rgba_floats_tuple(self, x):
308324 else :
309325 raise ValueError ("Thresholds are not sorted." )
310326
311- return tuple (
327+ return tuple ( # type: ignore
312328 (1.0 - p ) * self .colors [i - 1 ][j ] + p * self .colors [i ][j ] for j in range (4 )
313329 )
314330
315331 def to_step (
316332 self ,
317- n = None ,
318- index = None ,
319- data = None ,
320- method = None ,
321- quantiles = None ,
322- round_method = None ,
323- max_labels = 10 ,
324- ):
333+ n : Optional [ int ] = None ,
334+ index : Optional [ Sequence [ float ]] = None ,
335+ data : Optional [ Sequence [ float ]] = None ,
336+ method : str = "linear" ,
337+ quantiles : Optional [ Sequence [ float ]] = None ,
338+ round_method : Optional [ str ] = None ,
339+ max_labels : int = 10 ,
340+ ) -> "StepColormap" :
325341 """Splits the LinearColormap into a StepColormap.
326342
327343 Parameters
@@ -382,11 +398,7 @@ def to_step(
382398 max_ = max (data )
383399 min_ = min (data )
384400 scaled_cm = self .scale (vmin = min_ , vmax = max_ )
385- method = (
386- "quantiles"
387- if quantiles is not None
388- else method if method is not None else "linear"
389- )
401+ method = "quantiles" if quantiles is not None else method
390402 if method .lower ().startswith ("lin" ):
391403 if n is None :
392404 raise ValueError (msg )
@@ -454,7 +466,12 @@ def to_step(
454466 tick_labels = self .tick_labels ,
455467 )
456468
457- def scale (self , vmin = 0.0 , vmax = 1.0 , max_labels = 10 ):
469+ def scale (
470+ self ,
471+ vmin : float = 0.0 ,
472+ vmax : float = 1.0 ,
473+ max_labels : int = 10 ,
474+ ) -> "LinearColormap" :
458475 """Transforms the colorscale so that the minimal and maximal values
459476 fit the given parameters.
460477 """
@@ -510,14 +527,14 @@ class StepColormap(ColorMap):
510527
511528 def __init__ (
512529 self ,
513- colors ,
514- index = None ,
515- vmin = 0.0 ,
516- vmax = 1.0 ,
517- caption = "" ,
518- text_color = "black" ,
519- max_labels = 10 ,
520- tick_labels = None ,
530+ colors : Sequence [ TypeAnyColorType ] ,
531+ index : Optional [ Sequence [ float ]] = None ,
532+ vmin : float = 0.0 ,
533+ vmax : float = 1.0 ,
534+ caption : str = "" ,
535+ text_color : str = "black" ,
536+ max_labels : int = 10 ,
537+ tick_labels : Optional [ Sequence [ float ]] = None ,
521538 ):
522539 super ().__init__ (
523540 vmin = vmin ,
@@ -535,9 +552,9 @@ def __init__(
535552 self .index = [vmin + (vmax - vmin ) * i * 1.0 / n for i in range (n + 1 )]
536553 else :
537554 self .index = list (index )
538- self .colors = [_parse_color (x ) for x in colors ]
555+ self .colors : List [ TypeRGBAFloats ] = [_parse_color (x ) for x in colors ]
539556
540- def rgba_floats_tuple (self , x ) :
557+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
541558 """
542559 Provides the color corresponding to value `x` in the
543560 form of a tuple (R,G,B,A) with float values between 0. and 1.
@@ -549,9 +566,13 @@ def rgba_floats_tuple(self, x):
549566 return self .colors [- 1 ]
550567
551568 i = len ([u for u in self .index if u <= x ]) # 0 < i < n.
552- return tuple ( self .colors [i - 1 ])
569+ return self .colors [i - 1 ]
553570
554- def to_linear (self , index = None , max_labels = 10 ):
571+ def to_linear (
572+ self ,
573+ index : Optional [Sequence [float ]] = None ,
574+ max_labels : int = 10 ,
575+ ) -> LinearColormap :
555576 """
556577 Transforms the StepColormap into a LinearColormap.
557578
@@ -584,7 +605,12 @@ def to_linear(self, index=None, max_labels=10):
584605 max_labels = max_labels ,
585606 )
586607
587- def scale (self , vmin = 0.0 , vmax = 1.0 , max_labels = 10 ):
608+ def scale (
609+ self ,
610+ vmin : float = 0.0 ,
611+ vmax : float = 1.0 ,
612+ max_labels : int = 10 ,
613+ ) -> "StepColormap" :
588614 """Transforms the colorscale so that the minimal and maximal values
589615 fit the given parameters.
590616 """
@@ -611,7 +637,7 @@ def __init__(self):
611637 for key , val in _schemes .items ():
612638 setattr (self , key , LinearColormap (val ))
613639
614- def _repr_html_ (self ):
640+ def _repr_html_ (self ) -> str :
615641 return Template (
616642 """
617643 <table>
@@ -634,7 +660,7 @@ def __init__(self):
634660 for key , val in _schemes .items ():
635661 setattr (self , key , StepColormap (val ))
636662
637- def _repr_html_ (self ):
663+ def _repr_html_ (self ) -> str :
638664 return Template (
639665 """
640666 <table>
0 commit comments