[SOLVED] ScatterMapBox Zoom Not Working After updating Input/Dropdown DCC

Hello,

I am able to zoom in and out using my mouse when the graph is loaded as it is. However, when I update the scattermapbox graph with either an Input/Dropdown/Slider component, I am unable to zoom in any more. I am still able to pan or adjust the pitch of the scattermapbox though.

Is this issue a bug or rather an issue with my code? I can’t be sure but I know another person experiencing the same thing as I do…

Try it here:
https://dash-yelp.herokuapp.com/

(EDIT: Link is not working properly as intended. I will try to create a GIF or something similar to visualize this problem more clearly)

My code for that plot is as follows:

df = pd.read_csv("mainplot.csv")

#SELECTING unique cities,categories, and stars for dropdown menu and slider
city_indicators = df['city'].unique()
star_rating_indicators = sorted(df['stars'].unique())
category_indicators = sorted(df['categories'].unique())

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
app.layout = html.Div(
    html.Div([
        html.Div(
            [
                html.H1(children='Yelp Interactive Visualization',
                        className='nine columns'),
                html.P('An interactive visualization for the top 15 most reviewed cities in Yelp',
                        className='nine columns')
            ], className="row"
        ),
            
        #Dropdown menu and slider
        html.Div(
            [dcc.Store(id='memory-output',storage_type='session'),
                #City Dropdown    
                html.Div(
                    [   
                        html.P('Choose City:',
                               style = {'fontWeight':600}
                        ),
                        
                        dcc.Dropdown(id='city-column',
                                     options=[{'label': i, 'value': i} for i in city_indicators],
                                     value='Greater Toronto'
                        ),
                    ],
                    className='six columns',
                    style={'margin-top': '10'}
                ),
                 
                #Star Ratings Slider 
                html.Div(
                    [
                        html.P('Star Ratings:',
                               style = {'fontWeight':600}
                        ),
                        
                        dcc.RangeSlider(id='star-slider',
                                     marks={i: str(i)+' Star' for i in star_rating_indicators},
                                     min = 1,
                                     max = 5,
                                     step = 0.5,
                                     updatemode="drag",
                                     value=[1, 5]
                        ),
                    ],
                    className='two columns',
                    style={'margin-top': '0'}
                ),
                    
                #Category Dropdown 
                html.Div(
                    [
                        html.P('Category:',
                               style = {'fontWeight':600}
                        ),
                        
                        dcc.Input(id='category-column',
                                  placeholder= "Enter a category.. e.g., desserts",
                                  type="text",
                                  value="dessert"
                                     
                        ),
                    ],
                    className='two columns',
                    style={'margin-top': '0'}
                ),
            ], className="row"
        ),
        
     
        html.Div (
            [
                #Map
                html.Div(
                    [
                    html.Div([
                           dcc.Graph(
                                    id='map-figure'
                           )
                        ], className= 'six columns',  style={'margin-top': '0'})
                    ]
                ),
                    
               #DataTable
               html.Div(
                    [
                    dt.DataTable(
                        id='datatable',
                        data=df.to_dict('rows'),
                        columns=[
                                {"name": i, "id": i, "deletable": True} for i in df[['name','stars','review_count','address','categories']].columns
                        ],
                        
                        style_header={'backgroundColor': 'rgb(30, 30, 30)'},
                        
                        style_cell={'textAlign': 'left', 
                                'minWidth': '160px', 'width': '160px', 'maxWidth': '160px',
                                'whiteSpace': 'normal',
                                'backgroundColor': 'rgb(50, 50, 50)',
                                'color': 'white'
                            },
                        css=[{
                                'selector': '.dash-cell div.dash-cell-value',
                                'rule': 'display: inline; white-space: inherit; overflow: inherit; text-overflow: inherit;'
                            }],
                                    
                        style_cell_conditional=[
                            {'if': {'column_id': 'name'},
                             'width': '30%',
                             'textAlign': 'left'},
                            {'if': {'column_id': 'stars'},
                             'width': '15%',
                             'textAlign': 'left'},
                            {'if': {'column_id': 'review_counts'},
                             'width': '15%',
                             'textAlign': 'left'},
                            {'if': {'column_id': 'address'},
                             'width': '20%',
                             'textAlign': 'left'},
                            {'if': {'column_id': 'categories'},
                             'width': '20%',
                             'textAlign': 'left'},
                        ],
                                
                       style_table={
                            'maxHeight': '500',
                            'overflowY': 'scroll',
                            'overflowX': 'scroll'
                        },
                               
                        pagination_mode="fe",
                                pagination_settings={
                                    "displayed_pages": 1,
                                    "current_page": 0,
                                    "page_size": 15,
                                },
                                        
                        navigation="page",
                        n_fixed_rows=1,
                        sorting=True,
                        sorting_type="multi",
                        selected_rows=[]
                    ),
                ],className="six columns", style={'margin-top': '20'}
                )
    ], className="row"
    )

]))
                    
@app.callback(dash.dependencies.Output('datatable', 'data'),
             [dash.dependencies.Input('city-column', 'value'),
              dash.dependencies.Input('category-column', 'value'),
              dash.dependencies.Input('star-slider', 'value')])
                    
def update_rows(selected_city,selected_category,star):
    filtered = df.loc[ ( df.city == selected_city ) &
                  ( df.categories.str.contains(selected_category)) &
                  ( df['stars'].between(star[0],star[1],inclusive=True) ) 
              ]
    return filtered.to_dict('rows')
                        
@app.callback(
    dash.dependencies.Output('map-figure', 'figure'),
    [dash.dependencies.Input('city-column', 'value'),
     dash.dependencies.Input('category-column', 'value'),
     dash.dependencies.Input('star-slider', 'value')])

def update_mapfigure(selected_city,selected_category, star):
    
    
    filtered_df = df.loc[ ( df.city == selected_city ) &
                          ( df.categories.str.contains(selected_category)) &
                          ( df['stars'].between(star[0],star[1],inclusive=True)) 
                  ]
    my_text=['Name:' + name +'<br>Stars:' + str(stars) +'<br>Number of Reviews:' + str(revs)
    for name, stars, revs in zip(list(filtered_df['name']), 
                                 list(filtered_df['stars']),
                                 list(filtered_df['review_count'])
                                )
            ] 
    
    trace = [go.Scattermapbox(lat=filtered_df['latitude'],
                              lon=filtered_df['longitude'],
                              text=my_text,
                              mode='markers',
                              marker=dict(size=6, color='gold', opacity=.5)
            )]
                
    layout_map = dict(
            #autosize=True,
            hovermode='closest',
            width=720,
            height=580,
            margin=dict(l=0, r=0,b=0, t=0
                   ),
            plot_bgcolor="#191A1A",
            paper_bgcolor="#020202",
            mapbox=dict(
                    accesstoken=mapbox_access_token,
                    bearing=50,
                    center=dict(
                            lat=float(filtered_df.city_lat.values[0]),
                            lon=float(filtered_df.city_long.values[0]),
                            ),
                    pitch=50,
                    zoom=12,
                    style=map_style,
                    )
                )
    return {
        'data': trace,
        'layout': layout_map
    }

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

Hi @Des: I am also experiencing this issue and googling the problem brought me to your question.

My scattermapbox doesn’t use bearing or pitch but upon filtering my dcc.Dropdown (with multi=True) the view snaps to the default level and stops working.

Also like you, panning remains functional but zoom stops working until I refresh the page.

plotly version 3.6.1

1 Like

Hi @jb23626436,

Im glad I share the same problem with at least 2 more other person. I just updated my original post to include a GIF of the problem. Let me know if yours is similar. In my gif, you can see that after I update my map using the Input component, the zoom doesn’t work as intended anymore

1 Like

Hi @Des and @jb23626436,

I had this problem too, and solved it by explicitly defining scrollZoom to be true when I first declare the dcc.Graph object.

graph = dcc.Graph(
id=‘graph-geo’,
config={
‘scrollZoom’: True
}

(Apologies for the bad formatting - I created an account just to comment on this thread, so I’m still figuring out how posting works).

5 Likes

@GW2019 - thank you! That did the trick.

Hey @GW2019

That worked! Thank you so much! I hope this will help others too

Thanks for the report and digging everyone! This is actually two intertwined bugs, one in dcc and one in plotly.js. We’ll try to get these resolved ASAP

2 Likes

@GW2019 it works! :smiley: