Skip to content

Commit f13798b

Browse files
authored
Fix duplicate HTML when map.save() is called repeatedly (#2239)
* Fix duplicate HTML when map.save() is called repeatedly Repeated save() calls appended duplicate JavaScript because SetIcon and ElementAddToElement created new render children with unique IDs on each pass. Use stable script names so repeated renders replace instead of append. Do not clear figure.html in render(); geopandas adds legend HTML directly there. Fixes #2237 * Remove unrelated changes from repeated save fix Keep only ElementAddToElement.render() and Marker.SetIcon.render() per review feedback.
1 parent 6b75c07 commit f13798b

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

folium/elements.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ def __init__(self, element_name: str, element_parent_name: str):
149149
self.element_name = element_name
150150
self.element_parent_name = element_parent_name
151151

152+
def render(self, **kwargs):
153+
figure = self.get_root()
154+
assert isinstance(
155+
figure, Figure
156+
), "You cannot render this Element if it is not in a Figure."
157+
script = self._template.module.__dict__.get("script", None)
158+
if script is not None:
159+
figure.script.add_child(
160+
Element(script(self, kwargs)),
161+
name=f"{self.element_name}_add_to_{self.element_parent_name}",
162+
)
163+
152164

153165
class IncludeStatement(MacroElement):
154166
"""Generate an include statement on a class."""

folium/map.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,18 @@ def __init__(
517517
self.marker = marker
518518
self.icon = icon
519519

520+
def render(self, **kwargs):
521+
figure = self.get_root()
522+
assert isinstance(
523+
figure, Figure
524+
), "You cannot render this Element if it is not in a Figure."
525+
script = self._template.module.__dict__.get("script", None)
526+
if script is not None:
527+
figure.script.add_child(
528+
Element(script(self, kwargs)),
529+
name=f"{self.marker.get_name()}_set_icon",
530+
)
531+
520532
def __init__(
521533
self,
522534
location: Optional[Sequence[float]] = None,

tests/test_map.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,27 @@ def test_icon_invalid_marker_colors():
290290
pytest.warns(UserWarning, Icon, color="lila")
291291
pytest.warns(UserWarning, Icon, color=42)
292292
pytest.warns(UserWarning, Icon, color=None)
293+
294+
295+
def test_repeated_save_produces_identical_html(tmp_path):
296+
"""Regression test for https://github.com/python-visualization/folium/issues/2237"""
297+
m = Map(location=[40.75, -73.98], zoom_start=13)
298+
locations = [
299+
[40.7829, -73.9654],
300+
[40.7484, -73.9857],
301+
[40.7580, -73.9855],
302+
]
303+
for lat, lon in locations:
304+
Marker([lat, lon], icon=Icon(color="blue", icon="info-sign")).add_to(m)
305+
306+
path1 = tmp_path / "1.html"
307+
path2 = tmp_path / "2.html"
308+
path3 = tmp_path / "3.html"
309+
m.save(path1)
310+
m.save(path2)
311+
m.save(path3)
312+
313+
html1 = path1.read_text()
314+
html2 = path2.read_text()
315+
html3 = path3.read_text()
316+
assert html1 == html2 == html3

0 commit comments

Comments
 (0)