如何在返回到Dash标签时保留相同的内容

huangapple go评论65阅读模式
英文:

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

从我的理解,以下是发生的情况:

每次您切换选项卡时,显示的内容都会完全进行重新渲染,基于tab1tab2对象。这就是为什么您总是返回到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

huangapple
  • 本文由 发表于 2023年6月13日 03:34:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459787.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定