2
2
Make beautiful, interactive maps with Python and Leaflet.js
3
3
4
4
"""
5
-
5
+ import copyreg
6
+ import re
6
7
import time
7
8
import webbrowser
9
+ from collections import OrderedDict
8
10
from typing import Any , List , Optional , Sequence , Union
9
11
10
12
from branca .element import Element , Figure , MacroElement
16
18
from folium .utilities import (
17
19
TypeBounds ,
18
20
TypeJsonValue ,
19
- _parse_size ,
20
21
parse_options ,
21
22
temp_html_filepath ,
22
23
validate_location ,
23
24
)
24
25
25
26
ENV = Environment (loader = PackageLoader ("folium" , "templates" ))
26
27
28
+ def _parse_size (value ):
29
+ if isinstance (value , (int , float )):
30
+ return float (value ), "px"
31
+ elif isinstance (value , str ):
32
+ # match digits or a point, possibly followed by a space,
33
+ # followed by a unit: either 1 to 5 letters or a percent sign
34
+ match = re .fullmatch (r"([\d.]+)\s?(\w{1,5}|%)" , value .strip ())
35
+ if match :
36
+ return float (match .group (1 )), match .group (2 )
37
+ else :
38
+ raise ValueError (
39
+ f"Cannot parse { value !r} , it should be a number followed by a unit." ,
40
+ )
41
+ elif isinstance (value , tuple ) and isinstance (value [0 ], (int , float )) and isinstance (value [1 ], str ):
42
+ # value had been already parsed
43
+ return value
44
+ else :
45
+ raise TypeError (
46
+ f"Cannot parse { value !r} , it should be a number or a string containing a number and a unit." ,
47
+ )
27
48
28
49
_default_js = [
29
50
(
"leaflet" ,
"https://cdn.jsdelivr.net/npm/[email protected] /dist/leaflet.js" ),
@@ -258,9 +279,26 @@ def __init__(
258
279
disable_3d : bool = False ,
259
280
png_enabled : bool = False ,
260
281
zoom_control : bool = True ,
282
+ _children : OrderedDict = OrderedDict (),
261
283
** kwargs : TypeJsonValue ,
262
284
):
263
285
super ().__init__ ()
286
+ self .tiles = tiles
287
+ self .attr = attr
288
+ self .min_zoom = min_zoom
289
+ self .max_zoom = max_zoom
290
+ self .zoom_start = zoom_start
291
+ self .min_lat = min_lat
292
+ self .max_lat = max_lat
293
+ self .min_lon = min_lon
294
+ self .max_lon = max_lon
295
+ self .max_bounds = max_bounds
296
+ self .prefer_canvas = prefer_canvas
297
+ self .no_touch = no_touch
298
+ self .disable_3d = disable_3d
299
+ self .zoom_control = zoom_control
300
+ self ._children = _children
301
+
264
302
self ._name = "Map"
265
303
self ._env = ENV
266
304
@@ -301,14 +339,18 @@ def __init__(
301
339
self .global_switches = GlobalSwitches (no_touch , disable_3d )
302
340
303
341
self .objects_to_stay_in_front : List [Layer ] = []
304
-
305
- if isinstance (tiles , TileLayer ):
306
- self .add_child (tiles )
307
- elif tiles :
308
- tile_layer = TileLayer (
309
- tiles = tiles , attr = attr , min_zoom = min_zoom , max_zoom = max_zoom
310
- )
311
- self .add_child (tile_layer , name = tile_layer .tile_name )
342
+
343
+ if len (self ._children ) > 0 : # Add already prepared childrens
344
+ for key , child in self ._children .items (): # add the missing ones (key is a safety)
345
+ self .add_child (child , name = key )
346
+ else : # Initialize the tiles
347
+ if isinstance (tiles , TileLayer ):
348
+ self .add_child (tiles , index = 0 )
349
+ elif tiles :
350
+ tile_layer = TileLayer (
351
+ tiles = tiles , attr = attr , min_zoom = min_zoom , max_zoom = max_zoom , index = 0
352
+ )
353
+ self .add_child (tile_layer , name = tile_layer .tile_name )
312
354
313
355
def _repr_html_ (self , ** kwargs ) -> str :
314
356
"""Displays the HTML Map in a Jupyter notebook."""
@@ -473,3 +515,33 @@ def keep_in_front(self, *args: Layer) -> None:
473
515
"""
474
516
for obj in args :
475
517
self .objects_to_stay_in_front .append (obj )
518
+
519
+ def map_reduce (map_instance ):
520
+ return (Map , (
521
+ map_instance .location ,
522
+ map_instance .width ,
523
+ map_instance .height ,
524
+ map_instance .left ,
525
+ map_instance .top ,
526
+ map_instance .position ,
527
+ map_instance .tiles ,
528
+ map_instance .attr ,
529
+ map_instance .min_zoom ,
530
+ map_instance .max_zoom ,
531
+ map_instance .zoom_start ,
532
+ map_instance .min_lat ,
533
+ map_instance .max_lat ,
534
+ map_instance .min_lon ,
535
+ map_instance .max_lon ,
536
+ map_instance .max_bounds ,
537
+ map_instance .crs ,
538
+ map_instance .control_scale ,
539
+ map_instance .prefer_canvas ,
540
+ map_instance .no_touch ,
541
+ map_instance .disable_3d ,
542
+ map_instance .png_enabled ,
543
+ map_instance .zoom_control ,
544
+ map_instance ._children ,
545
+ ))
546
+
547
+ copyreg .pickle (Map , map_reduce )
0 commit comments