Properly Setting Up Callbacks For Dynamic Dropdowns Plotly Dash
I am trying to create a Dash dashboard where dropdown options in one box are dependent on the previous dropdown selection. The data consists of two dictionaries, with two keys each
Solution 1:
I haven't been able to figure out why your code fails. But I've been putting together an example that I think will come close to what you're looking for here. It builds on an example from the plotly docs, and so has a bit different layout from what you've got in your question. The main take-away is that three sets of radio buttons will let you:
- select a weight:
['prod', 'area']
, - which in turn will define the options in another callback:
['2m_temp_prod', 'total_precip_prod']
or['2m_temp_area', 'total_precip_area']
. - And you're also able to select produce
['corn', 'soybeans']
It's very possible that I've misunderstood the logic of what you want to achieve here. But just give me some feedback along the way and we can work out the details.
Dash app for selection DF: prod | Crops: corn | Column: 2m_temp_prod
Dash app for selection DF: area | Crops: soybeans | Column: total_precip_area
Complete code:
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
# datafrom jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd
from pandas import Timestamp
import numpy as np
# data ##########################################################################
index1= [1,2,3,4]
columns1 =['time', '2m_temp_prod' , 'total_precip_prod']
index2= [1,2,3,4]
columns2 = ['time', '2m_temp_area', 'total_precip_area']
df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,
data= np.random.randn(len(index1),len(columns1))).cumsum(),
'soybeans' : pd.DataFrame(index=index1, columns = columns1,
data= np.random.randn(len(index1),len(columns1))).cumsum()}
df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,
data= np.random.randn(len(index2),len(columns2))).cumsum(),
'soybeans' : pd.DataFrame(index=index2, columns = columns2,
data= np.random.randn(len(index2),len(columns2))).cumsum()}
# mimic data properties of your real world data
df_vals_prod['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['corn'].set_index('time', inplace = True)
df_vals_prod['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['soybeans'].set_index('time', inplace = True)
df_vals_area['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['corn'].set_index('time', inplace = True)
df_vals_area['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['soybeans'].set_index('time', inplace = True)
# dash ##########################################################################
app = JupyterDash(__name__)
# weighting
all_options = {
'prod': list(df_vals_prod[list(df_vals_prod.keys())[0]].columns),
'area': list(df_vals_area[list(df_vals_prod.keys())[0]].columns)
}
app.layout = html.Div([
dcc.RadioItems(
id='produce-radio',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value='prod'
),
html.Hr(),
dcc.RadioItems(
id='crop-radio',
options=[{'label': k, 'value': k} for k inlist(df_vals_prod.keys())],
value=list(df_vals_prod.keys())[0]
),
html.Hr(),
dcc.RadioItems(id='columns-radio'),
html.Hr(),
html.Div(id='display-selected-values'),
dcc.Graph(id="crop-graph")
])
# Callbacks ###################################################################### Weighting selection.@app.callback(# Dataframe PROD or AREA
Output('columns-radio', 'options'),
# layout element: dcc.RadioItems(id='produce-radio'...)
[Input('produce-radio', 'value')])defset_columns_options(selected_produce):
varz = [{'label': i, 'value': i} for i in all_options[selected_produce]]
print('cb1 output: ')
print(varz)
return [{'label': i, 'value': i} for i in all_options[selected_produce]]
# Columns selection@app.callback(
Output('columns-radio', 'value'),
# layout element: dcc.RadioItems(id='columns-radio'...)
[Input('columns-radio', 'options')])defset_columns(available_options):
return available_options[0]['value']
# Crop selection@app.callback(
Output('crop-radio', 'value'),
# layout element: dcc.RadioItems(id='columns-radio'...)
[Input('crop-radio', 'options')])defset_crops(available_crops):
return available_crops[0]['value']
# Display selections in its own div@app.callback(# Columns 2m_temp_prod, or....
Output('display-selected-values', 'children'),
[Input('produce-radio', 'value'),
Input('crop-radio', 'value'),
Input('columns-radio', 'value')])defset_display_children(selected_produce, available_crops, selected_column):
return('DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column)
# Make a figure based on the selections@app.callback(# Columns 2m_temp_prod, or....
Output('crop-graph', 'figure'),
[Input('produce-radio', 'value'),
Input('crop-radio', 'value'),
Input('columns-radio', 'value')])defmake_graph(selected_produce, available_crops, selected_column):
# data source / weightingif selected_produce == 'prod':
dfd = df_vals_prod
if selected_produce == 'area':
dfd = df_vals_area
# plotly figure
fig = go.Figure()
fig.add_trace(go.Scatter(x=dfd[available_crops].index, y=dfd[available_crops][selected_column]))
fig.update_layout(title=dict(text='DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column))
return(fig)
app.run_server(mode='inline', port = 8077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
Edit 1 - Dropdown menus.
All you have to do to get the desired dropdown buttons is to change each
dcc.RadioItems()
to
dcc.Dropdown()
Now you'll get:
Complete code:
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
# datafrom jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd
from pandas import Timestamp
import numpy as np
# data ##########################################################################
index1= [1,2,3,4]
columns1 =['time', '2m_temp_prod' , 'total_precip_prod']
index2= [1,2,3,4]
columns2 = ['time', '2m_temp_area', 'total_precip_area']
df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,
data= np.random.randn(len(index1),len(columns1))).cumsum(),
'soybeans' : pd.DataFrame(index=index1, columns = columns1,
data= np.random.randn(len(index1),len(columns1))).cumsum()}
df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,
data= np.random.randn(len(index2),len(columns2))).cumsum(),
'soybeans' : pd.DataFrame(index=index2, columns = columns2,
data= np.random.randn(len(index2),len(columns2))).cumsum()}
# mimic data properties of your real world data
df_vals_prod['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['corn'].set_index('time', inplace = True)
df_vals_prod['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['soybeans'].set_index('time', inplace = True)
df_vals_area['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['corn'].set_index('time', inplace = True)
df_vals_area['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['soybeans'].set_index('time', inplace = True)
# dash ##########################################################################
app = JupyterDash(__name__)
# weighting
all_options = {
'prod': list(df_vals_prod[list(df_vals_prod.keys())[0]].columns),
'area': list(df_vals_area[list(df_vals_prod.keys())[0]].columns)
}
app.layout = html.Div([
dcc.Dropdown(
id='produce-radio',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value='area'
),
# dcc.Dropdown(# id='produce-radio',# options=[# {'label': k, 'value': k} for k in all_options.keys()# ],# value='prod',# clearable=False),
html.Hr(),
dcc.Dropdown(
id='crop-radio',
options=[{'label': k, 'value': k} for k inlist(df_vals_prod.keys())],
value=list(df_vals_prod.keys())[0]
),
html.Hr(),
dcc.Dropdown(id='columns-radio'),
html.Hr(),
html.Div(id='display-selected-values'),
dcc.Graph(id="crop-graph")
])
# Callbacks ###################################################################### Weighting selection.@app.callback(# Dataframe PROD or AREA
Output('columns-radio', 'options'),
# layout element: dcc.RadioItems(id='produce-radio'...)
[Input('produce-radio', 'value')])defset_columns_options(selected_produce):
varz = [{'label': i, 'value': i} for i in all_options[selected_produce]]
print('cb1 output: ')
print(varz)
return [{'label': i, 'value': i} for i in all_options[selected_produce]]
# Columns selection@app.callback(
Output('columns-radio', 'value'),
# layout element: dcc.RadioItems(id='columns-radio'...)
[Input('columns-radio', 'options')])defset_columns(available_options):
return available_options[0]['value']
# Crop selection@app.callback(
Output('crop-radio', 'value'),
# layout element: dcc.RadioItems(id='columns-radio'...)
[Input('crop-radio', 'options')])defset_crops(available_crops):
return available_crops[0]['value']
# Display selections in its own div@app.callback(# Columns 2m_temp_prod, or....
Output('display-selected-values', 'children'),
[Input('produce-radio', 'value'),
Input('crop-radio', 'value'),
Input('columns-radio', 'value')])defset_display_children(selected_produce, available_crops, selected_column):
return('DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column)
# Make a figure based on the selections@app.callback(# Columns 2m_temp_prod, or....
Output('crop-graph', 'figure'),
[Input('produce-radio', 'value'),
Input('crop-radio', 'value'),
Input('columns-radio', 'value')])defmake_graph(selected_produce, available_crops, selected_column):
# data source / weightingif selected_produce == 'prod':
dfd = df_vals_prod
if selected_produce == 'area':
dfd = df_vals_area
# plotly figure
fig = go.Figure()
fig.add_trace(go.Scatter(x=dfd[available_crops].index, y=dfd[available_crops][selected_column]))
fig.update_layout(title=dict(text='DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column))
return(fig)
app.run_server(mode='inline', port = 8077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
Post a Comment for "Properly Setting Up Callbacks For Dynamic Dropdowns Plotly Dash"