破折号动态滑块
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特定的状态或特定的婚姻状况。所以有两个下拉菜单:
- 选择(州或婚姻状况)
- 选择一个特定的选项,例如。得克萨斯州或已婚(动态响应第一个下拉列表)
选择了两个下拉菜单后,我想在屏幕上放置一个滑块来调整该州或婚姻状况的税率。 .
滑块是我卡住的地方。我需要他们提供的三个特殊功能:
- 如果我们调整特定州的税率,比如说佛罗里达州 +5%,然后针对特定的婚姻状况,比如说已婚,+4%,那么我希望已婚的佛罗里达人有 +9%增税。这意味着我需要存储佛罗里达州的税率,即使屏幕上没有动态生成的佛罗里达州滑块。
- 如果我设置了佛罗里达州的税率,然后将下拉菜单从佛罗里达州切换回来,然后我希望滑块位于为佛罗里达州选择的税率。
- 我希望从上传的数据库中动态生成婚姻状况选项和状态选项。
到目前为止我已经尝试了两种方法。
方法 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 中。不过离开也没什么坏处。
精简问题:
我想要由下拉菜单索引的滑块。因此,在下拉列表中,我将有 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特定的状态或特定的婚姻状况。所以有两个下拉菜单:
- 选择(州或婚姻状况)
- 选择一个特定的选项,例如。得克萨斯州或已婚(动态响应第一个下拉列表)
选择了两个下拉菜单后,我想在屏幕上放置一个滑块来调整该州或婚姻状况的税率。 .
滑块是我卡住的地方。我需要他们提供的三个特殊功能:
- 如果我们调整特定州的税率,比如说佛罗里达州 +5%,然后针对特定的婚姻状况,比如说已婚,+4%,那么我希望已婚的佛罗里达人有 +9%增税。这意味着我需要存储佛罗里达州的税率,即使屏幕上没有动态生成的佛罗里达州滑块。
- 如果我设置了佛罗里达州的税率,然后将下拉菜单从佛罗里达州切换回来,然后我希望滑块位于为佛罗里达州选择的税率。
- 我希望从上传的数据库中动态生成婚姻状况选项和状态选项。
到目前为止我已经尝试了两种方法。
方法 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 中。不过离开也没什么坏处。