Search code examples
pythonlayermarkersfolium

Folium 0.11.0 : Keep markers layer in front


I would like to make the markers layer always stay in front, but I can't figure out how to do it.

As soon as I start clicking and unclicking layers in the Layer Control pane, the markers layer disappears behind the choropleth layers.

This is my code:

m = folium.Map([40.4165001, -3.7025599], zoom_start=10, tiles='CartoDB Positron', overlay=True)
# folium.TileLayer('cartodbpositron', overlay=True).add_to(m)


income=folium.Choropleth(
    geo_data=censo,
    data=df1,
    name='Household Income 2016',
    columns=['CDSSCC', 'HouseholdIncome2016'],
    key_on='feature.properties.CDSSCC',
    fill_color='BuGn',
    fill_opacity=1,
    line_opacity=0.2,
    highlight=True,
    legend=False,
).add_to(m)

pop=folium.Choropleth(
    geo_data=censo,
    data=df1,
    name='Population 2016',
    columns=['CDSSCC', 'POB_TOTAL'],
    key_on='feature.properties.CDSSCC',
    fill_color='YlOrBr',
    fill_opacity=1,
    line_opacity=0.2,
    highlight=True,
    legend=False,
).add_to(m)

# add clusters to the map
markers_colors = []
for lat, lon, poi, cluster in zip(buildingsmadrid_merged['Latitude'], buildingsmadrid_merged['Longitude'], buildingsmadrid_merged['Name'], buildingsmadrid_merged['Cluster Labels']):
    label = folium.Popup(str(poi) + ' Cluster ' + str(cluster), parse_html=True)
    puntos=folium.CircleMarker(
        [lat, lon],
        radius=5,
        popup=label,
        tooltip = label,
        color='YlOrBr'[cluster-1],
        fill=True,
        fill_color='YlOrBr'[cluster-1],
        fill_opacity=0.7,
        overlay=False).add_to(m)

folium.LayerControl(position='topright', collapsed=False, autoZIndex=True).add_to(m)

# m.save(os.path.join('choropleth.html'))

m

Thanks for your help


Solution

  • Folium has a solution for that with the method m.keep_in_front.

    If you save a list markers of the CircleMarker objects you can use m.keep_in_front(*markers).
    Note that the order of the items will set their priority, last as top most, though I doubt it matters in your case.


    This solution is currently only working when switching between overlay layers.
    In case of switching between base layers this will not work.

    I've run into a similar problem when trying to display a tooltip while switching between choropleths.

    My setup was a bit different with the choropleth layers having overlay=False since I prefer to switch with radio-buttons, and I only had a single layer to keep in front.

    I've managed to solve this using these 2 sources:
    A similar question about Leaflet
    This issue from the Folium github

    Since I switch base layers I've used the event baselayerchange.

    from branca.element import Element
    
    js_keep_in_front = f"""
        {m.get_name()}.on("baselayerchange", function (event) {{
          {popup.get_name()}.bringToFront();
        }});
    """
    e = Element(js_keep_in_front)
    html = m.get_root()
    html.script.get_root().render()
    # Insert new element or custom JS
    html.script._children[e.get_name()] = e
    

    In case there are many objects like in your example, it's possible to group them into a folium.FeatureGroup as in this example and then keep that single layer in front using the method described.

    Note the use of the get_name method inside the formatted string. This is important since you don't know the names that folium will use for the map/layers.