Non-responsive scatter/bar plots to the Callback function

I am very new to Plotly Dash and I cannot get a hang of the @callback function with multiple inputs linked to two (scatter/bar) graphs.

Dashboard

This is how my dashboard looks like:

Sample Data

This is my sample data:

For some reason, after selecting the inputs and clicking the “Run selection” button, the graphs do not update accordingly. Does anyone know what I am doing wrong? Been reading the documentation and browsing through online examples, but could not figure this one out… I believe something is wrong with the @callback function or the way I defined the data in my function.

Thank you in advance, would highly appreciate every bit of help! :slight_smile:

import pandas as pd
import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State

import plotly.graph_objs as go
import plotly.express as px

# load the data
data = pd.read_excel('example_data.xlsx')
data.fillna(0, inplace=True)
data['Satellite'] = data['Satellite'].astype(int)

#initiate app and set theme
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# navigation bar
navbar = dbc.NavbarSimple(
    children=[
        dbc.NavItem(dbc.NavLink("Page 1", href="#")),
        dbc.DropdownMenu(
            children=[
                dbc.DropdownMenuItem("Page 2", href="#"),
                dbc.DropdownMenuItem("Page 3", href="#"),
            ],
            nav=True,
            in_navbar=True,
            label="More",
        ),
    ],
    brand="Sample Dash Application",
    brand_href="#",
    color="primary",
    dark=True,
)
    
# Construct a dictionary of dropdown values for the days
day_options = []
for day in data['AsofDate'].unique():
    # grab day_options and append to it
    day_options.append({'label':str(day),'value':day})
    
# Construct a dictionary of dropdown values for the portfolios
portfolio_options = []
for portfolio in data['Satellite'].unique():
    portfolio_options.append({'label':str(portfolio),'value':int(portfolio) or 0})
    
# Construct a dictionary of dropdown values for the region
region_options = []
for region in data['Region'].unique():
    region_options.append({'label':str(region),'value':region})
    

###############################################################################
# Filter pane
# Check dash core components at https://dash.plotly.com/dash-core-components
###############################################################################
controls = [
    html.Div(
        [
            'Select Day',
            dcc.Dropdown(
                id='day-dropdown',
                options=day_options,
                value=data['AsofDate'].min(),
                clearable=False
            ),
        ]
    ),
    
    html.Div(
        [
            'Select Portfolio',
            dcc.Dropdown(
                id='portfolio-dropdown',
                options=portfolio_options,
                value=data['Satellite'].min(),
                clearable=False
            ),
        ]
    ),

    html.Div(
        [
            'Select Region',
            dcc.Dropdown(
                id='region-dropdown',
                options=region_options,
                value=data['Region'].min(),
                clearable=False
            ),
        ]
    ),
    
    html.Br(),
    
    dbc.Button("Run selection", color="primary", id="button-submit")
    
]
        
###############################################################################
# Add components here, e.g. graphs
############################################################################### 
   
avp_graph = dcc.Graph(id="avp-graph", style={"height": "500px"})

bar_plot_graph = dcc.Graph(id='bar-plot-graph', style={"height": "500px"})

###############################################################################
# Container
# Check dash core components at https://dash.plotly.com/dash-core-components
###############################################################################    

container = dbc.Container(
    fluid=True,
    children=[
        html.Hr(),
        html.H3('Dashboard'),
        html.Hr(),
        # Bootstrap Layout examples:
        # https://getbootstrap.com/docs/4.0/examples/
        # Bootstrap grid system: https://getbootstrap.com/docs/4.0/layout/grid/
        
        # Under each column (2, 5, 5) you can add components.
        # The left column has a width of 2 and contains the controls only.
        # The middle column has a width of 5 and contains a table and a graph.
        # The right column has a width of 5 and contains a table and a graph.
        dbc.Row(
            [
                dbc.Col(
                    [
                        # See https://dash-bootstrap-components.opensource.faculty.ai/docs/components/card/
                        dbc.Card([
                            dbc.CardHeader("Filter Pane"),
                            dbc.CardBody(controls),
                        ]
                        ),
                    ],
                    sm=2
                ),
                dbc.Col(
                    [
                        html.H5('Column 1'),
                        avp_graph # middle column, graph 1
                    ],
                    sm=5
                ),
                dbc.Col(
                    [
                        html.H5('Column 2'),
                        bar_plot_graph # right column, graph 2
                    ],
                    sm=5
                )
            ]
        )
    ]

)

# Define Layout
app.layout = html.Div([
    navbar,
    container
])

@app.callback(
    [
        Output("avp-graph", "figure"),
        Output("bar-plot-graph", "figure")

    ],
    [Input("button-submit", "n_clicks")],
    [
     State("day-dropdown", "value"),
     State("portfolio-dropdown", "value"),
     State("region-dropdown", "value"),
     ],
)

def run_submit(n_clicks, day, portfolio, region):
   
    # Bar plot
    mask = data["AsofDate"] == day
    bar_plot_graph = px.bar(data[mask], x=data['Region'], y=data['Return'], title='Bar Plot') # barmode="group",
    
    # Scatter Plot
    avp_graph = px.scatter(
        x=data['line_x'],
        y=data['line_y'],
        labels={"x": "x", "y": "y"},
        title=f"Scatter Plot",
    )
    
    return [avp_graph, bar_plot_graph] # return the components in the order of Output Callbacks!!!

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

Answer

I’m not sure how you want your plots to change, but what I can see is:

  • The variables portfolio and region are defined by the state of the dropdown menus, but they are not used in your callback function.
  • The plot avp_graph in the callback function doesn’t depend on any input. Therefore, it makes sense that it remains constant independently of what you select in your dropdown menus.
  • The plot bar_plot_graph only depends on the variable day.