本文示例代码已上传至我的
Github
仓库https://github.com/CNFeffery/DataScienceStudyNotes
1 简介
这是我的系列教程Python+Dash快速web应用开发的第三期,在前两期的教程中,我们围绕什么是Dash
,以及如何配合方便好用的第三方拓展dash-bootstrap-components
来为我们的Dash
应用设计布局展开了非常详细的介绍。
而Dash
最吸引我的地方在于其高度封装了react.js
,使得我们无需编写js
语句,纯Python
编程就可以实现浏览器前端与后端计算之间常规的异步通信,从而创造出功能强大的交互式web
应用。
图1
从今天的文章开始,我就将开始带大家走进Dash
的核心内容——回调。
2 Dash中的基础回调
2.1 最基础的回调
Dash
中的回调(callback)是以装饰器的形式,配合自编回调函数,实现前后端异步通信交互,这句话可能不太好理解,我们从一个简单的例子出发来认识Dash
中的回调:
app1.py
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
__name__,
external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Container(
[
dbc.Row(
[
dbc.Col(dbc.Input(id='input-value',
placeholder='请输入些东西'),
width=12),
dbc.Col(dbc.Label(id='output-value'),
width=12)
]
)
]
)
]
)
# 对应app实例的回调函数装饰器
@app.callback(
Output('output-value', 'children'),
Input('input-value', 'value')
)
def input_to_output(input_value):
'''
简单的回调函数
'''
return input_value
if __name__ == '__main__':
app.run_server()
先来看看app1
的交互效果:
图2
下面我们来分解上面的代码,梳理一下要构造一个具有实际交互功能的Dash
应用需要做什么:
- 确定输入与输出部件
一个可交互的系统一定是有输入与输出的,我们开头导入的Input
与Output
对象,他们分别扮演着输入者与输出者两种角色,其各自的第一个参数component_id
用于联动前端部分定义的部件。
我们在前面定义前端部件时,为dbc.Input
对应的输入框设置了id='input-value'
,为dbc.Label
对应的文字输出设置了id='output-value'
,让它们作为第一个参数可以被Input()
与Output()
唯一识别出来。
- 确定输入与输出内容
在确定了输入者与输出者之后,更重要的是为告诉Dash
需要监听什么输入,响应什么输出,这就要用到第二个参数component_property
。
它与对应的前端部件有关,譬如我们的dbc.Input()
输入框,其被输入的内容都存在value
属性中,而children
属性是dbc.Label
以及绝大多数html
部件的第一个参数,这样我们就确定了输入输出内容。
- 装饰回调函数
app.callback()
装饰器按照规定的先Output()
后Input()
的顺序传入相应对象,而既然是装饰器,自然需要配合自定义回调函数使用。
我们的input_to_output()
就是对应的回调函数,其参数与装饰器中的Input()
对应,而函数内部则用来定义计算处理过程。
最后return
的对象则对应Output()
。
# 对应app实例的回调函数装饰器
@app.callback(
Output('output-value', 'children'),
Input('input-value', 'value')
)
def input_to_output(input_value):
'''
简单的回调函数
'''
return input_value
通过上面这样的结构,我们得以纯Python
“寥寥数语”实现了交互功能,赋予我们编写任意功能Dash
应用的能力。
2.2 同时设置多个Input()与Output()
在上一小节中我们介绍的是最基本的单输入 -> 单输出回调模式,很多时候我们需要更复杂的回调模式,譬如下面的例子:
app2.py
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
__name__,
external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Container(
[
dbc.Row(
[
dbc.Col(dbc.Input(id='input-value1'), width=3),
dbc.Col(html.P('+'), width=1),
dbc.Col(dbc.Input(id='input-value2'), width=3),
],
justify='start'
),
html.Hr(),
dbc.Label(id='output-value')
]
)
]
)
@app.callback(
Output('output-value', 'children'),
Input('input-value1', 'value'),
Input('input-value2', 'value')
)
def input_to_output(input_value1, input_value2):
try:
return float(input_value1) + float(input_value2)
except:
return '请输入合法参数!'
if __name__ == '__main__':
app.run_server()
图3
这里我们的Input()
对象不止一个,在Output()
对象之后依次传入(也可以把所有Input()
对象包在一个列表中传入),其顺序对应后面回调函数的参数顺序,从而实现了多个输入值的一一对应。
同样的,Output()
也可以有多个:
app3.py
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
__name__,
external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Container(
[
dbc.Row(
[
dbc.Col(dbc.Input(id='input-lastname'), width=3),
dbc.Col(html.P('+'), width=1),
dbc.Col(dbc.Input(id='input-firstname'), width=3),
],
justify='start'
),
html.Hr(),
dbc.Label(id='output1'),
html.Br(),
dbc.Label(id='output2')
]
)
]
)
@app.callback(
[Output('output1', 'children'),
Output('output2', 'children')],
[Input('input-lastname', 'value'),
Input('input-firstname', 'value')]
)
def input_to_output(lastname, firstname):
try:
return '完整姓名:' + lastname + firstname, f'姓名长度为{len(lastname+firstname)}'
except:
return '等待输入...', '等待输入...'
if __name__ == '__main__':
app.run_server()
图4
可以看到不管是多个Output()
还是Input()
,只需要嵌套在列表中即可。
2.3 利用State()实现惰性交互
很多情况下,如果我们的回调函数计算过程时间开销较大,那么像前面介绍的仅靠Input()
与Output()
实现的前后端通信会很频繁,因为监听到的所有输入部件对应属性值只要略一改变,就会触发回调。
为了解决这类问题,Dash
中设计了State()
对象,我们可以利用State()
替换Input()
来绑定对应的输入值,再将一些需要主动触发的譬如dbc.Button()
按钮部件的属性n_clicks
,作为Input()
对象进行绑定。
让我们通过下面的例子更好的理解它的作用:
app4.py
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
app = dash.Dash(
__name__,
external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
[
html.Br(),
html.Br(),
html.Br(),
dbc.Container(
[
dbc.Row(
[
dbc.Col(dbc.Input(id='input-value'),
width=4),
dbc.Col(dbc.Button('小写转大写',
id='state-button',
n_clicks=0),
width=4),
dbc.Col(dbc.Label(id='output-value',
style={'padding': '0',
'margin': '0',
'line-height': '38px'}),
width=4)
],
justify='start'
)
]
)
]
)
@app.callback(
Output('output-value', 'children'),
Input('state-button', 'n_clicks'),
State('input-value', 'value')
)
def input_to_output(n_clicks, value):
if n_clicks:
return value.upper()
if __name__ == '__main__':
app.run_server()
图5
可以看到,装饰器中按照Output()
、Input()
、State()
的顺序传入各个对象后,我们的Button()
部件的n_clicks
参数记录了对应的按钮被点击了多少次,初始化我们设置其为0,之后每次等我们输入完单词,主动去点击按钮从而增加其被点击次数记录时,回调函数才会被触发,这样就方便了我们的很多复杂应用场景~
以上就是本期的全部内容,欢迎在评论区与我进行讨论~
(数据科学学习手札104)Python+Dash快速web应用开发——回调交互篇(上)的更多相关文章
- (数据科学学习手札75)基于geopandas的空间数据分析——坐标参考系篇
本文对应代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在上一篇文章中我们对geopandas中的数据结 ...
- (数据科学学习手札84)基于geopandas的空间数据分析——空间计算篇(上)
本文示例代码.数据及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在本系列之前的文章中我们主要讨论了g ...
- (数据科学学习手札88)基于geopandas的空间数据分析——空间计算篇(下)
本文示例代码及数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在基于geopandas的空间数据分析系列 ...
- (数据科学学习手札50)基于Python的网络数据采集-selenium篇(上)
一.简介 接着几个月之前的(数据科学学习手札31)基于Python的网络数据采集(初级篇),在那篇文章中,我们介绍了关于网络爬虫的基础知识(基本的请求库,基本的解析库,CSS,正则表达式等),在那篇文 ...
- (数据科学学习手札47)基于Python的网络数据采集实战(2)
一.简介 马上大四了,最近在暑期实习,在数据挖掘的主业之外,也帮助同事做了很多网络数据采集的内容,接下来的数篇文章就将一一罗列出来,来续写几个月前开的这个网络数据采集实战的坑. 二.马蜂窝评论数据采集 ...
- (数据科学学习手札32)Python中re模块的详细介绍
一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...
- (数据科学学习手札80)用Python编写小工具下载OSM路网数据
本文对应脚本已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们平时在数据可视化或空间数据分析的过程中经常会 ...
- (数据科学学习手札90)Python+Kepler.gl轻松制作时间轮播图
本文示例代码及数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 Kepler.gl作为一款强大的开源地理信 ...
- (数据科学学习手札55)利用ggthemr来美化ggplot2图像
一.简介 R中的ggplot2是一个非常强大灵活的数据可视化包,熟悉其绘图规则后便可以自由地生成各种可视化图像,但其默认的色彩和样式在很多时候难免有些过于朴素,本文将要介绍的ggthemr包专门针对原 ...
- (数据科学学习手札49)Scala中的模式匹配
一.简介 Scala中的模式匹配类似Java中的switch语句,且更加稳健,本文就将针对Scala中模式匹配的一些基本实例进行介绍: 二.Scala中的模式匹配 2.1 基本格式 Scala中模式匹 ...
随机推荐
- java4
1:如何制作帮助文档(了解) (1)写一个类 (2)加入文档注释 (3)通过javadoc工具生成即可 javadoc -d 目录 -author -version ArrayTool.java 2: ...
- 关于WPF中文件夹浏览对话框的方式
文件夹浏览时dialogresult要写全引用路径 string path=null; FolderBrowserDialog fbd = new FolderBrowserDialog(); fbd ...
- 动态规划 - 最长公共子序列(LCS)
最长公共子序列也是动态规划中的一个经典问题. 有两个字符串 S1 和 S2,求一个最长公共子串,即求字符串 S3,它同时为 S1 和 S2 的子串,且要求它的长度最长,并确定这个长度.这个问题被我们称 ...
- WP8.1:关于屏幕尺寸和分辨率的那些事儿
目前市面上的Windows Phone设备越来越多,尺寸和分辨率也越来越多,特别是WP8.1时代的到来.做过wp开发的人都知道应用适配其实较安卓要简单太多了,其中有一个重要原因,就是微软号称所有WP设 ...
- Mac OS X 10.10 Yosemite下安装java、jdk、mysql、maven、idea
Mac OS X Yosemite已经在2014年10月17日正式发布了. 作为一个java开发者,尝鲜第一时间安装了最新版本. 和之前的OS X系统还是有很多不同的.下面主要在java开发环境方面做 ...
- io外挂
c++里最快的io方式是什么呢? 详见这里. 同时给出一个比较常用的方式,就是用fread.然后自己解析文本,而不是用cin或者scanf,见这里: //fast io test #include & ...
- SQL常用语句,随时用随时更新
更多详细说明文档查询 http://www.postgres.cn/docs/9.5/infoschema-columns.html 1.1通过表名查询表的属性 SELECT * FROM sys.s ...
- 保证Activity启动时每次都调用create
原文:https://stackoverflow.com/questions/41766547/run-oncreate-every-time-android-app-is-opened If you ...
- Educational Codeforces Round 44 (Rated for Div. 2)
题目链接:https://codeforces.com/contest/985 ’A.Chess Placing 题意:给了一维的一个棋盘,共有n(n必为偶数)个格子.棋盘上是黑白相间的.现在棋盘上有 ...
- 在properties.xml中定义变量,在application.xml中取值问题
如果为application.xml中的变量赋默认值,同时又在properties.xml中变量赋值,而加载后是取不到properties.xml中的值的问题. 解决这个问题需要加上黑体部分配置: & ...