Skip to content

Commit d5663ad

Browse files
Make the map pickable using copyreg
1 parent 57e8eae commit d5663ad

File tree

1 file changed

+82
-10
lines changed

1 file changed

+82
-10
lines changed

folium/folium.py

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
Make beautiful, interactive maps with Python and Leaflet.js
33
44
"""
5-
5+
import copyreg
6+
import re
67
import time
78
import webbrowser
9+
from collections import OrderedDict
810
from typing import Any, List, Optional, Sequence, Union
911

1012
from branca.element import Element, Figure, MacroElement
@@ -16,14 +18,33 @@
1618
from folium.utilities import (
1719
TypeBounds,
1820
TypeJsonValue,
19-
_parse_size,
2021
parse_options,
2122
temp_html_filepath,
2223
validate_location,
2324
)
2425

2526
ENV = Environment(loader=PackageLoader("folium", "templates"))
2627

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+
)
2748

2849
_default_js = [
2950
("leaflet", "https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js"),
@@ -258,9 +279,26 @@ def __init__(
258279
disable_3d: bool = False,
259280
png_enabled: bool = False,
260281
zoom_control: bool = True,
282+
_children: OrderedDict = OrderedDict(),
261283
**kwargs: TypeJsonValue,
262284
):
263285
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+
264302
self._name = "Map"
265303
self._env = ENV
266304

@@ -301,14 +339,18 @@ def __init__(
301339
self.global_switches = GlobalSwitches(no_touch, disable_3d)
302340

303341
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)
312354

313355
def _repr_html_(self, **kwargs) -> str:
314356
"""Displays the HTML Map in a Jupyter notebook."""
@@ -473,3 +515,33 @@ def keep_in_front(self, *args: Layer) -> None:
473515
"""
474516
for obj in args:
475517
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

Comments
 (0)