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.
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!
Thanks, @chriddyp!
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?
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!
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