破折号动态滑块

Dash Dynamic Sliders

精简问题:

我想要由下拉菜单索引的滑块。因此,在下拉列表中,我将有 A、B,这将导致调整 A 值的滑块或调整 B 值的滑块。在任何时候,我都希望有一个条形图显示 A 和 B 的值。

下面是执行此操作的代码,但有一个问题除外:如果我将 A 的值从其默认值调整,将下拉列表切换到 B,然后将其切换回 A,A 将重置回其默认值。

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

app.layout = html.Div([

    dcc.Dropdown(id='segselect', options = [{'label': 'A', 'value': 'A'}, 
        {'label': 'B', 'value': 'B'}]),

    html.Div(id='SliderAContainer'),
    html.Div(id='SliderBContainer'),
    dcc.Graph(id='plot_graph')

    ])

app.config['suppress_callback_exceptions']=True

@app.callback(Output('SliderAContainer', 'children'),
    [Input('segselect', 'value')])
def return_containerA(seg):
    if seg == 'A':
        return html.Div(dcc.Slider(id='A', min = 0, max = 10, step = 1))
    else:
        return html.Div(dcc.Slider(id='A', min = 0, max = 10, step = 1), style={'display': 'none'})

@app.callback(Output('SliderBContainer', 'children'),
    [Input('segselect', 'value')])
def return_containerB(seg):
    if seg == 'B':
        return html.Div(dcc.Slider(id='B', min = 0, max = 10, step = 1, value = 2))
    else:
        return html.Div(dcc.Slider(id='B', min = 0, max = 10, step = 1, value = 2), style={'display': 'none'})


@app.callback(
    Output('plot_graph', 'figure'),
    [Input('A', 'value'), Input('B', 'value')])
def plot_A(A, B):
    return {
            'data': [
                {'y': [A, B], 'type': 'bar'},
            ],
        }


if __name__ == '__main__':
    app.run_server(debug=True, port=8041, dev_tools_hot_reload=False)

我怎样才能让A在菜单切换到B并返回后不重置,而不会触发循环依赖?


原文: 这是一个有点复杂的设置,所以让我们看一个例子。

假设我正在为税单建模。我有一个公民数据库,其中列出了他们的州、婚姻状况和收入。

我想创建允许我根据婚姻状况和州调整税率的滑块,然后计算平均税单。

屏幕上一次显示的滑块太多,所以我设置了一个下拉菜单,让我们决定按州或婚姻状况进行调整,然后是第二个下拉菜单,让我们 select特定的状态或特定的婚姻状况。所以有两个下拉菜单:

  1. 选择(州或婚姻状况)
  2. 选择一个特定的选项,例如。得克萨斯州或已婚(动态响应第一个下拉列表)

选择了两个下拉菜单后,我想在屏幕上放置一个滑块来调整该州或婚姻状况的税率。 .

滑块是我卡住的地方。我需要他们提供的三个特殊功能:

  1. 如果我们调整特定州的税率,比如说佛罗里达州 +5%,然后针对特定的婚姻状况,比如说已婚,+4%,那么我希望已婚的佛罗里达人有 +9%增税。这意味着我需要存储佛罗里达州的税率,即使屏幕上没有动态生成的佛罗里达州滑块。
  2. 如果我设置了佛罗里达州的税率,然后将下拉菜单从佛罗里达州切换回来,然后我希望滑块位于为佛罗里达州选择的税率。
  3. 我希望从上传的数据库中动态生成婚姻状况选项和状态选项。

到目前为止我已经尝试了两种方法。

方法 1:创建一个滑块字典——每个州一个,每个婚姻状况一个——将所有滑块都放在布局中,但除了下拉菜单选择的那个以外,其他滑块都不可见。这中断了,因为我需要计算平均税单,因此创建一个回调,将所有可能的加息作为输入。但是,回调仅在呈现所有函数时才起作用,这会中断。

方法 2:创建一个税率字典,以及一个带有动态名称的滑块。然后我可以创建一个包含所有状态和婚姻状况的动态字典,它会根据 selected 下拉列表和滑块进行更新。然而,为了在不清除之前 selected 值的情况下进行更新,这个动态字典需要由一个将自身作为状态的回调创建,而 Dash 不允许循环依赖,即使对于状态也是如此!

我很乐意 post 编码,但它会很长,所以我选择描述我在上面尝试过的方法。

查看您的代码,我了解到您不介意简单地隐藏滑块。问题是您使用容器的 children 属性,其中 "recreates" 滑块每次更改,有效地重置它们。我的建议是直接更改容器的 style 属性:

app.layout = html.Div([

    dcc.Dropdown(id='segselect', options=[{'label': 'A', 'value': 'A'},
                                          {'label': 'B', 'value': 'B'}]),

    html.Div(dcc.Slider(id='A', min=0, max=10, step=1), id='SliderAContainer'),
    html.Div(dcc.Slider(id='B', min=0, max=10, step=1, value=2), id='SliderBContainer'),
    dcc.Graph(id='plot_graph')

])   

@app.callback(Output('SliderAContainer', 'style'),
              [Input('segselect', 'value')])
def return_containerA(seg):
    if seg == 'A':
        return {}
    else:
        return {'display': 'none'}

@app.callback(Output('SliderBContainer', 'style'),
              [Input('segselect', 'value')])
def return_containerB(seg):
    if seg == 'B':
        return {}
    else:
        return {'display': 'none'}

请注意,我必须在布局设置中将滑块添加为子项,因为它们不再由回调函数生成。

另外,请注意您不再需要 suppress_callback_exceptions 配置,因为滑块始终存在于 DOM 中。不过离开也没什么坏处。