文章目录
视频讲解:
一、什么是Dash回调?
1.1 回调的作用
Dash应用程序通过Dash回调函数实现交互:当输入组件的属性发生变化时,自动调用编写好的Python函数。可以把多个回调函数链接起来,即UI输入组件中的一个变动,触发整个应用程序中的几个变动。
1.2 回调的实现
Dash通过装饰器函数来实现回调:应用程序接口Input和Ouput是通过app.callback装饰器声明的
二、带回调功能的组件
2.1 按钮
import dash
from dash import dcc
from dash import html
# css样式表无法下载,返回403错误
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(children=[
html.Div(dcc.Input(id='input-box', type='text')),
html.Button('提交', id='button'),
html.Div(id='output-container-button',
children='输入完毕,请点击提交按钮。')
])
@app.callback(
dash.dependencies.Output('output-container-button', 'children'),
[dash.dependencies.Input('button', 'n_clicks')],
[dash.dependencies.State('input-box', 'value')])
def update_html(n_clicks, values):
print(values, type(values)) # 你好吗 <class 'str'>
print(n_clicks, type(n_clicks)) # 1 <class 'int'>
return f'输入内容:"{values}" ,提交了 {n_clicks} 次'
if __name__ == '__main__':
app.run_server(debug=True)
2.2 上传组件1:解析 CSV 或 Excel 文件并将结果显示在表格中
import base64
import datetime
import io
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import dash_table
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Upload(
id='upload-data',
children=html.Div([
'请将Excel或CSV文件拖放到此处,或 ',
html.A('选择文件')
]),
style={
'width': '100%', # 宽度
'height': '60px', # 高度
'lineHeight': '60px', # 线高
'borderWidth': '1px', # 边框宽度
'borderStyle': 'dashed', # 边框样式
'borderRadius': '5px', # 边框半径
'textAlign': 'center', # 文字居中
'margin': '10px' # 外边距
},
# 允许同时上传多个文件
multiple=True
),
html.Div(id='output-data-upload'),
])
def parse_contents(contents, filename, date):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# 上传了一个CSV文件
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# 上传了一个Excel文件
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return html.Div([
'Sorry,处理文件出错。'
])
return html.Div([
html.H5(filename),
# 从时间戳转化为日期时间字符串
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(), # 分割线
# 为了测试,通过浏览器显示原始数据
html.Div('原始数据'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
}),
html.Pre(str(df.to_dict('records'))),
])
@app.callback(Output('output-data-upload', 'children'),
Input('upload-data', 'contents'),
State('upload-data', 'filename'),
State('upload-data', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
""" 装饰器 Input State State 中的值分别传给本函数的三个参数 """
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
2.3 上传组件2:上传图像并在页面显示
import datetime
import dash
from dash.dependencies import Input, Output, State
from dash import dcc
from dash import html
# css无法访问,无效
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Upload(
id='upload-image',
children=html.Div([
'拖放图像文件到此,或 ',
html.A('选择文件。')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
# 允许同时上传多个文件
multiple=True
),
html.Div(id='output-image-upload'),
])
def parse_contents(contents, filename, date):
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
# 在 Dash 上传模块的支持下,html.IMG可以直接显示图像文件
html.Img(src=contents, width=600),
html.Hr(),
])
@app.callback(Output('output-image-upload', 'children'),
Input('upload-image', 'contents'),
State('upload-image', 'filename'),
State('upload-image', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
2.4 上传组件的三种使用方式
import dash
from dash import dcc
from dash import html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Upload(html.Button('上传文件')),
html.Hr(),
dcc.Upload(html.A('上传文件')),
html.Hr(),
dcc.Upload([
'拖放文件到此,或 ',
html.A('选择一个文件')
], style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center'
})
])
if __name__ == '__main__':
app.run_server(debug=True)
2.5 上传属性:help(dash.dcc.Upload)
children(列表或单个破折号组件,字符串或数字 | 字符串;可选):上传组件的内容。
id( string ; 可选): 该组件的 ID,用于标识回调中的 dash 组件。ID 需要在应用程序中的所有组件中都是唯一的。
accept(字符串;可选):允许特定类型的文件。有关更多信息,请参阅 https://github.com/okonet/attr-accept。
- 请记住,mime 类型确定在跨平台上并不可靠。例如,CSV 文件在 macOS 下报告为 text/plain,但在 Windows 下报告为 application/vnd.ms-excel。在某些情况下,可能根本没有设置 MIME 类型。请参阅:https : //github.com/react-dropzone/react-dropzone/issues/276。
className(字符串;可选):组件的 HTML 类名。
className_active(字符串;可选):活动时组件的 HTML 类名。
className_disabled(字符串;可选):组件的 HTML 类名称(如果禁用)。
className_reject(字符串;可选):如果被拒绝,组件的 HTML 类名。
contents(字符串 | 字符串列表;可选):上传文件的内容作为二进制字符串。
disable_click( boolean ; default False): 不允许点击组件打开文件对话框。
disabled( boolean ; default False): 完全启用/禁用上传组件。
filename(字符串 | 字符串列表;可选):上传的文件的名称。请注意,这不包括文件的路径(出于安全原因)。
last_modified( number | list of numbers ; optional): 上传文件的最后修改日期在unix时间(自1970年以来的秒数)。
loading_state( dict ; 可选): 保存来自 dash-renderer 的加载状态对象的对象。
loading_state 是一个带键的字典: - component_name(字符串;可选):保存正在加载的组件的名称。
- is_loading(boolean ; 可选):确定组件是否正在加载。
- prop_name(字符串;可选):保存正在加载的属性。
max_size(数字;默认-1):最大文件大小(以字节为单位)。如果-1,则无穷大。
min_size(数字;默认0):最小文件大小(以字节为单位)。
multiple( boolean ; default False): 允许删除多个文件。
style(dict ; 可选):要应用的 CSS 样式。
style_active( dict ; default { borderStyle: ‘solid’, borderColor: ‘#6c6’, backgroundColor: ‘#eee’,}):活动时应用的 CSS 样式。
style_disabled( dict ; default { opacity: 0.5,}): CSS 样式(如果禁用)。
style_reject( dict ; default { borderStyle: ‘solid’, borderColor: ‘#c66’, backgroundColor: ‘#eee’,}): CSS 样式,如果被拒绝。
2.6 下载组件:下载文本
import dash
from dash.dependencies import Output, Input
from dash import html
from dash import dcc
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div(children=
[html.Button("下载文本", id="btn_txt"),
dcc.Download(id="download-text-index")]
)
@app.callback(
Output("download-text-index", "data"),
Input("btn_txt", "n_clicks"))
def func(n_clicks):
if n_clicks is None:
raise dash.exceptions.PreventUpdate
else:
return dict(content="这是将要保存的文本内容。", filename="hello.txt")
if __name__ == "__main__":
app.run_server(debug=True)
2.7 下载组件:DataFrame下载为CSV
import dash
from dash.dependencies import Output, Input
from dash import html
from dash import dcc
import pandas as pd
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Button("下载CSV", id="btn_csv"),
# 下载组件
dcc.Download(id="download-dataframe-csv"),
]
)
df = pd.DataFrame({"a": [1, 2, 3, 4],
"b": [2, 1, 5, 6],
"c": ["x", "x", "y", "y"]})
@app.callback(
Output("download-dataframe-csv", "data"),
Input("btn_csv", "n_clicks"),
prevent_initial_call=True,
)
def func(n_clicks):
return dcc.send_data_frame(df.to_csv, "mydf.csv")
if __name__ == "__main__":
app.run_server(debug=True)
2.8 下载组件:DataFrame下载为Excel
import dash
from dash.dependencies import Output, Input
from dash import html
from dash import dcc
import pandas as pd
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Button("下载为Excel文件", id="btn_xlsx"),
# 下载组件
dcc.Download(id="download-dataframe-xlsx"),
]
)
df = pd.DataFrame({"a": [1, 2, 3, 4],
"b": [2, 1, 5, 6],
"c": ["x", "x", "y", "y"]})
@app.callback(
Output("download-dataframe-xlsx", "data"),
Input("btn_xlsx", "n_clicks"),
prevent_initial_call=True, # 阻止首次回调
)
def func(n_clicks):
return dcc.send_data_frame(df.to_excel, "mydf.xlsx", sheet_name="Sheet_name_1")
if __name__ == "__main__":
app.run_server(debug=True)
2.9 下载组件:下载图像
import dash
from dash.dependencies import Output, Input
from dash import html
from dash import dcc
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button("下载图像", id="btn_image"),
dcc.Download(id="download-image")
])
@app.callback(
Output("download-image", "data"),
Input("btn_image", "n_clicks"),
prevent_initial_call=True, # 阻止首次回调
)
def func(n_clicks):
return dcc.send_file("QR-PyDataLab.jpg")
if __name__ == "__main__":
app.run_server(debug=True)
2.10 下载属性
help(dash.dcc.Download)
id( string ; 可选): 该组件的 ID,用于标识回调中的 dash 组件。
base64( boolean ; default False):base64 的默认值,在未设置为数据属性的一部分时使用。
data(dict ; 可选):更改时,调用下载。
data 是一个带键的字典:
- base64(布尔值;可选):设置为 True,当数据采用 base64 编码时。
- content(字符串;必需):文件内容。
- filename( string ; required): 下载对话框中建议的文件名。
- type(字符串;可选):Blob 类型,通常是 MIME 类型。
type( string ; default ‘text/plain’): type 的默认值,在未设置为 data 属性的一部分时使用。