Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Use one Dropdown (Countries) to change all graphs in my dashboard

I am currently building a dashboard that includes multiple graphs.
The idea is that each graph in the dashboard displays the data for the same country.
For that I want to have a dropdown at the top that selects the country and then all graphs update accordingly.

Is that possible? So far it seems like the regular dropdown function in plotly can only be linked to a single graph.
Are Dropdown Widgets the answer here or will I have to go with a completely different solution to Plotly/Dash?

Thanks in advance.

You can use single dropdown as Input to multiple callbacks, only the Output has to be unique across the app.

So if you have dcc.Dropdown(options=[], value=[], id='country-dropdown') and multiple graphs, i.e.: graph-a, graph-b, graph-c then you can do:

@app.callback(Output('graph-a', 'figure'),
              Input('country-dropdown', 'value'))
def update_graph_a(value):
    # prepare figure_a from value
    return figure_a

@app.callback(Output('graph-b', 'figure'),
              Input('country-dropdown', 'value'))
def update_graph_b(value):
    # prepare figure_b from value
    return figure_b

@app.callback(Output('graph-c', 'figure'),
              Input('country-dropdown', 'value'))
def update_graph_c(value):
    # prepare figure_c from value
    return figure_c

That is great news, then I can really use dash for my project. Thanks for the quick input!

@radekwlsk
Hello There !
I was trying to use your solution since I wanted to do the same thing.
It is working, but I was wondering if I was using the repeated callbacks correctly ?
Is there a way to have a more simple code ?
Thank you for your help.
Below is my code :

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
from plotly import tools
import pandas as pd

df = pd.read_excel('data/test-anon-3IPP.xlsx', index_col='IPP')


app = dash.Dash()

# Added for heroku
server = app.server

# Variable for dropdown
name_options = []
for Nom in df['Nom'].unique():
    name_options.append({'label':Nom,'value':Nom})

app.layout = html.Div([
            # Div for Dropdown
            html.Div([
            dcc.Dropdown(id='name_picker', options=name_options)
            ],style={'width':'40%'}),

            # Div for graph1
            html.Div([
            dcc.Graph(id='graph1')
            ],style={'width':'70%'}),

            # Div for graph2
            html.Div([
            dcc.Graph(id='graph2')
            ],style={'width':'70%'}),

])

@app.callback(Output('graph1','figure'),
            [Input('name_picker','value')])
def update_figure(selected_name):

    # data only for the selected name from the dropdown menu
    filtered_df = df[df['Nom']== selected_name]

    traces = []

    for patient_name in filtered_df['Nom'].unique():
        df_by_name = filtered_df[filtered_df['Nom']==patient_name]

    # Platelets
    traces.append(go.Bar(x = df_by_name['Date de prélèvement'],
                        y = df_by_name['Valeur de résultat du Plaquettes'],
                        name = 'Plaquettes',
                        marker=dict(color='#d87224'))
                )

    return {'data': traces,
            'layout' :go.Layout(title='Plaquettes')
            }

########## Repeated code
@app.callback(Output('graph2','figure'),
            [Input('name_picker','value')])
def update_figure(selected_name):

    # data only for the selected name from the dropdown menu
    filtered_df = df[df['Nom']== selected_name]

    traces = []

    for patient_name in filtered_df['Nom'].unique():
        df_by_name = filtered_df[filtered_df['Nom']==patient_name]

    # Monocytes
    traces.append(go.Bar(x = df_by_name['Date de prélèvement'],
                        y = df_by_name['Valeur de résultat du Monocytes'],
                        name = 'Monocytes',
                        marker=dict(color='red'))
                )

    return {'data': traces,
            'layout' :go.Layout(title='Monocytes')
            }

##########


# Append an externally hosted CSS stylesheet
my_css_url = "https://codepen.io/chriddyp/pen/bWLwgP.css"
app.css.append_css({
    "external_url": my_css_url
})

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

You can:

  1. Put repeated code parts to separate functions.
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
from plotly import tools
import pandas as pd

df = pd.read_excel('data/test-anon-3IPP.xlsx', index_col='IPP')


app = dash.Dash()

# Added for heroku
server = app.server

# Variable for dropdown
name_options = []
for Nom in df['Nom'].unique():
    name_options.append({'label':Nom,'value':Nom})

app.layout = html.Div([
            # Div for Dropdown
            html.Div([
            dcc.Dropdown(id='name_picker', options=name_options)
            ],style={'width':'40%'}),

            # Div for graph1
            html.Div([
            dcc.Graph(id='graph1')
            ],style={'width':'70%'}),

            # Div for graph2
            html.Div([
            dcc.Graph(id='graph2')
            ],style={'width':'70%'}),

])

def gen_traces(selected_name, trace_name, trace_color):
    filtered_df = df[df['Nom']== selected_name]

    traces = []

    for patient_name in filtered_df['Nom'].unique():
        df_by_name = filtered_df[filtered_df['Nom']==patient_name]

    traces.append(go.Bar(x = df_by_name['Date de prélèvement'],
                        y = df_by_name['Valeur de résultat du {}'.format(trace_name)],
                        name = trace_name,
                        marker=dict(color=trace_color))
                )
    return traces


@app.callback(Output('graph1','figure'),
            [Input('name_picker','value')])
def update_figure(selected_name):
    return {'data': gen_traces(selected_name, 'Plaquettes', '#d87224'),
            'layout' :go.Layout(title='Plaquettes')
            }

@app.callback(Output('graph2','figure'),
            [Input('name_picker','value')])
def update_figure(selected_name):
    return {'data': gen_traces(selected_name, 'Monocytes', 'red'),
            'layout' :go.Layout(title='Monocytes')
            }


# Append an externally hosted CSS stylesheet
my_css_url = "https://codepen.io/chriddyp/pen/bWLwgP.css"
app.css.append_css({
    "external_url": my_css_url
})

if __name__ == '__main__':
    app.run_server(debug=True)
  1. Make callback function factory that takes as arguments values that differ between those two callbacks.

Oh I see !
I’ll try that. Many thanks.

@radekwlsk
Your suggestion works perfectly! Thank you very much.
I’m trying to have a logarithmic x axis but I cannot figure out how to do that…

I tried that without success :

#Function generating traces
def gen_traces(selected_name, trace_name, trace_color):
filtered_df = df[df[‘Nom’]== selected_name]

traces = []

for patient_name in filtered_df['Nom'].unique():
    df_by_name = filtered_df[filtered_df['Nom']==patient_name]

traces.append(go.Scatter(x = df_by_name['Date de prélèvement'],
                    xaxis={'type': 'log'},
                    y = df_by_name['Valeur de résultat du {}'.format(trace_name)],
                    name = trace_name,
                    marker=dict(color=trace_color))
            )
return traces

Any idea ?
Phil.