✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

Google Map Integration with Dash web framework

In one of the requirement, I need to integrate Google Map with Dash framework and on map click - retrieve lat , long and address (on map click event).

I was able to retrieve the same using google API and flask framework using java script which gives Lat ,Long and Address based on map click event and renders Google Map

Here is the python code used in flask framework :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/map', methods=['GET', 'POST'])
def map():
location = {}
if request.method == "POST":
    location = request.get_json()
    # latitude = location['latitude']
    # longitude = location['longitude']
    print(location);
return render_template('map.html')

if __name__ == '__main__':
app.run(debug = True) # run app

Is there a way to achieve the same in Dash using similar method. Thank you.

You can use mapbox or dash-leaflet for drawing the map, but you will probably need another lib/api (such as google) for reverse geocoding to get addresses.

Thank you @Emil for your reply. I tried the dash leaflet library designed by you & your team as per below code. Must say great add on for Dash framework.
Two issues , if you can suggest the solution - it would be great. In below example Map Event Click is not working on zoom In and Out of the Map. And Is it possible to use mapbox tile here.

Below is complete code which I have tried -

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

# region Example 5

GEOTIFF_ID = "geotiff-id"
GEOTIFF_MARKER_ID = "geotiff-marker-id"
COORDINATE_CLICK_ID = "coordinate-click-id"

def render_example5():
    # Example from https://plot.ly/python/scatter-plots-on-maps/#us-airports-map
    color_domain = dict(domainMin=20, domainMax=40, colorscale=['white', 'orange', 'red'])
    return [
        html.H1("Example 5: GeoTIFFOverlay"),
        html.P("US airports (most arrivals)"),
        dl.Map(style={'width': '1000px', 'height': '500px'},
               center=[-17.782769, -50.924872],
               zoom=3,
               children=[
                   # dl.TileLayer(url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}.png"),
                   dl.TileLayer(url="http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}"),
                   dl.GeoTIFFOverlay(id=GEOTIFF_ID, interactive=True, style={'width': '1000px', 'height': '500px'}),
                   # dl.GeoTIFFOverlay(id=GEOTIFF_ID, interactive=True, url="/assets/tz850.tiff", band=1, opacity=0.9,
                   # **color_domain),
                   dl.Marker(
                       id="marker",
                       interactive=True,
                       position=[-17.782769, -50.924872],
                       draggable=False,
                   ),
                   html.Div(id=GEOTIFF_MARKER_ID)

               ]),

        html.P("Coordinate (click on map):"),
        html.Div(id=COORDINATE_CLICK_ID)
    ]


def register_example5(app):
    @app.callback(Output(GEOTIFF_MARKER_ID, 'children'),
                  [Input(GEOTIFF_ID, 'click_lat_lng_val')])
    def geotiff_marker(x):
        if x is not None:
            lat, lon, val = x
            return dl.Marker(position=[lat, lon],  children=[
                dl.Tooltip('Test')
            ])
        else:
            return None


def register_example1(app):
    @app.callback(Output(COORDINATE_CLICK_ID, 'children'),
                  [Input(GEOTIFF_ID, 'click_lat_lng_val')])
    def click_coord(e):
        if e is not None:
            return json.dumps(e)
        else:
            return "-"


# endregion

app = dash.Dash(__name__, external_scripts=['https://codepen.io/chriddyp/pen/bWLwgP.css'])

# Create layout.
app.layout = html.Div(

    render_example5()
)
# Bind callbacks.

register_example5(app)
register_example1(app)

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

@string - Thanks! The reason that click events are not working in the example is that you have added a geotiff overlay without an url. When the map zooms, leaflet tried to redraw the geotiff layer, but since the url is not set, this operation fails.

Here is a code piece, which does what i guess you were intending (without a geotiff overlay; it seems that you are not using it?),

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

MAP_ID = "map"
MARKER_GROUP_ID = "marker-group"
COORDINATE_CLICK_ID = "coordinate-click-id"

# Create app.
app = dash.Dash(__name__, external_scripts=['https://codepen.io/chriddyp/pen/bWLwgP.css'])
app.layout = html.Div([
    dl.Map(style={'width': '1000px', 'height': '500px'},
           center=[-17.782769, -50.924872],
           zoom=3,
           children=[
               dl.TileLayer(url="http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}"),
               dl.LayerGroup(id=MARKER_GROUP_ID)
           ], id=MAP_ID),
    html.P("Coordinate (click on map):"),
    html.Div(id=COORDINATE_CLICK_ID)]
)


@app.callback(Output(MARKER_GROUP_ID, 'children'), [Input(MAP_ID, 'click_lat_lng')])
def set_marker(x):
    if not x:
        return None
    return dl.Marker(position=x, children=[dl.Tooltip('Test')])


@app.callback(Output(COORDINATE_CLICK_ID, 'children'), [Input(MAP_ID, 'click_lat_lng')])
def click_coord(e):
    if not e:
        return "-"
    return json.dumps(e)


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

You can use any tile provider that you like, mapbox included. Just set the url of the TileLayer accordingly.

1 Like