英文:
how to preserve the same content after going back to a tab in Dash
问题
I have multiple tabs in a Dash app where each tab has different information shown. Let's say I make some selections from a drop-down menu on the first tab and create some charts. Then, I switch to another tab and come back to the first tab. My intention is to see the same information and charts on the first tab. I found similar questions, but no answer has been provided.
这是一个Dash应用程序,其中有多个选项卡,每个选项卡显示不同的信息。假设我从第一个选项卡的下拉菜单中进行一些选择并创建一些图表。然后,我切换到另一个选项卡,然后返回到第一个选项卡。我的意图是在第一个选项卡上看到相同的信息和图表。我找到了类似的问题,但没有提供答案。
Here is a very simple dash app as a MWE.
这是一个非常简单的Dash应用程序示例。
If you have any specific translation requests for code or other parts, please let me know.如果您对代码或其他部分有特定的翻译要求,请告诉我。
英文:
I have multiple tabs in a Dash app where each tab has different information shown. Let's say I make some selections from a drop down menu on the first tab and create some charts. Then, I switch to another tab and come back to the first tab. My intention is to see the same information and charts on the first tab. I found similar questions, but no answer has been provided.
https://stackoverflow.com/questions/62386470/keep-values-dash-tab
https://stackoverflow.com/questions/56753040/how-to-save-the-content-of-a-tab-in-dash
https://community.plotly.com/t/how-to-preserve-last-state-in-tabs/14694
Here is a very simple dash app as a MWE.
import dash
from dash import html, dcc
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets, suppress_callback_exceptions=True)
myList = ['A', 'B']
myDict = {'A': [1,2,3],'B': [4,5,6] }
tab1 = html.Div([
html.H3('Tab content 1'),
dcc.Dropdown(
id='first-dropdown-tab1',
options=[{'label': l, 'value': l} for l in myList],
value='A'
),
dcc.Dropdown(
id='second-dropdown-tab1',
options=[{'label': i, 'value': i} for i in myDict['A']],
value=1
),
])
tab2 = html.Div([
html.H3('Tab content 2'),
dcc.Dropdown(
id='first-dropdown-tab2',
options=[{'label': l, 'value': l} for l in myList],
value='A'
),
dcc.Dropdown(
id='second-dropdown-tab2',
options=[{'label': i, 'value': i} for i in myDict['A']],
value=1
),
])
app.layout = html.Div([
html.H1('Dash Tabs component demo'),
dcc.Tabs(id="tabs-example", value='tab-1', children=[
dcc.Tab(label='Tab One', value='tab-1'),
dcc.Tab(label='Tab Two', value='tab-2'),
]),
html.Div(id='tabs-content-example')
])
@app.callback(
Output('tabs-content-example', 'children'),
[Input('tabs-example', 'value')]
)
def render_content(tab):
if tab == 'tab-1':
return tab1
elif tab == 'tab-2':
return tab2
@app.callback(
[Output('second-dropdown-tab1', 'options'),
Output('second-dropdown-tab1', 'value')],
[Input('first-dropdown-tab1', 'value')]
)
def update_dropdown_tab1(value):
return [{'label': i, 'value': i} for i in myDict[value]], myDict[value][0]
@app.callback(
[Output('second-dropdown-tab2', 'options'),
Output('second-dropdown-tab2', 'value')],
[Input('first-dropdown-tab2', 'value')]
)
def update_dropdown_tab2(value):
return [{'label': i, 'value': i} for i in myDict[value]], myDict[value][0]
if __name__ == '__main__':
app.run_server(debug=True)
答案1
得分: 1
从我的理解,以下是发生的情况:
每次您切换选项卡时,显示的内容都会完全进行重新渲染,基于tab1
或tab2
对象。这就是为什么您总是返回到A-1
选择的原因。
对于每个下拉菜单,您可以使用内存持久性来保存组件的状态,以便在重新渲染时返回到上次选择的选项/值。
但是,对于您拥有的两个链接的下拉菜单,您将面临另一个问题->第一个下拉菜单上的更改值触发的第二个回调将始终更新第二个下拉菜单的选项/值,即使它已经根据保留的状态正确渲染。
保留您目前的布局,我想到的唯一解决方案都相当巧妙。但是,您可以简单地使用Tab
子元素更改布局,以不触发我上面描述的整个链条,从而获得您想要的行为。
app.layout = html.Div(
[
html.H1("Dash Tabs component demo"),
dcc.Tabs(
id="tabs-example",
value="tab-1-example",
children=[
dcc.Tab(
id="tab-1", label="Tab One", value="tab-1-example", children=[tab1]
),
dcc.Tab(
id="tab-2", label="Tab Two", value="tab-2-example", children=[tab2]
),
],
),
]
)
# 您可以删除这个回调
# @app.callback(
# dash.dependencies.Output("tabs-content-example", "children"),
# [dash.dependencies.Input("tabs-example", "value")],
# )
# def render_content(tab):
# if tab == "tab-1-example":
# return tab1
# elif tab == "tab-2-example":
# return tab2
英文:
From my understanding, here is what's happening:
Each time you switch tabs, the displayed content is fully re-rendered, based on either the tab1
or the tab2
object. This is why you're always returning to the A-1
selection.
For each dropdown, you could use memory persistence to save the state of the component, so that when it's re-rendered it goes back to the last selected options/value.
However, with the two linked dropdowns that you have, you'll face another issue -> The second callback triggered by a changing value on the first dropdown will systematically update the second dropdown options/values, even if it was properly rendered with the persisted state.
Preserving the layout you have, the only solutions I can think of are pretty hacky. However, you can simply change the layout using Tab
children to not trigger the whole chain I described above, and so to obtain the behavior you want.
app.layout = html.Div(
[
html.H1("Dash Tabs component demo"),
dcc.Tabs(
id="tabs-example",
value="tab-1-example",
children=[
dcc.Tab(
id="tab-1", label="Tab One", value="tab-1-example", children=[tab1]
),
dcc.Tab(
id="tab-2", label="Tab Two", value="tab-2-example", children=[tab2]
),
],
),
]
)
# You can remove this callback
# @app.callback(
# dash.dependencies.Output("tabs-content-example", "children"),
# [dash.dependencies.Input("tabs-example", "value")],
# )
# def render_content(tab):
# if tab == "tab-1-example":
# return tab1
# elif tab == "tab-2-example":
# return tab2
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论