Show and Tell - Dash Leaflet

Yes, that is possible. The Marker itself exposes an n_clicks property (similar to a button) that could be used.

I have just (0.0.21) added a new SuperCluster component. Like the MarkerClusterGroup it performs marker clustering, but while the MarkerClusterGroup can only handle a few thousand markers, the SuperCluster component can handle millions. So if you have lots of markers, this is the component for you.

1 Like

Can you just give me a clue how to put the marker in the ap…layout in the code in your reply?
I tried many things, but can’t seem to work it out.
Many thanks

Hi @Emil, How can i pass in an access token in a dl.WMSTileLayer call?
I assigned what I think to be the token to session[‘user’] and passed in dl.WMSTileLayer call like this access_token={session[‘user’][‘sub’]}. no luck

that supercluster feature is awesome @Emil!

2 Likes

Thanks, @chriddyp! :smiley:

1 Like

It might depend on the use case, but i guess the most common approach would be to embed it in the url.

Tried many things for many hours, but still can’t work it out. I just
need one clue for the layout and the callback decorator to get myself
going again.
Since the markers are made in the callback function by users clicking on
the map, n_clicks in the decorator does not give me any integers.
Instead, I get errors like “Cannot read property ‘removeLayer’ of
undefined”. Same error for addLayer. Does anybody have a tip? Much
appreciated

It seems that you are trying to target dynamically generated components in a callback. In Dash, this is possible using pattern matching callbacks. Here is an example,

import dash
import dash_html_components as html
import dash_leaflet as dl

from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output, State, ALL

app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([
    dl.Map([dl.TileLayer(), dl.LayerGroup(id="container", children=[])], id="map", center=(56, 10), zoom=10,
           style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"}),
    html.Div(id="log")
])


@app.callback(Output("container", "children"), [Input("map", "click_lat_lng")], [State("container", "children")])
def add_marker(click_lat_lng, children):
    children.append(dl.Marker(position=click_lat_lng, n_clicks=0, id=dict(tag="marker", index=len(children))))
    return children


@app.callback(Output("log", "children"), [Input(dict(tag="marker", index=ALL), "n_clicks")])
def marker_click(n_clicks):
    triggered = dash.callback_context.triggered
    # Don't react of marker add event.
    if len(triggered) > 1 or (len(triggered) == 1 and triggered[0]['value'] == 0):
        raise PreventUpdate
    # Write to log div which marker was clicked.
    return f"You clicker marker with id {triggered[0]['prop_id'].split('.')[0]}", n_clicks


if __name__ == '__main__':
    app.run_server()

Many thanks! I just changed the index for id and increment the id number with every marker.
The reason is that I also delete markers when clicked upon.
So now, by clicking on the map you get a customised marker.
By dragging the marker stays on the map.
By clicking on a marker the marker will be deleted.
If the marker was moved previously, it needs a double click to delete it.
I will use this for users to choose formal taxi stops.

By dragging you get a marker move (position) signal first and then straight on a marker click (click_lat_lng) signal.
I could not work out how to dismiss the second trigger. If they would be combined in one trigger list (dash.callback_context.triggered), I could choose the right trigger from the list.
My code is somewhat clumsy, I am not a programmer. If anybody is interested, I can post it here.

It would be helpful for identifying your issue, if you posted the code. Ideally, with some some comments on where/what specifically goes wrong. It the code is long, it might be better to post it in a separate thread, i.e. as a separate question.

By any chance, could the Choropleth component be on the implementation roadmap?
Struggling to make a dashboard based on a GeoDataFrame of LineStrings (as explained here: https://anitagraser.com/2019/10/31/interactive-plots-for-geopandas-geodataframe-of-linestrings/)

Currently, a GeoJSON component is available, but i have considered to create a separate Choropleth component. Do you need any particular functionality?

1 Like

Thanks for the quick and useful answer, it works by simply feeding the GeoDataFrame’s __geo_interface__ to the GeoJSON component. Cheers

Thanks, I will do I bumped into something else. Can anybody help me with this.
Is it possible to fire a callback based on clicks on defined markers in another callback?

The markers are made in a callback and placed in layergroup container2.
So something like this, albeit not working:
@app.callback(Output(“container3”, “children”),[Input(marker.id,“n_clicks”) for marker in “container2”])

Found it.
It is well documented at
https://dash.plotly.com/pattern-matching-callbacks
I just needed to make a dictionary for the ID, with keys type and index.
So nice that this is working!

1 Like

Quick question regarding the Colorbar component.

I was planning to apply a style to features using branca (colormap.LinearColormap), whereby cm(val) returns a hex. Should the branca cmap be fed to the dash-leaflet Colobar, or should I use Colorbar from the start within my style function in order to display the legend? If so, how do we retrieve the hex codes from a continuous Colorbar?

Hi Emil,

Any plans to implement L.canvas? it seems that preferCanvas does not do much now, so I was planning to create markers and force them to use the same canvas as in Leaflet.

Best,
Farry

Could marker clustering fit your usecase?

No it does not as I need to show “all” the circlemarker “all” the time (no clustering at any zoom level) . This is similar to the main use case for Scattermapbox with ~15k circles…

Farry