🏥 🏭 Working on the COVID-19 response in Canada? Plotly & the Canadian government can help you and your organization. Learn more and get in touch.

Mapbox re-centering based on text input not working

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)

I would appreciate any help on this. Thanks in advance!

Hello,
try to remove the Dcc.Loading from your code and don’t wrap the map inside it, that should fix the issue.
hopefully it will work !

That works!!

Thanks a lot for the suggestion.