I am using Plotly Dash to create a dashboard. I want to have multiple tabs, and when the user clicks on any particular tab, for relevant callbacks to be triggered.
The main.py
file calls a layout.py
file to generate the layout. Here is a code snippet of how I'm going about it.
def create_layout(app):
@callback(Output("tab-output", "children"), Input("tab-input", "value"))
def update_tab(tab):
if tab == "tabname1":
return my_individual_script.render(app) # might work, might not
elif tab == "tabname2":
return f"You selected tab {tab}." # works properly
# 1st alternative (succeeds ✅)
layout = html.Div(children=[
dcc.Tabs(id="tabs-input", value="tabname1",
children=[dcc.Tab(label="foo", value="tabname1"), dcc.Tab(label="bar", value="tabname2")]),
my_individual_script.render(app)
])
# 2nd alternative (fails ❌)
layout = html.Div(children=[
dcc.Tabs(id="tab-input", value="tabname1",
children=[dcc.Tab(label="foo", value="tabname1"), dcc.Tab(label="bar", value="tabname2")]),
html.Div(id="tab-output")
])
return layout
What I expect / what I have tried:
- I want
update_tab
to call the right separate scripts to render all the content for that tab. Hence the use ofmy_individual_script
. - The 1st alternative which succeeds 'statically' calls the render function from
my_individual_script
with its own callback. - The 2nd alternative which fails only calls
my_individual_script
IF the tab name is correct. Obviously, this is the desired behavior because I want content to change based on the tab selection. Here, I place anhtml.Div
with the IDtab-output
to triggerupdate_tab
. I think it should work because I get the expected behavior fromtabname2
. - I have tried supplying
Input("tab-output", "children")
tomy_individual_script
's callback based on my tenuous understanding of chained callbacks, but I'm not sure if that's applicable here, considering that the callback is triggered based onif
conditions in the parent callback. It also doesn't work.
Here is code in my_individual_script.py
with its callback that fails to trigger in the 2nd alternative:
def render(app):
@callback(Output("output-div", "children"), [Input("dropdown", "value")])
def update_value(value):
return f"You have selected {value}."
div = html.Div(children=[
dcc.Dropdown(["foo", "bar"], "foo", id="dropdown"),
html.Br(),
html.Div(id="output-div")
])
return div
In this code, a dropdown menu with two options is initialized and all I want to do is print out what the user has selected in an html.Div
below the dropdown. This is ultimately the div
I want to show up when I write html.Div(id="tab-output")
in the 2nd alternative.
The problem is that the callback in my_individual_script
just isn't triggered. Why is that the case SPECIFICALLY when I try access its content through an html.Div
with the parent callback's output ID?
Is it to do with my callback being dependent on another callback, so dash
doesn't see it when it's initialized?
How can I allow for 'dynamic' loading of scripts based on the tab the user has clicked?
Apologies for any possible syntax errors here. I've had to transcribe this code from another computer, so any errors here do not correspond to syntax errors in the code I'm working with.
I am not getting any error messages so it's difficult to search for answers on StackOverFlow or elsewhere that correspond to my issue.