Use Dash! How to display html.Lable
and dcc.Dropdown
on the same line?
1、目标
下图展示了我想要实现的效果。
数据筛选部分包含了三个筛选条件:日期区间选择器;区域选择器;地市选择器。其中,地市选择器的取值和已选区域是对应的,如果选择的是全省,则关闭地市选择器。
红框中的内容所打印的输出旨在模拟后端处理函数已经捕获了筛选的内容。
2、代码
首先贴出全部的代码:
# Dash == 2.6.1
import datetime
from dash import Dash, html, dcc, Input, Output, State
app = Dash(__name__)
app.layout = html.Div([
html.H1(
children='数据看板',
style={
'textAlign': 'center',
}
),
html.Div(
children=[
html.H2(
children='数据筛选',
style={
'padding-left': '45px',
}
),
html.Div(className='my-label',
children=[html.Label('选择日期:', style={'padding-right': '5px'}),
dcc.DatePickerRange(
id='date-picker-range-3',
start_date='2022-12-10',
end_date='2022-12-20',
min_date_allowed=(datetime.datetime.now() + datetime.timedelta(1)).strftime('%Y-%m-%d'),
max_date_allowed=(datetime.datetime.now() + datetime.timedelta(29)).strftime('%Y-%m-%d'),
display_format='YYYY-MM-DD',
updatemode='bothdates',
first_day_of_week=1,
minimum_nights=0,
),
html.Label(
children=[
html.Label('选择区域:',
style={'padding-left': '20px',
'padding-right': '5px'}),
dcc.Dropdown(options=['全省', '晋北', '晋中', '晋南'],
id='area-dp',
value='全省', clearable=False,
style={'width': '100px',
'display': 'inline-table'})],
),
html.Label(
children=[
html.Label('选择地市:',
style={'padding-left': '20px',
'padding-right': '5px'}),
dcc.Dropdown(
id='city-dp',
value='all',
clearable=False,
style={'width': '100px',
'display': 'inline-table'})
]
),
html.Button('确定',
id='confirm-btn',
style={'height': '30px',
'margin-left': '50px',
'font-size': '15px',
'background-color': '#439DF8',
'color': 'white'})
]),
html.Label('全省城市', id='output', className='my-label')
]
),
])
@app.callback(
Output('city-dp', 'options'),
Output('city-dp', 'value'),
Output('city-dp', 'disabled'),
Input('area-dp', 'value')
)
def update_city_dp(value):
area_2_cities = {
'晋北': ['大同', '朔州', '忻州'],
'晋中': ['吕梁', '太原', '晋中', '阳泉'],
'晋南': ['临汾', '长治', '运城', '晋城']
}
if area_2_cities.get(value):
return ['all'] + area_2_cities[value], 'all', False
else:
return [], '', True
@app.callback(
Output('output', 'children'),
Input('confirm-btn', 'n_clicks'),
State('area-dp', 'value'),
State('city-dp', 'value'),
State('date-picker-range-3', 'start_date'),
State('date-picker-range-3', 'end_date'),
)
def make_output(n_clicks, area='全省', city='all', start_date='2022-12-10', end_date='2022-12-20'):
return '下拉选项内容:' + area + city + ';日期区间:' + start_date + '~' + end_date
if __name__ == '__main__':
app.run_server(debug=True, port=5000)
Attention 1
在这个实现中,我花费时间最长的是解决如何将Label
和Dropdown
放置在同一行内这个问题。如代码中所示,最终选择的方案(Line35-45)是:将Label
和Dropdown
放置在另一个Label
中,并且通过css设置了Dropdown
的display
为inline-table
——我尝试了其他的值,均达不到想要的效果,我其实没有太明白为什么这样设置就可以。
Attention 2
设置了筛选条件后,通过点击Button
按钮来将所有的设置同步到后端函数。在编写后端函数时需要注意,Button
的n_click
作为该函数的输入,即使在函数中没有被用到,也要放到形参中,因为该后端函数的参数数量必须与其装饰器中定义的数量一致(Line91-100)。
Attention 3
代码中我引用了外部的css文件中的一组格式设置:
.my-label {
padding-right: 20px;
margin-left: 45px;
}
欢迎留言讨论。