I’ve been working on a multi-page app in healthcare and it servers 2 pages: 1 with an overview of patients, the other with an in depth view of a single patient when clicked on it.
So when clicking on a patient, it’s a href like url.com/31 with 31 being the patient’s unique ID.
Now I’d like it when a user clicks on a patient, the in-depth graphs on that patient are loaded immediately. To make this, I created a callback with url, pathname as input and figure-id, figure as output. So you’d expect that when the url changes from / to /31, it triggers a callback to generate the figure needed based on the number in the url.
That’s not what I see. When I trigger the same function with a button and use url as state input it works perfectly fine. When using url input and text output, it works as expected too. Just not with a figure.
I’ve created a reproducible example from a mashup between the example here: https://dash.plot.ly/urls and here https://dash.plot.ly/getting-started
It’s a 2 page app. The callbacks to look at are called example_1 and example_2. Both have the exact same input, only example_1 outputs to a div with text and example_2 to a graph. You can click around and see that example_1 only triggers when we get to page-1. Example-2 only gets triggered when going back to /. Not when going from / to /page-1
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
df = pd.read_csv(
'https://raw.githubusercontent.com/plotly/'
'datasets/master/gapminderDataFiveYear.csv')
print(dcc.__version__) # 0.6.0 or above is required
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Since we're adding callbacks to elements that don't exist in the app.layout,
# Dash will raise an exception to warn us that we might be
# doing something wrong.
# In this case, we're adding the elements through a callback, so we can ignore
# the exception.
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
index_page = html.Div([
dcc.Link('Go to Page 1', href='/page-1'),
html.Br(),
dcc.Link('Go to Page 2', href='/page-2'),
])
page_1_layout = html.Div([
html.H1('Page 1', id='title'),
dcc.Dropdown(
id='page-1-dropdown',
options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
value='LA'
),
html.Div(id='page-1-content'),
html.Div(id='page-1-content-2'),
dcc.Graph(id='graph-with-slider'),
html.Br(),
dcc.Link('Go to Page 2', href='/page-2'),
html.Br(),
dcc.Link('Go back to home', href='/'),
])
@app.callback(dash.dependencies.Output('page-1-content', 'children'),
[dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
return 'You have selected "{}"'.format(value)
@app.callback(dash.dependencies.Output('page-1-content-2', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def example_1(pathname):
print('example_1 triggered!')
return "You're on the url: {}".format(pathname)
@app.callback(
dash.dependencies.Output('graph-with-slider', 'figure'),
[dash.dependencies.Input('url', 'pathname')])
def example_2(selected_year):
print('example_2 triggered!')
filtered_df = df[df.year == 2007]
traces = []
for i in filtered_df.continent.unique():
df_by_continent = filtered_df[filtered_df['continent'] == i]
traces.append(go.Scatter(
x=df_by_continent['gdpPercap'],
y=df_by_continent['lifeExp'],
text=df_by_continent['country'],
mode='markers',
opacity=0.7,
marker={
'size': 15,
'line': {'width': 0.5, 'color': 'white'}
},
name=i
))
return {
'data': traces,
'layout': go.Layout(
xaxis={'type': 'log', 'title': 'GDP Per Capita'},
yaxis={'title': 'Life Expectancy', 'range': [20, 90]},
margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
legend={'x': 0, 'y': 1},
hovermode='closest'
)
}
page_2_layout = html.Div([
html.H1('Page 2'),
dcc.RadioItems(
id='page-2-radios',
options=[{'label': i, 'value': i} for i in ['Orange', 'Blue', 'Red']],
value='Orange'
),
html.Div(id='page-2-content'),
html.Br(),
dcc.Link('Go to Page 1', href='/page-1'),
html.Br(),
dcc.Link('Go back to home', href='/')
])
@app.callback(dash.dependencies.Output('page-2-content', 'children'),
[dash.dependencies.Input('page-2-radios', 'value')])
def page_2_radios(value):
return 'You have selected "{}"'.format(value)
# Update the index
@app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/page-1':
return page_1_layout
elif pathname == '/page-2':
return page_2_layout
else:
return index_page
# You could also return a 404 "URL not found" page here
if __name__ == '__main__':
app.run_server(debug=True)
What am I missing? Also: I love dash, so if this is a real bug, I might go search for it and fix it myself with a PR if I can!