python-visualization / folium

Python Data. Leaflet.js Maps.
https://python-visualization.github.io/folium/
MIT License
6.93k stars 2.23k forks source link

Creating an SVG divicon variable and using it in a marker works. Adding a second, marker that uses that variable causes neither to appear as expected #1885

Open rl-utility-man opened 9 months ago

rl-utility-man commented 9 months ago

Describe the bug

If I pass the same object reference to Marker twice, it fails cryptically, but if I pass two distinct but identical objects to Marker, it succeeds

If I create one marker containing a variable that contains a DivIcon with an svg image tag, it works. If I add a second marker containing a different svg image tag -- even if the code underlying the divicon is identical, it will also work (see the left panel). But if I create a second marker containing the same svg icon variable, both of the icons fail (see the right panel).

folium

For now, a viable workaround seems to be to avoid creating an icon variable and instead to just use:

folium.Marker(
...    icon=folium.DivIcon(
    icon_anchor=(15, 15),
    html=f"""<div><img src="book-open-variant-outline.svg" height="35" width="35"/></div>""")
).add_to(map_lc)

I suspect based on some struggles I've had in the last few days, but have not confirmed, that this affects font-awesome DivIcons as well.

To Reproduce

import folium
import copy
# Library of Congress coordinates (latitude, longitude)
loc_coordinates = (38.8886, -77.0047)

# Create a Folium map centered around the Library of Congress
map_lc = folium.Map(location=loc_coordinates, zoom_start=15)

# Define the DivIcon with the custom icon.  This variable can be used in one marker successfully, but will fail if we use it in two markers.

icon=folium.DivIcon(
    icon_anchor=(15, 15),
    html=f"""<div><img src="book-open-variant-outline.svg" height="35" width="35"/></div>""")

folium.Marker(
    location=(38.886970844230866, -77.00471380332),
    popup='Library of Congress:  James Madison Building',
    icon=icon
).add_to(map_lc)
#if we save here, everything will be fine.

map_lc_this_will_fail = copy.deepcopy(map_lc)

#creating a second divicon variable which we will use successfully just once.
icon2=folium.DivIcon(
    icon_anchor=(15, 15),
    html=f"""<div><img src="book-open-variant-outline.svg" height="35" width="35"/></div>""")

# Place the DivIcon on the map at a second Library of Congress building
folium.Marker(
    location=loc_coordinates,
    popup='Library of Congress',
    icon=icon2

).add_to(map_lc)

map_lc.save("map_lc_two_markers_working.html")

# Now we go back to the original map with one marker and one icon variable, and add a second marker reusing the icon variable.  this will fail.

folium.Marker(
    location=loc_coordinates,
    popup='Library of Congress',
    icon=icon
).add_to(map_lc_this_will_fail)

map_lc_this_will_fail.save("map_lc_two_markers_failing.html")

I think the problem is in the following section of output: Here is the last section of output for the working version:


            var div_icon_4498347d8908f5fb01eb5edf2d8f8686 = L.divIcon({"className": "empty", "html": "\u003cdiv\u003e\u003cimg src=\"book-open-variant-outline.svg\" height=\"35\" width=\"35\"/\u003e\u003c/div\u003e", "iconAnchor": [15, 15]});
            marker_d22f07e6b7d4128cdb776c42c0bf7338.setIcon(div_icon_4498347d8908f5fb01eb5edf2d8f8686);

        var popup_4da04ad31f973bf8571e17602171f9e2 = L.popup({"maxWidth": "100%"});

                var html_109688bee6a903cb0c7b60eab2c8df3b = $(`<div id="html_109688bee6a903cb0c7b60eab2c8df3b" style="width: 100.0%; height: 100.0%;">Library of Congress</div>`)[0];
                popup_4da04ad31f973bf8571e17602171f9e2.setContent(html_109688bee6a903cb0c7b60eab2c8df3b);

        marker_d22f07e6b7d4128cdb776c42c0bf7338.bindPopup(popup_4da04ad31f973bf8571e17602171f9e2)
        ;

</script>
</html>

Here is the last section of output for the failing version:


            var marker_d68a61b4cefaeb27aa01a913ae70110f = L.marker(
                [38.8886, -77.0047],
                {}
            ).addTo(map_1fa405e7ecfa1525f7efcde55531458f);

        var popup_6e53ecd0bf0bfcc83ca8d766f47677ac = L.popup({"maxWidth": "100%"});

                var html_daad95df46a6fd6a8e27a761c60854c9 = $(`<div id="html_daad95df46a6fd6a8e27a761c60854c9" style="width: 100.0%; height: 100.0%;">Library of Congress</div>`)[0];
                popup_6e53ecd0bf0bfcc83ca8d766f47677ac.setContent(html_daad95df46a6fd6a8e27a761c60854c9);

        marker_d68a61b4cefaeb27aa01a913ae70110f.bindPopup(popup_6e53ecd0bf0bfcc83ca8d766f47677ac)
        ;

</script>
</html>

Expected behavior

Using one variable pointing at an svg icon variable in multiple maps should work. In other words, both maps should work.

The behavior should be the same and correct regardless of whether you specify

folium.Marker(
...    icon=folium.DivIcon(
    icon_anchor=(15, 15),
    html=f"""<div><img src="book-open-variant-outline.svg" height="35" width="35"/></div>""")
).add_to(map_lc)

or

icon=folium.DivIcon(
    icon_anchor=(15, 15),
    html=f"""<div><img src="book-open-variant-outline.svg" height="35" width="35"/></div>""")

folium.Marker(
...    icon=icon
).add_to(map_lc)

Right now, specifying folium.Marker(...icon=icon...) repeatedly will fail, but repeating folium.Marker(...icon=folium.DivIcon(... works.

Environment (please complete the following information):

Additional context Add any other context about the problem here.

Possible solutions List any solutions you may have come up with.

folium is maintained by volunteers. Can you help making a fix for this issue?

Yes, I can try to help. Are these the relevant sections of code? https://github.com/python-visualization/folium/blob/226ba52c7e94850859a8bc6a23d8035e56f3c97e/folium/map.py#L363 https://github.com/python-visualization/branca/blob/f3d866f598a194f9acd30e24e1affe52a32a9f05/branca/element.py#L129

The SVG icon I saved locally and used is: book-open-variant-outline

hansthen commented 7 months ago

@rl-utility-man I managed to reproduce the error. The issue seems to be that there is a parent-child relationship between the Marker and the Icon. Since each child can have only one parent (in this context at least) the code breaks. Are you still willing to help fix this?

A possible solution would be to add a clone() method to Icon and make a clone inside Marker. __init__.

rl-utility-man commented 7 months ago

Thanks @hansthen! Yes, I can take a look at a fix along the lines you recommend and either issue a pull request or circle back with questions. Give me a week or two.

Conengmo commented 6 months ago

Duplicate of https://github.com/python-visualization/folium/issues/744 it seems. I'll leave this one open since we have more recent discussion here.