Search code examples
pythonplotlyplotly-dashplotly-python

Having issues troubleshooting app.layout and callbacks


I'm trying to display a scatterplot with trend lines that also has a drop-down menu. I'm still learning Dash-Plotly and am having trouble debugging what I did wrong. I've used the dash tutorial and a lot of other StackOverflow posts but I'm not getting what I need to do. I thought I did all my callbacks correctly and set up my app.layout correctly.

My Code:

app.layout = html.Div([
    html.H1('King County Housing Data: 1900-2015', style = {'text-align': 'center'}),

    dcc.Dropdown(id='grade-selector',  # geo-dropdown is what you'll see with the drop down
                 # Create a loop that pulls the unique values from the grade column and it values for the dropdown
                 options=[{'label': i, 'value': i}  # Creates the unique properties for the dropdown
                          for i in df['grade'].unique()],
                 value=7,
                 multi = False,
                 style={'width', '40%'}),  # value = default value for the dropdown)
    html.Div(id='output-container'),
    dcc.Graph(id='grade-price')
])



# Set up the callback functions: This is what connects all the figures and things together
@app.callback(
    # A call back needs two things, a input and an output
    [Output(component_id='output-container', component_property='children'),
     Output(component_id='grade-price', component_property='figure')],
    [Input(component_id='grade_selector', component_property='value')]
)

# Connecting Plotly graphs to Dash Components:

# **NOTE** Your arguments are tied to the number of inputs that you have. If you have only one input, then you'll
# Only have one argument.

def gupdate_output_div(grade_selector): # The argument refers to the Input's Component Property.
    print(grade_selector)
    print(type(grade_selector))
    container = 'The grade the user selected was {}'.format(grade_selector)

    # Creating a copy of the dataframe, not smart to mess around with the primary DataFrame in here
    dff = df.copyy()
    dff = dff[dff['grade']== grade_selector] # You are sorting the DF by what the user has selected

    # Plotly Express:
    fig = px.scatter(dff, x='sqft_living', y='price', color='view', marginal_y='violin',
                     marginal_x='box', trendline='ols', template='plotly_dark')

    return container, fig # What you return here is actually going to go into the output!
# If you have two Outputs, you're returning two things, three Outputs --> three returns


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

My Data:

display(df[['price','sqft_living','grade']].head())
       price  sqft_living  grade
0  13.180632     7.501082      7
1  13.515081     8.384804      8
2  13.345507     7.306531      7
3  13.296317     7.319865      7
4  13.091904     7.244228      7

Solution

  • The key issues are:

    1. As @r-beginners mentioned, there is a typo in dff = df.copyy() which should be replaced by dff = df.copy().

    2. The id of the dropdown that you defined in the layout is 'grade-selector', but in the callback you are using 'grade_selector'.

    3. The style property of the dropdown is defined incorrectly as it needs to be a dictionary, i.e. you need to replace {'width', '40%'} with {'width': '40%'}.

    4. You are using the 'view' column to define the colorscale for the graph, but it's not clear if you actually have this column in your data frame (it's not included in the df shown in your question above).

    These issues have been fixed in the code below:

    import pandas as pd
    import dash
    import dash_html_components as html
    import dash_core_components as dcc
    from dash.dependencies import Input, Output
    import plotly.express as px
    
    # data
    df = pd.DataFrame({
        'price': {0: 13.180632, 1: 13.515081, 2: 13.345507, 3: 13.296317, 4: 13.091904},
        'sqft_living': {0: 7.501082, 1: 8.384804, 2: 7.306531, 3: 7.319865, 4: 7.244228},
        'grade': {0: 7, 1: 8, 2: 7, 3: 7, 4: 7}
    })
    
    # app set-up
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    server = app.server
    
    # app layout
    app.layout = html.Div([
    
        html.H1('King County Housing Data: 1900-2015', style={'text-align': 'center'}),
    
        dcc.Dropdown(id='grade-selector',
                     options=[{'label': i, 'value': i} for i in df['grade'].unique()],
                     value=7,
                     multi=False,
                     style={'width': '40%'}),
    
        html.Div(id='output-container'),
    
        dcc.Graph(id='grade-price')
    
    ])
    
    # app callbacks
    @app.callback(
        [Output(component_id='output-container', component_property='children'),
         Output(component_id='grade-price', component_property='figure')],
        [Input(component_id='grade-selector', component_property='value')]
    )
    
    def gupdate_output_div(grade_selector):
    
        container = 'The grade the user selected was {}'.format(grade_selector)
    
        dff = df.copy()
        dff = dff[dff['grade'] == grade_selector]
    
        fig = px.scatter(dff, x='sqft_living', y='price', marginal_y='violin', marginal_x='box', trendline='ols', template='plotly_dark')
    
        return [container, fig]
    
    if __name__ == '__main__':
        app.run_server(debug=False, host='127.0.0.1')