Search code examples
pythondataframeplotlydropdownplotly-dash

I am trying to create a dash app for a Restaurant directory the dropdown filter is work I know but map doesn't update


I have restaurant name, cusines, lat , long as columns. The map I am trying to show on the html page is not updating as per the filter , It shows all the restaurnats.

import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output

import pandas as pd
import plotly.express as px 


app = dash.Dash('app')

df = pd.read_excel('Resturants.XLSX')


app.layout = html.Div([
    html.H1('Resturant map by cusine', style={'text-align': 'center'} ),

    dcc.Dropdown(id='cusine_dd', 
                 options=[{'label': i, 'value': i} for i in df.cusines.unique()],
                  value = 'Chinese',
                 style={'width':'40%'}),
    
    html.Div(id= 'output', children =[] ),

    dcc.Graph(id='mapbycusine', figure={})
])

@app.callback(
    [Output(component_id='output', component_property='children'),
    Output(component_id='mapbycusine', component_property='figure')],
    [Input(component_id='cusine_dd', component_property='value')]
)
def update_figure(input_cusine):
    #cusine_filter = 'All'
    container = f"Currently showing {input_cusine}"
    df_copy = df.copy(deep=True)
    if input_cusine:
        df_copy = df_copy[df_copy['cusines'] == input_cusine]  
    print(df_copy.head())
    fig = px.scatter_mapbox(data_frame=df_copy, lat='Latitude',  lon='Longitude', zoom=3, height=300, hover_data= ['cusines'])
    fig.update_layout(mapbox_style="open-street-map")
    fig.update_layout(height=1000, margin={"r":100,"t":100,"l":100,"b":300})
    return container, fig

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

I am checking every step just to make sure if input and output is working I have used countainers updates on the html page and print the df_copy after filtering data as per the input cusine. The containers give the correct output and the df.copy.head() shows only filltered columns in the console but the map on html dash app is not updating.

I want the map to show the restaurants for just the selected cusine


Solution

  • I cannot reproduce your error, but perhaps some of the steps I took in debugging might prove helpful:

    First, I took the first 100 rows of a restaurant dataset from kaggle, and then randomly assigned three different cuisine types to each unique restaurant name. Then when creating the fig object with px.scatter_mapbox, I passed the cuisine column to the color argument and a mapping between cuisine and color to the color_discrete_map argument so that the marker colors will be different when you select different cuisine types from the dropdown.

    This is the result, with visible changes between the marker locations as well as the marker colors (depending on the dropdown selection). Also, as you mentioned, the print outs of df_copy from inside your update_figure function match the dropdown selections as expected.

    enter image description here

    As far as I can tell, the only thing fundamentally different between your dashboard and mine would be the data that was used. Maybe it is possible that you have a bunch of duplicate rows that span multiple cuisines (i.e. imagine I took a data set of only Mexican restaurants, then duplicated all of the rows but switched the cuisine to Italian – then if you select Mexican or Italian from the dropdown, the result would be the same because you're plotting all of the same latitudes and longitudes in each case so the figure wouldn't appear to change, and you might not catch this from examining the df_copy print outs).

    Can you verify that your data set doesn't contain duplicate latitude and longitude points with different cuisines assigned to the same point?

    import dash
    from dash import dcc
    from dash import html
    from dash.dependencies import Input, Output
    
    import numpy as np
    import pandas as pd
    import plotly.express as px 
    
    
    app = dash.Dash('app')
    
    # df = pd.read_excel('Resturants.XLSX')
    
    ## create a small restaurant dataset similar to yours
    ## downloaded from: https://www.kaggle.com/datasets/khushishahh/fast-food-restaurants-across-us?resource=download
    df = pd.read_csv('Fast_Food_Restaurants_US.csv', nrows=100, usecols=['latitude','longitude','name'])
    df.rename(columns={'latitude':'Latitude', 'longitude':'Longitude'}, inplace=True)
    
    ## randomly assign some cuisine types to unique restaurant names
    unique_names = df['name'].unique()
    np.random.seed(42)
    name_cuisine_map = {
        name:cuisine for name,cuisine in 
        zip(unique_names, np.random.choice(['American','Mexican','Chinese'], size=len(unique_names)))
    }
    cuisine_color_map = {
        'American':'blue',
        'Mexican':'green',
        'Chinese':'red'
    }
    df['cusines'] = df['name'].map(name_cuisine_map)
    df['color'] = df['cusines'].map(cuisine_color_map)
    
    app.layout = html.Div([
        html.H1('Resturant map by cusine', style={'text-align': 'center'} ),
    
        dcc.Dropdown(id='cusine_dd', 
                     options=[{'label': i, 'value': i} for i in df.cusines.unique()],
                      value = 'Chinese',
                     style={'width':'40%'}),
        
        html.Div(id= 'output', children =[] ),
    
        dcc.Graph(id='mapbycusine', figure={})
    ])
    
    @app.callback(
        [Output(component_id='output', component_property='children'),
        Output(component_id='mapbycusine', component_property='figure')],
        [Input(component_id='cusine_dd', component_property='value')]
    )
    def update_figure(input_cusine):
        #cusine_filter = 'All'
        container = f"Currently showing {input_cusine}"
        df_copy = df.copy(deep=True)
        if input_cusine:
            df_copy = df_copy[df_copy['cusines'] == input_cusine]  
        print("\n")
        print(df_copy.head())
        fig = px.scatter_mapbox(data_frame=df_copy, lat='Latitude',  lon='Longitude', zoom=3, height=300, hover_data= ['cusines'], color='cusines', color_discrete_map=cuisine_color_map)
        fig.update_layout(mapbox_style="open-street-map")
        fig.update_layout(height=1000, margin={"r":100,"t":100,"l":100,"b":300})
        return container, fig
    
    if __name__ == '__main__':
        app.run_server(debug=True)