短跑动态滑块

时间:2019-02-18 19:57:28

标签: python plotly-dash

简单的问题:

我想要一个由下拉列表索引的滑块。因此,在下拉菜单中,我将得到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)

在不触发循环依赖关系的情况下,如何使菜单切换到B后又不重置A呢?


原件: 设置有些复杂,所以让我们看一个例子。

说我正在建模税单。我有一个公民数据库,列出了他们的状态,婚姻状况和收入。

我想创建滑块,让我可以根据婚姻状况和州别调整税率,然后计算平均税单。

一次在屏幕上没有太多的滑块,因此我设置了一个下拉菜单,让我们决定根据州或婚姻状况进行调整,然后设置第二个下拉菜单,使我们可以选择特定的州或特定的州婚姻状况。因此,有两个下拉列表:

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

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

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

  1. 如果我们将特定州的税率调整为+ 5%,然后将特定婚姻状况(例如已婚)调整为+ 4%,那么我希望已婚佛罗里达州的税率增加+ 9% 。这意味着即使屏幕上没有动态生成佛罗里达州的滑块,我也需要存储佛罗里达州的税率。
  2. 如果我设置了佛罗里达州的税率,然后将下拉列表从佛罗里达州移开,然后再返回,那么我希望滑块处于选定的佛罗里达州税率。
  3. 我希望从上传的数据库中动态生成婚姻状况选项和状态选项。

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

方法1:为每个状态创建一个滑块dict-每个状态一个,对于每个婚姻状况一个-将所有布局放到布局中,但使下拉菜单中选择的所有滑块除外。这样做会中断,因为我需要计算平均税单,因此创建一个回调,将所有可能的税率提高作为输入。但是,回调仅在呈现所有功能时才起作用,并且会中断。

方法2:创建税率字典,只有一个带有动态名称的滑块。然后,我可以创建所有状态和婚姻状况的动态字典,并根据所选的下拉列表和滑块进行更新。但是,为了在不清除先前选择的值的情况下进行更新,此动态字典将需要通过以自身为状态的回调来创建,并且Dash甚至对于状态也不允许循环依赖!

我很高兴发布代码,但是它会很长,所以我选择描述上面尝试的方法。

1 个答案:

答案 0 :(得分:2)

看看您的代码,我了解到您不介意仅仅隐藏滑块。问题是您使用了容器的children属性,该属性会在每次更改时“重新创建”滑块,从而有效地重置它们。我建议直接改为更改容器的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中。离开它并没有什么坏处。