1

I made a folium map with lot of markers, each of them has a tooltip and a popup filled up with html formatted text. For every position defined by the markers I have additional geo datapoints which I want to display as a line / path / route / AntPath .. whatever. My Problem: The additional line should only appear when you click the marker (--> opens also the popup) or when hovering the marker (--> opens the tooltip).

I have no clue if it even is possible and hope to find some inspiration here

enter image description here

Here is an example which can be used in a jupyter. When you have installed pandas and folium it should work. I added some AntPath, but they never disappear as they are in the map. If you add them to the markercluster, the ants are not moving, if I add them to the popup everything is broken.


# imports
import pandas as pd
import folium
from folium.plugins import HeatMap, AntPath

# functions
def segmrk(latlng, geopath, pop='some text in the popup', tool='tooltiptext<br>in html'):
    # define marker
    style = ['bicycle', 'blue', '#FFFFFF']
    # popup
    iframe = folium.IFrame(pop,  # html style text .. next step: change font!!
                           width=200,
                           height=200
                           )
    fpop = folium.Popup(iframe)
    #AntPath(geopath).add_to(fpop)
    
    # marker
    mrk = folium.Marker(location=latlng,
                        popup=fpop,
                        tooltip=tool,
                        icon=folium.Icon(icon=style[0], prefix='fa',
                                         color=style[1],
                                         icon_color=style[2]
                                         ),
                        )
    return mrk

# sample data
df = pd.DataFrame()
df['geo'] = [[52.5172, 12.1024],[52.5172, 12.2024],[52.5172, 12.3024]]
df['geo_path'] = [[[52.5172, 12.1024],[52.6172, 12.1024],[52.7172, 12.1024],[52.7172, 12.1024]],
                  [[52.5172, 12.2024],[52.6172, 12.2024],[52.7172, 12.2024],[52.7172, 12.2024]],
                  [[52.5172, 12.3024],[52.6172, 12.3024],[52.7172, 12.3024],[52.7172, 12.3024]],
                 ]

# define map

geo_start = [52.5172, 12.2024]
dmap = folium.Map(location=geo_start,
                  zoom_start=10,
                  tiles='OpenStreetMap'
                  )

mapstyle_2 = folium.raster_layers.TileLayer(tiles='CartoDB dark_matter',
                                            name='dark',
                                            overlay=False,
                                            control=True,
                                            show=True,
                                            )
mapstyle_2.add_to(dmap)

# add full screen button
folium.plugins.Fullscreen().add_to(dmap)


# add layercontrol

# markergroups in layercontrol
mc = folium.plugins.MarkerCluster(name='Segment Markers',
                                  overlay=True,
                                  control=True,
                                  show=True,
                                  disableClusteringAtZoom=10
                                  )
mc.add_to(dmap)
mcsub1 = folium.plugins.FeatureGroupSubGroup(mc, name='- markers subcluster',
                                             show=True,
                                             control=False)  # checkmark actually not shown
mcsub1.add_to(dmap)

# the layercontrol itself
lc = folium.map.LayerControl(collapsed=False)
lc.add_to(dmap)

# add geo markers
for _, data in df.iterrows():
    mrk = segmrk(data['geo'], data['geo_path'])
    mrk.add_to(mcsub1)
    # this AntPath should be shown when popup appears OR when hovering marker
    AntPath(data['geo_path']).add_to(dmap)
    
# show map
dmap
flipSTAR
  • 579
  • 1
  • 4
  • 18

1 Answers1

2

If you don't have too many markers, you can try this.

# imports
import pandas as pd
import folium
from folium.plugins import HeatMap
from folium.map import Marker, Template

# sample data
df = pd.DataFrame()
df['geo'] = [[52.5172, 12.1024],[52.5172, 12.2024],[52.5172, 12.3024]]
df['geo_path'] = [[[52.5172, 12.1024],[52.6172, 12.1024],[52.7172, 12.1024],[52.7172, 12.1024]],
                  [[52.5172, 12.2024],[52.6172, 12.2024],[52.7172, 12.2024],[52.7172, 12.2024]],
                  [[52.5172, 12.3024],[52.6172, 12.3024],[52.7172, 12.3024],[52.7172, 12.3024]],
                 ]

# define map

geo_start = [52.5172, 12.2024]
dmap = folium.Map(location=geo_start,
                  zoom_start=10,
                  tiles='OpenStreetMap'
                  )

mapstyle_2 = folium.raster_layers.TileLayer(tiles='CartoDB dark_matter',
                                            name='dark',
                                            overlay=False,
                                            control=True,
                                            show=True,
                                            )
mapstyle_2.add_to(dmap)

# add full screen button
folium.plugins.Fullscreen().add_to(dmap)

# Modify Marker template to include the onClick event
click_template = """{% macro script(this, kwargs) %}
    var {{ this.get_name() }} = L.marker(
        {{ this.location|tojson }},
        {{ this.options|tojson }}
    ).addTo({{ this._parent.get_name() }}).on('click', onClick);
{% endmacro %}"""

# Change template to custom template
Marker._template = Template(click_template)



# add layercontrol

# markergroups in layercontrol
mc = folium.plugins.MarkerCluster(name='Segment Markers',
                                  overlay=True,
                                  control=True,
                                  show=True,
                                  disableClusteringAtZoom=10
                                  )
mc.add_to(dmap)
mcsub1 = folium.plugins.FeatureGroupSubGroup(mc, name='- markers subcluster',
                                             show=True,
                                             control=False)  # checkmark actually not shown
mcsub1.add_to(dmap)


# the layercontrol itself
lc = folium.map.LayerControl(collapsed=False)
lc.add_to(dmap)

# Create the onClick listener function as a branca element and add to the map html
map_id = dmap.get_name()
click_js = f"""function onClick(e) {{                
                    
                                 
                 var coords = e.target.options.pathCoords;
                 //var coords = JSON.stringify(coords);
                 //alert(coords);
                 var ant_path = L.polyline.antPath(coords, {{
                "delay": 400,
                "dashArray": [
                    10,
                    20
                ],
                "weight": 5,
                "color": "#0000FF",
                "pulseColor": "#FFFFFF",
                "paused": false,
                "reverse": false,
                "hardwareAccelerated": true
                }}); 
                
                {map_id}.eachLayer(function(layer){{
                   if (layer instanceof L.Polyline)
                      {{ {map_id}.removeLayer(layer) }}
                      }});
                     
                ant_path.addTo({map_id});
                 }}"""
                 
e = folium.Element(click_js)
html = dmap.get_root()
html.script.add_child(e)


# add geo markers
for index, data in df.iterrows():
    mrk = folium.Marker(data['geo'], pathCoords=data['geo_path'])
    mrk.add_to(mcsub1)
    
# Add leaflet antpath plugin cdn link
link = folium.JavascriptLink("https://cdn.jsdelivr.net/npm/leaflet-ant-path@1.3.0/dist/leaflet-ant-path.js")
dmap.get_root().html.add_child(link)  
# show map

dmap
​
PeaceLeka
  • 1,138
  • 1
  • 9
  • 11
  • This is insanely awesome, thanks!! I will have to try when it breaks because of the marker count. Perhaps I can reduce my markers just to use this cool feature ;-) – flipSTAR Dec 12 '22 at 12:14
  • finally implemented ... no problems with 1500 markers. – flipSTAR Dec 25 '22 at 11:28