Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the map pickable natively #1812

Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 87 additions & 10 deletions folium/folium.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
Make beautiful, interactive maps with Python and Leaflet.js

"""

import copyreg
import re
import time
import webbrowser
from collections import OrderedDict
from typing import Any, List, Optional, Sequence, Union

from branca.element import Element, Figure, MacroElement
Expand All @@ -16,14 +18,33 @@
from folium.utilities import (
TypeBounds,
TypeJsonValue,
_parse_size,
parse_options,
temp_html_filepath,
validate_location,
)

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

def _parse_size(value):
if isinstance(value, (int, float)):
return float(value), "px"
elif isinstance(value, str):
# match digits or a point, possibly followed by a space,
# followed by a unit: either 1 to 5 letters or a percent sign
match = re.fullmatch(r"([\d.]+)\s?(\w{1,5}|%)", value.strip())
if match:
return float(match.group(1)), match.group(2)
else:
raise ValueError(
f"Cannot parse {value!r}, it should be a number followed by a unit.",
)
elif isinstance(value, tuple) and isinstance(value[0], (int, float)) and isinstance(value[1], str):
# value had been already parsed
return value
else:
raise TypeError(
f"Cannot parse {value!r}, it should be a number or a string containing a number and a unit.",
)

_default_js = [
("leaflet", "https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js"),
Expand Down Expand Up @@ -258,9 +279,26 @@ def __init__(
disable_3d: bool = False,
png_enabled: bool = False,
zoom_control: bool = True,
_children: OrderedDict = OrderedDict(),
**kwargs: TypeJsonValue,
):
super().__init__()
self.tiles = tiles
self.attr = attr
self.min_zoom = min_zoom
self.max_zoom = max_zoom
self.zoom_start = zoom_start
self.min_lat = min_lat
self.max_lat = max_lat
self.min_lon = min_lon
self.max_lon = max_lon
self.max_bounds = max_bounds
self.prefer_canvas = prefer_canvas
self.no_touch = no_touch
self.disable_3d = disable_3d
self.zoom_control = zoom_control
self._children = _children

self._name = "Map"
self._env = ENV

Expand Down Expand Up @@ -301,14 +339,23 @@ def __init__(
self.global_switches = GlobalSwitches(no_touch, disable_3d)

self.objects_to_stay_in_front: List[Layer] = []

if isinstance(tiles, TileLayer):
self.add_child(tiles)
elif tiles:
tile_layer = TileLayer(
tiles=tiles, attr=attr, min_zoom=min_zoom, max_zoom=max_zoom
)
self.add_child(tile_layer, name=tile_layer.tile_name)

if len(self._children) > 0: # Add already prepared childrens
for key, child in self._children.items(): # add the missing ones (key is a safety)
self.add_child(child, name = key)
else: # Initialize the tiles
if isinstance(tiles, TileLayer):
self.add_child(tiles)
elif tiles:
tile_layer = TileLayer(
tiles=tiles, attr=attr, min_zoom=min_zoom, max_zoom=max_zoom
)
self.add_child(tile_layer, name=tile_layer.tile_name)

def set_parent_for_children(self) -> None:
for _, child in self._children.items():
child._parent = self
return None

def _repr_html_(self, **kwargs) -> str:
"""Displays the HTML Map in a Jupyter notebook."""
Expand Down Expand Up @@ -473,3 +520,33 @@ def keep_in_front(self, *args: Layer) -> None:
"""
for obj in args:
self.objects_to_stay_in_front.append(obj)

def map_pickler(map_instance):
return (Map, (
map_instance.location,
map_instance.width,
map_instance.height,
map_instance.left,
map_instance.top,
map_instance.position,
map_instance.tiles,
map_instance.attr,
map_instance.min_zoom,
map_instance.max_zoom,
map_instance.zoom_start,
map_instance.min_lat,
map_instance.max_lat,
map_instance.min_lon,
map_instance.max_lon,
map_instance.max_bounds,
map_instance.crs,
map_instance.control_scale,
map_instance.prefer_canvas,
map_instance.no_touch,
map_instance.disable_3d,
map_instance.png_enabled,
map_instance.zoom_control,
map_instance._children,
))

copyreg.pickle(Map, map_pickler)
Loading