I have a Dash app with some pages where every plot I have gets its data from a hidden div.
The problem I have is that every time I load a page the plots doesn’t update their content until I trigger it using some imput element (like a radio button). I found a way to ensure that when the page loads it also populates the element I have problems with. To do so I create a dummy hidden div an use it as an input but it doesn’t seem an elegant way to do that.
I think that the proper way to implement that should be an event that is triggered when the page is changed and the pass it to the callback. But after a lot of trial and research I haven’t been able to do it.
Example to show the problem
In order to make my problem more clear I used the code from the multipage tutorial (https://dash.plot.ly/urls) to have an easy example to show.
The files I used are:
– app.py
– index.py
– apps/app1.py
– apps/app2.py
with the following code:
app.py
import dash
import os
app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True
index.py
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from app import app
from apps import app1, app2
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(list("ABC"), id="data", style={"display":"none"}),
html.Div(id='page-content')
])
@app.callback(Output('page-content', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/apps/app1':
return app1.layout
elif pathname == '/apps/app2':
return app2.layout
else:
return '404'
if __name__ == '__main__':
app.run_server(debug=True)
apps/app1.py
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
from app import app
layout = html.Div([
html.H3('App 1'),
dcc.Link('Go to App 2', href='/apps/app2'),
dcc.Dropdown(id='app-1-dropdown'),
html.Div(id='dummy_div'),
])
@app.callback(
Output('app-1-dropdown', 'options'),
[Input('data', 'children')])
def update_dropdown(options):
return [{"label": x, "value": x} for x in options]
apps/app2.py
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
from app import app
layout = html.Div([
html.H3('App 2'),
dcc.Link('Go to App 1', href='/apps/app1'),
dcc.Dropdown(id='app-2-dropdown'),
html.Div(id='dummy_div'),
])
@app.callback(
Output('app-2-dropdown', 'options'),
[Input('data', 'children'),
Input('dummy_div', 'children')]) #This is what ensures that the dropdown loads its options
def update_dropdown(options, aux):
return [{"label": x, "value": x} for x in options]
In this example when you open App1 the dropdown it don’t have the options defined. But App2 it does have them due to the Input('dummy_div', 'children')
.
Any suggestions on how to implement that in a more elegant way?
Thanks in advance!