Black Lives Matter. Please consider donating to Black Girls Code today.

Show and Tell - Dash Leaflet

To enable greater flexibility and a more interactive map experience, a college and I have developed a Dash Leaflet map component. It is a light wrapper around React-Leaflet, with syntax similar to other Dash components and naming conventions following the React-Leaflet API. Not all React-Leaflet component have been implemented, but the most common are in place:

  • Polygon (draw arbitrary polygons on the map)
  • Polyline (draw arbitrary lines on the map)
  • Rectangle (draw rectangles on the map)
  • Circle (draw circles on the map, size in physical units)
  • CircleMarker (draw circles on the map, size in pixels)
  • Marker (draw markers with default or custom icons on the map)
  • Tooltip (show tooltips for any of the objects above)
  • Popup (show popups on click for any of the objects above)
  • TileLayer (show tiles from arbitrary tile providers)
  • WMSTileLayer (similar to tile layers, but more generic)
  • ImageOverlay (draw images on the map)
  • VideoOverlay (play videos on the map)

Dash callbacks can be attached to events emitted by the map, e.g. the on-click event. It is thus easy to achieve an interactive experience. Dash Leaflet is available on pypi,

pip install dash-leaflet

After installing it, you should be able to run the mwe,

import dash
import dash_leaflet as dl
import dash_html_components as html

app = dash.Dash()
app.layout = html.Div([
    dl.Map(style={'width': '1000px', 'height': '500px'}, center=[56.05, 10.25], zoom=10, children=dl.TileLayer())
])

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

More advanced examples can be found in the usage gallery,

7 Likes

Awesome! Would love to see some screenshots from whoever ends up using this!

This looks great! Any idea if you can get the coordinates in the callback? In the Dash mapboxchoropleth if you click, the lat/long coordinates are not returned; we need those for an implementation we are working on.

Yes, that is possible. You can see an example here,

Great, thanks for the quick reply!

Looks great! I tried to run the examples, but I get the error:

Traceback (most recent call last):
  File "../usage_gallery.py", line 5, in <module>
    import dash_leaflet as dl
  File "/Users/benny/bsgip/repos/dash-leaflet/dash_leaflet/__init__.py", line 10, in <module>
    from ._imports_ import *
ModuleNotFoundError: No module named 'dash_leaflet._imports_'

Any idea what’s happening there?

@benn0 - It looks like an issue related to the Python setup. Could you try creating a new project with a new virtual environment, into which you install dash-leaflet and check that the mwe in the initial post works?

Yeah, that works - I think I was messing around with the git repo and it must have polluted my python path. Thanks @Emil.

Great that it works! You should then be able to copy the relevant example(s) from the usage gallery into the new project. Next time i look at the project, i will try to figure out a better way to structure the files and/or add instructions so that the usage gallery “just works” when the project is cloned.

HOW TO UPDATE MARKER POSITION FROM DROPDOWN
PLEASE HELP ME ASAP

If you need to change multiple properties of the marker, you can recreate it through a callback as shown here,

If you only need to move the marker, you can update it’s position property from the callback instead.

I am not able to move the marker after updating the position property in callback.I am sharing the code if I have mistaken somewhere please correct me.

import dash
import dash_leaflet as dl
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input

import pandas as pd

loc=pd.read_csv(“D:\Dash_Arnab##PAGE\in.csv”)
loc1=loc.filter([‘city’, ‘lat’, ‘lng’,‘population’, ‘population_proper’])
app = dash.Dash()

app.layout = html.Div([

                 html.Div([          
                html.H6("Select City:",style={'paddingRight':'30px'}),
                dcc.Dropdown(id='city',
                             options=[{'label':i,'value':i} for i in loc1.city],
                                      value='Mumbai')],
                             style={ 'display': 'inline-block','padding':'100px'}),
                             
                
    
dl.Map(id="map", style={'width': '1000px', 'height': '500px'}, center=[20.5937, 78.9629], zoom=10, children=[
        dl.TileLayer(id="tile"),
        # Marker with tool tip and popup.
        dl.Marker(id='mark',position=[22.56262,88.36304399999999], children=[
            dl.Tooltip("Marker tooltip"),
            dl.Popup([
                html.H1("Marker popup"),
                html.P("with inline html")
            ])
        ])

])
])
#url=“https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
@app.callback(Output(“mark”, “position”),
[Input(“city”, “value”)])

def city_update(sel_city):
loc_city=loc1[loc1.city==sel_city].iloc[:,1:3]

return dl.Marker(position=[loc_city.lat, loc_city.lng])

if name == ‘main’:
app.run_server(debug=False)

Since i don’t have the data, i can’t run the code to examine the exact cause of the error. However, i can see that you are targeting the position property, but returning a Marker object, which is definitely an issue. When you target the position property, you should return the position only, e.g. something like

return [loc_city.lat, loc_city.lng]

https://simplemaps.com/data/in-cities

this is the dataset,I have used in my code.I have tried your solution to return the position but still the marker is not moving and also if you can help me with Tooltip to pop out as city name.

Thank you again for making the python package!
May I ask if it is possible to acquire the user’s location using Leaflet Geo-Location Feature?

Thank you!

Awesome package. I want to know if is there a way to print n markets that are in a pandas dataframe. Thanks!.

I have just added a LocateControl component to enable geolocation, so now it is possible. Here is a small example,

import dash
import dash_html_components as html
import dash_leaflet as dl

app = dash.Dash(external_stylesheets=['https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'])
app.layout = html.Div([
    dl.Map(children=[dl.TileLayer(url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), dl.LocateControl()],
           style={'width': "100%", 'height': "100%"}, center=[55.5, 10.5], zoom=8),
], style={"position": "relative", 'width': '1000px', 'height': '500px'})

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

Thanks! Yes, you can add all the marker that you need. The exact code depends on the structure of you dataframe, but here is a small example,

import dash
import dash_html_components as html
import dash_leaflet as dl
import pandas as pd
import numpy as np

# Create example data frame.
lats = [56, 56, 56]
lons = [10, 11, 12]
df = pd.DataFrame(columns=["lat", "lon"], data=np.column_stack((lats, lons)))

# Create markers from data frame.
markers = [dl.Marker(position=[row["lat"], row["lon"]]) for i, row in df.iterrows()]

# Create example app.
app = dash.Dash(external_stylesheets=['https://codepen.io/chriddyp/pen/bWLwgP.css'])
app.layout = html.Div([
    dl.Map(children=[dl.TileLayer(url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), dl.LayerGroup(markers)],
           style={'width': "100%", 'height': "100%"}, center=[56, 11], zoom=9, id="map"),
], style={'width': '1000px', 'height': '500px'})



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

I have just added a MarkerClusterGroup and a GeoJSON component (version 0.0.12). Furthermore, i have created a documentation page with an interactive example gallery :slight_smile:

2 Likes

This is fantastic. Thank you for your contribution!

1 Like