9
9
import json
10
10
import math
11
11
import os
12
+ from typing import Dict , List , Optional , Sequence , Tuple , Union
12
13
13
14
from jinja2 import Template
14
15
15
16
from branca .element import ENV , Figure , JavascriptLink , MacroElement
16
17
from branca .utilities import legend_scaler
17
18
18
- rootpath = os .path .abspath (os .path .dirname (__file__ ))
19
+ rootpath : str = os .path .abspath (os .path .dirname (__file__ ))
19
20
20
21
with open (os .path .join (rootpath , "_cnames.json" )) as f :
21
- _cnames = json .loads (f .read ())
22
+ _cnames : Dict [ str , str ] = json .loads (f .read ())
22
23
23
24
with 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 ())
25
26
26
27
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 :
28
36
return x .startswith ("#" ) and len (x ) == 7
29
37
30
38
31
- def _parse_hex (color_code ) :
39
+ def _parse_hex (color_code : str ) -> TypeRGBAFloats :
32
40
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 ,
36
45
)
37
46
38
47
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 :
40
59
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 ):
45
64
cname = _cnames .get (x .lower (), None )
46
65
if cname is None :
47
66
raise ValueError (f"Unknown color { cname !r} ." )
48
- color_tuple = _parse_hex (cname )
67
+ return _parse_hex (cname )
49
68
else :
50
69
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 ]))
54
70
55
71
56
- def _base (x ) :
72
+ def _base (x : float ) -> float :
57
73
if x > 0 :
58
74
base = pow (10 , math .floor (math .log10 (x )))
59
75
return round (x / base ) * base
@@ -78,15 +94,15 @@ class ColorMap(MacroElement):
78
94
Maximum number of legend tick labels
79
95
"""
80
96
81
- _template = ENV .get_template ("color_scale.js" )
97
+ _template : Template = ENV .get_template ("color_scale.js" )
82
98
83
99
def __init__ (
84
100
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 ,
90
106
):
91
107
super ().__init__ ()
92
108
self ._name = "ColorMap"
@@ -95,9 +111,9 @@ def __init__(
95
111
self .vmax = vmax
96
112
self .caption = caption
97
113
self .text_color = text_color
98
- self .index = [vmin , vmax ]
114
+ self .index : List [ float ] = [vmin , vmax ]
99
115
self .max_labels = max_labels
100
- self .tick_labels = None
116
+ self .tick_labels : Optional [ Sequence [ Union [ float , str ]]] = None
101
117
102
118
self .width = 450
103
119
self .height = 40
@@ -127,7 +143,7 @@ def render(self, **kwargs):
127
143
name = "d3" ,
128
144
) # noqa
129
145
130
- def rgba_floats_tuple (self , x ) :
146
+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
131
147
"""
132
148
This class has to be implemented for each class inheriting from
133
149
Colormap. This has to be a function of the form float ->
@@ -137,37 +153,37 @@ def rgba_floats_tuple(self, x):
137
153
"""
138
154
raise NotImplementedError
139
155
140
- def rgba_bytes_tuple (self , x ) :
156
+ def rgba_bytes_tuple (self , x : float ) -> TypeRGBAInts :
141
157
"""Provides the color corresponding to value `x` in the
142
158
form of a tuple (R,G,B,A) with int values between 0 and 255.
143
159
"""
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
145
161
146
- def rgb_bytes_tuple (self , x ) :
162
+ def rgb_bytes_tuple (self , x : float ) -> TypeRGBInts :
147
163
"""Provides the color corresponding to value `x` in the
148
164
form of a tuple (R,G,B) with int values between 0 and 255.
149
165
"""
150
166
return self .rgba_bytes_tuple (x )[:3 ]
151
167
152
- def rgb_hex_str (self , x ) :
168
+ def rgb_hex_str (self , x : float ) -> str :
153
169
"""Provides the color corresponding to value `x` in the
154
170
form of a string of hexadecimal values "#RRGGBB".
155
171
"""
156
172
return "#%02x%02x%02x" % self .rgb_bytes_tuple (x )
157
173
158
- def rgba_hex_str (self , x ) :
174
+ def rgba_hex_str (self , x : float ) -> str :
159
175
"""Provides the color corresponding to value `x` in the
160
176
form of a string of hexadecimal values "#RRGGBBAA".
161
177
"""
162
178
return "#%02x%02x%02x%02x" % self .rgba_bytes_tuple (x )
163
179
164
- def __call__ (self , x ) :
180
+ def __call__ (self , x : float ) -> str :
165
181
"""Provides the color corresponding to value `x` in the
166
182
form of a string of hexadecimal values "#RRGGBBAA".
167
183
"""
168
184
return self .rgba_hex_str (x )
169
185
170
- def _repr_html_ (self ):
186
+ def _repr_html_ (self ) -> str :
171
187
"""Display the colormap in a Jupyter Notebook.
172
188
173
189
Does not support all the class arguments.
@@ -264,14 +280,14 @@ class LinearColormap(ColorMap):
264
280
265
281
def __init__ (
266
282
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 ,
275
291
):
276
292
super ().__init__ (
277
293
vmin = vmin ,
@@ -280,7 +296,7 @@ def __init__(
280
296
text_color = text_color ,
281
297
max_labels = max_labels ,
282
298
)
283
- self .tick_labels = tick_labels
299
+ self .tick_labels : Optional [ Sequence [ float ]] = tick_labels
284
300
285
301
n = len (colors )
286
302
if n < 2 :
@@ -289,9 +305,9 @@ def __init__(
289
305
self .index = [vmin + (vmax - vmin ) * i * 1.0 / (n - 1 ) for i in range (n )]
290
306
else :
291
307
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 ]
293
309
294
- def rgba_floats_tuple (self , x ) :
310
+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
295
311
"""Provides the color corresponding to value `x` in the
296
312
form of a tuple (R,G,B,A) with float values between 0. and 1.
297
313
"""
@@ -308,20 +324,20 @@ def rgba_floats_tuple(self, x):
308
324
else :
309
325
raise ValueError ("Thresholds are not sorted." )
310
326
311
- return tuple (
327
+ return tuple ( # type: ignore
312
328
(1.0 - p ) * self .colors [i - 1 ][j ] + p * self .colors [i ][j ] for j in range (4 )
313
329
)
314
330
315
331
def to_step (
316
332
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" :
325
341
"""Splits the LinearColormap into a StepColormap.
326
342
327
343
Parameters
@@ -382,11 +398,7 @@ def to_step(
382
398
max_ = max (data )
383
399
min_ = min (data )
384
400
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
390
402
if method .lower ().startswith ("lin" ):
391
403
if n is None :
392
404
raise ValueError (msg )
@@ -454,7 +466,12 @@ def to_step(
454
466
tick_labels = self .tick_labels ,
455
467
)
456
468
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" :
458
475
"""Transforms the colorscale so that the minimal and maximal values
459
476
fit the given parameters.
460
477
"""
@@ -510,14 +527,14 @@ class StepColormap(ColorMap):
510
527
511
528
def __init__ (
512
529
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 ,
521
538
):
522
539
super ().__init__ (
523
540
vmin = vmin ,
@@ -535,9 +552,9 @@ def __init__(
535
552
self .index = [vmin + (vmax - vmin ) * i * 1.0 / n for i in range (n + 1 )]
536
553
else :
537
554
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 ]
539
556
540
- def rgba_floats_tuple (self , x ) :
557
+ def rgba_floats_tuple (self , x : float ) -> TypeRGBAFloats :
541
558
"""
542
559
Provides the color corresponding to value `x` in the
543
560
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):
549
566
return self .colors [- 1 ]
550
567
551
568
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 ]
553
570
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 :
555
576
"""
556
577
Transforms the StepColormap into a LinearColormap.
557
578
@@ -584,7 +605,12 @@ def to_linear(self, index=None, max_labels=10):
584
605
max_labels = max_labels ,
585
606
)
586
607
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" :
588
614
"""Transforms the colorscale so that the minimal and maximal values
589
615
fit the given parameters.
590
616
"""
@@ -611,7 +637,7 @@ def __init__(self):
611
637
for key , val in _schemes .items ():
612
638
setattr (self , key , LinearColormap (val ))
613
639
614
- def _repr_html_ (self ):
640
+ def _repr_html_ (self ) -> str :
615
641
return Template (
616
642
"""
617
643
<table>
@@ -634,7 +660,7 @@ def __init__(self):
634
660
for key , val in _schemes .items ():
635
661
setattr (self , key , StepColormap (val ))
636
662
637
- def _repr_html_ (self ):
663
+ def _repr_html_ (self ) -> str :
638
664
return Template (
639
665
"""
640
666
<table>
0 commit comments