Folium 0.11.0 : Keep markers layer in front

Question:

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

Asked By: Marta Bescansa

||

Answers:

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.

Answered By: Arnon Erez

I had the same issue – that bring to front –> it’s only applied at the time of execution. And z offset wasn’t working for some unclear reason. Here is some tested code to bring items to the front when there are multiple geojson layers in folium:

class Bring2Front(MacroElement):
"""Binds a colormap to a given layer.

Parameters
----------
colormap : branca.colormap.ColorMap
    The colormap to bind.
"""
def __init__(self, fg):
    super(Bring2Front, self).__init__()
    self.fg = fg
    self._template = Template(u"""
    {% macro script(this, kwargs) %}
        {{this._parent.get_name()}}.on('baselayerchange', function (event) {
            {{this.fg.get_name()}}.bringToFront();
            });
        {{this._parent.get_name()}}.on('layeradd', function (event) {
            {{this.fg.get_name()}}.bringToFront();
            });
        {{this._parent.get_name()}}.on('layerremove', function (event) {
            {{this.fg.get_name()}}.bringToFront();
            });
    {% endmacro %}
    """)

You can then add this macro to bring the feature group forward as follows:

m.add_child(Bring2Front(fg))
Answered By: Noe
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.