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
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.
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))
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
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.
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))