I am relatively a newbie to Dash. I am exploring writing a Dash application with a mapbox. At the moment, my layout just has a text box with a dropdown list of valid suggestions and a mapbox. I would like to zoom the mapbox to the country the user has typed in the text box. The zooming should only occur if a valid country name (one from the suggested list) is entered. For partial and invalid entries, the map would default to a default zoom and centering.
The problem I am encountering is that even though I return the correct mapbox paramters in the input callback, the map does not center and zoom to the selected country. But if I delete a character or erase the text in the input text box, then it center and zooms to the previously selected country.
I would really appreciate any help with this! I have attached my code below:
import os
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import io
import requests
COL_COUNTRY='Country'
COL_LATITUDE='Latitude'
COL_LONGITUDE='Longitude'
data = {
COL_COUNTRY: ['USA', 'Japan', 'India', 'Brazil'],
COL_LATITUDE: [37.0902, 36.2048, 20.5937, -14.2350],
COL_LONGITUDE: [-95.7129, 138.2529, 78.9629, -51.9253]
}
df = pd.DataFrame.from_dict(data)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
mapbox_access_token = os.environ.get('MAPBOX_TOKEN')
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
def get_location_suggestions():
suggestions = sorted(df[COL_COUNTRY].unique().tolist())
return suggestions
DEFAULT_LATITUDE=40.0
DEFAULT_LONGITUDE=0.0
DEFAULT_ZOOM=1
def get_latlong_and_zoom(location):
if location is not None and location is not '':
rows = df[df.Country == location]
if rows.shape[0] != 0:
row = rows.iloc[0]
return row[COL_LATITUDE], row[COL_LONGITUDE], 4
return DEFAULT_LATITUDE, DEFAULT_LONGITUDE, DEFAULT_ZOOM
def get_mapbox(center_latitude, center_longitude, zoom):
datamap = dict(
type='scattermapbox',
lat=df['Latitude'],
lon=df['Longitude'],
mode='markers',
marker=go.scattermapbox.Marker(
size=10
),
)
layout = dict(
autosize=True,
hovermode='closest',
geo = dict(
projection = dict(
type = 'equirectangular'
),
),
mapbox=dict(
style='basic',
accesstoken=mapbox_access_token,
bearing=0,
center=dict(
lat=center_latitude,
lon=center_longitude
),
pitch=0,
zoom=zoom,
),
height=600,
width=800
)
fig = dict(
data=[datamap],
layout=layout
)
return fig
def serve_layout():
return html.Div(
[
html.P('Zoom to:'),
html.Datalist(
id='id-list-suggested-inputs',
children=[html.Option(value=word) for word in get_location_suggestions()]
),
dcc.Input(id='id-input-loc',
type='text',
list='id-list-suggested-inputs',
value=''
),
dcc.Loading(
id='id-loading',
children=[
html.Div(
dcc.Graph(
id='id-mapbox',
figure={}
),
id='id-map-container'
),
],
type='circle'
)
]
)
app.layout = serve_layout()
@app.callback(
Output('id-mapbox', 'figure'),
[Input('id-input-loc', 'value')]
)
def location_selected(location):
lat, long, zoom = get_latlong_and_zoom(location)
app.logger.warning(f'location={location}, lat={lat}, long={long}, zoom={zoom}')
return get_mapbox(lat, long, zoom)
if __name__ == '__main__':
app.run_server(debug=False)