Confused with callback for dropdown linked to graph output

Hello,

I’m new to dash and am struggling to get the dropdown callback to work. I’ve tried each part individually between the graph and the dropdown and both work separately, but when I tie them together with the callback and update function, I only see the dropdown without a graph. Any insight into why would be greatly appreciated.

fig1 = go.Figure(data=go.Histogram(x=df_cl['hvol10'], opacity=0.75, name='10 day realized vol'))
fig2 = go.Figure(data=go.Histogram(x=df_cl['hvol30'], opacity=0.75, name='30 day realized vol'))
fig3 = go.Figure(data=go.Histogram(x=df_cl['hvol90'], opacity=0.75, name='90 day realized vol'))

app = JupyterDash()
app.layout = html.Div([
html.Div([
html.Label('Select Vol Duration'),
    dcc.Dropdown(
        id='vol-dropdown',
        options=[
            {'label': '10 day vol', 'value': '10 day vol'},
            {'label': '30 day vol', 'value': '30 day vol'},
            {'label': '90 day vol', 'value': '90 day vol'}
        ],
        value='10 day vol'
    ),]),
    dcc.Graph(id='vol graph',
                 figure=fig1)
])
@app.callback(
    dash.dependencies.Output('vol graph', 'figure'),
    [dash.dependencies.Input('vol-dropdown', 'value')])

def update_graph(dropdown_value):
    graphs = []
    if dropdown_value == '10 day vol':
        graphs.append(fig1)
    if dropdown_value == '30 day vol':
        graphs.append(fig2)
    if dropdown_value == '90 day vol':
        graphs.append(fig3)
    return graphs

Hi and welcome to Dash!

I didn’t test this, but if all the individual pieces work, then it’s probably not working because you are trying to return the figure as a list.

Since you already have each of the figures defined outside your callback, you could do something simple like this:

def update_graph(dropdown_value):    
    if dropdown_value == '10 day vol':
        return fig1
    if dropdown_value == '30 day vol':
        return fig2
    if dropdown_value == '90 day vol':
        return fig3

Hi @AnnMarieW,

I appreciate your help! I was really struggling with this for too much time. Runs perfectly now. Many thanks. :pray:

Awesome!

I know how frustrating it can be - I’m new at this too. But it’s fun when it all starts working and Dash is so cool :wink:

Hi @AnnMarieW,

Sorry to bother you again, but I was wondering if you could help me with this very similar problem regarding the callback and function. I can’t seem to get the checklist to generate the graphs specified in the function and all that shows up is a blank graph regardless of which checkboxes are checked. The graphs work fine without the checklist too. Any idea what I’m doing wrong?

scatter1 = go.Scatter(x=df_cl['CloseTime'], y=df_cl['hvol10'], opacity=0.75, name='10 day realized vol')
scatter2 = go.Scatter(x=df_cl['CloseTime'], y=df_cl['hvol30'], opacity=0.75, name='30 day realized vol')
scatter3 = go.Scatter(x=df_cl['CloseTime'], y=df_cl['hvol90'], opacity=0.75, name='90 day realized vol')
app1 = JupyterDash(__name__, external_stylesheets=external_stylesheets)
app1.layout = html.Div([
    dcc.Checklist(
        id = 'vol checklist',
        options=[
            {'label': '10 day realized vol', 'value': '10 day realized vol'},
            {'label': '30 day realized vol', 'value': '30 day realized vol'},
            {'label': '90 day realized vol', 'value': '90 day realized vol'}
        ],
        value=['10 day realized vol'],
        labelStyle={'display': 'inline-block'}
),
    dcc.Graph(
        id='vol graph',
    ),
])
@app.callback(
    dash.dependencies.Output('vol graph', 'figure'),
    [dash.dependencies.Input('vol checklist', 'value')])

def update_scatter(checklist_value):
    graphs=[]
    if '10 day realized vol' in checklist_value:
        graphs.append(scatter1)
    if '30 day realized vol' in checklist_value:
        graphs.append(scatter2)
    if '90 day realized vol' in checklist_value:
        graphs.append(scatter3)
    return {'data': graphs,
           'layout': {
                'title': 'realized vol'
            }} 

Hi @faust

Happy to help… yes, it’s a very similar problem. Try solving it in 2 steps, first get it working without trying to update the layout - it’s just like last time. Then try updating the layout. There is a really good tutorial here:

If you are still having trouble after a while, PM me and we can go step by step and you can post your solution back here.

Sorry @faust I didn’t look closely at your code in my first reply, I assumed your scatter1, scatter2 scatter3 were figures again. But I see they are traces, so I think your code sample should work. If you would like to provide a small sample program and sample data that reproduces the problem, I will take another look.

Hi @AnnMarieW,

Thanks for your response. I tried playing with it some more today. I’ve narrowed the problem down to the update function. Specifically, there are no values being generated from the checklist. I’ve tried using ‘value’ and ‘values’ (believe it is just ‘value’ now after recent updates) and can’t seem to generate the checklist values. If I can find a way to generate these values in the update function, then I believe the rest of the code will work. Here are some sample graphs if you get a chance to take a look. Really appreciate your help.

N = 1000
t = np.linspace(0, 10, 100)
y = np.sin(t)
z = np.cos(t)
w = np.tan(t)
trace1 = go.Scatter(x=t, y=y, mode='markers')
trace2 = go.Scatter(x=t, y=z, mode='markers')
trace3 = go.Scatter(x=t, y=w, mode='markers')

#test graph
app1 = JupyterDash()
app1.layout = html.Div([
    dcc.Checklist(
        id = 'vol checklist',
        options=[
            {'label': '10 day realized vol', 'value': '10 day realized vol'},
            {'label': '30 day realized vol', 'value': '30 day realized vol'},
            {'label': '90 day realized vol', 'value': '90 day realized vol'}
        ],
        value=['10 day realized vol'],
        labelStyle={'display': 'inline-block'}
),
    dcc.Graph(
        id='vol graph',
    ),
])
@app.callback(
    dash.dependencies.Output('vol graph', 'figure'),
    [dash.dependencies.Input('vol checklist', 'value')])

def update_scatter(checklist_value):
    graphs=[]
    if '10 day realized vol' in checklist_value:
        graphs.append(trace1)
    if '30 day realized vol' in checklist_value:
        graphs.append(trace2)
    if '90 day realized vol' in checklist_value:
        graphs.append(trace3)
    return {'data': graphs,
           'layout': {
                'title': 'realized vol'
            }} 

Hi @faust

So I copied your code and made it into a regular dash app like what’s in the Dash tutorial (I see you are using Jupyter… I haven’t tried that yet, but it looks pretty cool. How do you like it?)

Your app works like a charm! I made no changes to your layout or callbacks.

Here is the complete code that you can cut and paste:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go

import numpy as np

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

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


N = 1000
t = np.linspace(0, 10, 100)
y = np.sin(t)
z = np.cos(t)
w = np.tan(t)
trace1 = go.Scatter(x=t, y=y, mode="markers")
trace2 = go.Scatter(x=t, y=z, mode="markers")
trace3 = go.Scatter(x=t, y=w, mode="markers")


app.layout = html.Div(
    [
        dcc.Checklist(
            id="vol checklist",
            options=[
                {"label": "10 day realized vol", "value": "10 day realized vol"},
                {"label": "30 day realized vol", "value": "30 day realized vol"},
                {"label": "90 day realized vol", "value": "90 day realized vol"},
            ],
            value=["10 day realized vol"],
            labelStyle={"display": "inline-block"},
        ),
        dcc.Graph(id="vol graph"),
    ]
)


@app.callback(
    dash.dependencies.Output("vol graph", "figure"),
    [dash.dependencies.Input("vol checklist", "value")],
)
def update_scatter(checklist_value):
    graphs = []
    if "10 day realized vol" in checklist_value:
        graphs.append(trace1)
    if "30 day realized vol" in checklist_value:
        graphs.append(trace2)
    if "90 day realized vol" in checklist_value:
        graphs.append(trace3)
    return {"data": graphs, "layout": {"title": "realized vol"}}


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

And for people new to Dash and Plotly, I made another version of your app that uses Graph Objects (go) to create the figure. The Plotly tutorials have more examples using this method than creating a figure as a dictionary. I think it’s helpful to have more examples to see how that looks in Dash.

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go

import numpy as np

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

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


N = 1000
t = np.linspace(0, 10, 100)
y = np.sin(t)
z = np.cos(t)
w = np.tan(t)

app.layout = html.Div(
    [
        dcc.Checklist(
            id="vol checklist",
            options=[
                {"label": "10 day realized vol", "value": "10 day realized vol"},
                {"label": "30 day realized vol", "value": "30 day realized vol"},
                {"label": "90 day realized vol", "value": "90 day realized vol"},
            ],
            value=["10 day realized vol"],
            labelStyle={"display": "inline-block"},
        ),
        dcc.Graph(id="vol graph"),
    ]
)


@app.callback(
    dash.dependencies.Output("vol graph", "figure"),
    [dash.dependencies.Input("vol checklist", "value")],
)
def update_scatter(checklist_value):

    fig = go.Figure()

    if "10 day realized vol" in checklist_value:
        fig.add_trace(go.Scatter(x=t, y=y, mode="markers"))
    if "30 day realized vol" in checklist_value:
        fig.add_trace(go.Scatter(x=t, y=z, mode="markers"))
    if "90 day realized vol" in checklist_value:
        fig.add_trace(go.Scatter(x=t, y=w, mode="markers"))

    fig.update_layout(title_text="realized vol")

    return fig


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

Hi @AnnMarieW,

First of all, thank you very much for running this and making sure it works. When I saw your response, I knew my error had to be something subtle, as there was no traceback, just a blank graph. And that’s when it hit me. I was using two separate apps – one denoted as ‘app’ and the other as ‘app1’. When I copied the code from ‘app’ to ‘app1’, I forgot to change the call back from ‘@app’ to ‘@app1’. :man_facepalming:

Really appreciate you taking the time to help me understand the subtleties and my silly mistakes.

haha - I was once stuck for over a week and my error was a comma :grimacing:

I saw the app1 thing, but I haven’t used JupyterDash() and I thought maybe you had to do it that way