我想要一个由下拉列表索引的滑块。因此,在下拉菜单中,我将得到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:为每个状态创建一个滑块dict-每个状态一个,对于每个婚姻状况一个-将所有布局放到布局中,但使下拉菜单中选择的所有滑块除外。这样做会中断,因为我需要计算平均税单,因此创建一个回调,将所有可能的税率提高作为输入。但是,回调仅在呈现所有功能时才起作用,并且会中断。
方法2:创建税率字典,只有一个带有动态名称的滑块。然后,我可以创建所有状态和婚姻状况的动态字典,并根据所选的下拉列表和滑块进行更新。但是,为了在不清除先前选择的值的情况下进行更新,此动态字典将需要通过以自身为状态的回调来创建,并且Dash甚至对于状态也不允许循环依赖!
我很高兴发布代码,但是它会很长,所以我选择描述上面尝试的方法。
答案 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中。离开它并没有什么坏处。