Dash Leaflet - Hover on Geojson

Hello,

I am using Dash Leaflet and trying to set up tooltips on a geojson feature that return the site name based upon its properties. The geojson data contains lots of polygons so the name returned should be the polygon that is hovered over.

I am using the below code and use the thread below to implement - however, as long as my mouse is hovering over the polygon, the callback will keep firing many times rather than just once and returning the name. Is there a way to solve this or a better method?

dl.GeoJSON(
id=‘geojson-layer’,
data=geojson_data,
children=[dl.Tooltip(id=“geojson-tooltip”)],
style={‘color’: ‘purple’, ‘fillOpacity’: 0.8, ‘weight’: ‘2’, ‘z-index’: ‘1000’},
hoverStyle=dict(weight=5, color=‘#666’, dashArray=‘’)
)

@dash.callback(
Output(‘geojson-tooltip’, ‘children’),
Input(‘geojson-layer’, ‘hoverData’),
)
def region_layer_hover(feature):
if feature and ‘properties’ in feature:
return f"{feature[‘properties’][‘name’]}"
return None

Did you try adding a tooltip property? Like in this example,

https://www.dash-leaflet.com/docs/geojson_tutorial#a-feature-filtering

1 Like

Thank you Emil - as in the example, when including the the tooltip reference in the geojson then it appears on hover :slight_smile:

Thank you for building this amazing library and for always being so responsive :smiley:

1 Like

@Emil, do you know if there is a way to add the ‘sticky’ property to a tooltip when doing this? I’m displaying tooltips for a GeoJson polygon layer, and would prefer the tooltip position to follow the mouse.

It’s a straightforward set of world boundaries, and I get some slightly weird tooltip placement with the defaults. (The mouse position was near the western end of Russia when I did this screengrab)

His does your current code look? What did you try so far? :slight_smile:

The minimal code is very straightforward:

    ...
    dl.GeoJSON( url="/assets/world_bdys_filtered.geojson")
    ...

… where the dataset is the Natural Earth world_boundaries_50m.geojson dataset with a “tooltip” column added.

If it was a points dataset I think I could add the sticky attribute using pointToLayer, but I don’t see any equivalent for polygons.

I can’t see a way of using children=[dl.Tooltip(sticky=True)], since I don’t know how to tie the country names from the dataset into that

Except that I’ve just found your post at How to add popup and marker information to GeoJSON module · Issue #37 · emilhe/dash-leaflet · GitHub, which looks like it should give a way of doing it that will work with polygons, and is probably my next thing to try

I’ve realised that what I called the ‘weird’ tooltip placement happens only when the features are MultiPolygons. If Multipolygons are exploded into multiple records with Polygon geometry, then the tooltip always appears at the centroid of the polygon that the mouse is hovering over.

If I can get my other functionality working with a Polygon file, this looks like it gives a good enough solution without having to use sticky tooltips

I’ve put a complete working example now at GitHub - dh3968mlq/dash-leaflet-mwe: Mininum working example(s) for Dash Leaflet - showing more of the kind of thing I’m trying to do. (Code also below, data on the repo).

I’m showing clustered markers for countries, and can customise the icon etc. for those. At the same time I’d like to show a tooltip when I hover over a country, and hope to customise the appearance of those, and hopefully also to filter them so that the hover tooltips don’t duplicate visible marker labels.

from dash import Dash
import dash_leaflet as dl
from dash_extensions.javascript import assign

draw_marker = assign(
    """
        function(feature, latlng){
        const flag = L.icon({iconUrl: `assets/fluent-emoji-flat--diamond-with-a-dot.svg`, iconSize: [18, 18]});
        marker = new L.marker(latlng, { icon: flag }); 
        marker.bindTooltip("My Label", {permanent: true, className: "my-label", offset: [0, 0] });
        return marker;
    }"""
)

app = Dash(__name__) 
app.layout = dl.Map(
    children=[
        # Use /assets/world_bdys.geojson for multipolygons - shows unexpected tooltip location
        # Use /assets/world_bdys_exploded.geojson for polygons - tooltip located at polygon centroid
        dl.GeoJSON(url="/assets/world_bdys_exploded.geojson"),
        dl.GeoJSON(
            url="/assets/world_centroids.geojson", 
            cluster=True,
            pointToLayer=draw_marker,
            superClusterOptions={"radius": 100}
        )
    ],
    center=[56,10], zoom=2, style={'height': '50vh'}
)
if __name__ == "__main__":
    app.run()

That looks like a good solution. If you want to realise your initial idea, you could bind the popup explicitly using the onEachFeature handle,

This is what is going on “under the hood”, when you add a tooltip property. However, by doing it explicitly as the example above, you should be able to customize the tooptip as you like - for example making it sticky. You can see all options here,

https://leafletjs.com/reference.html#tooltip

2 Likes

Thanks - that approach works perfectly.

1 Like