视频讲解:
Dash应用程序通过Dash回调函数实现交互:当输入组件的属性发生变化时,自动调用编写好的Python函数。可以把多个回调函数链接起来,即UI输入组件中的一个变动,触发整个应用程序中的几个变动。
Dash通过装饰器函数来实现回调:应用程序接口Input和Ouput是通过app.callback装饰器声明的
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)
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)
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)
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)
children(列表或单个破折号组件,字符串或数字 | 字符串;可选):上传组件的内容。
id( string ; 可选): 该组件的 ID,用于标识回调中的 dash 组件。ID 需要在应用程序中的所有组件中都是唯一的。
accept(字符串;可选):允许特定类型的文件。有关更多信息,请参阅 https://github.com/okonet/attr-accept。
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)
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)
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)
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)
help(dash.dcc.Download)
id( string ; 可选): 该组件的 ID,用于标识回调中的 dash 组件。
base64( boolean ; default False):base64 的默认值,在未设置为数据属性的一部分时使用。
data(dict ; 可选):更改时,调用下载。
data 是一个带键的字典: