本文示例代码已上传至我的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应用需要做什么:

  • 确定输入与输出部件

一个可交互的系统一定是有输入输出的,我们开头导入的InputOutput对象,他们分别扮演着输入者输出者两种角色,其各自的第一个参数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应用开发——回调交互篇(上)的更多相关文章

  1. (数据科学学习手札75)基于geopandas的空间数据分析——坐标参考系篇

    本文对应代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在上一篇文章中我们对geopandas中的数据结 ...

  2. (数据科学学习手札84)基于geopandas的空间数据分析——空间计算篇(上)

    本文示例代码.数据及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在本系列之前的文章中我们主要讨论了g ...

  3. (数据科学学习手札88)基于geopandas的空间数据分析——空间计算篇(下)

    本文示例代码及数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在基于geopandas的空间数据分析系列 ...

  4. (数据科学学习手札50)基于Python的网络数据采集-selenium篇(上)

    一.简介 接着几个月之前的(数据科学学习手札31)基于Python的网络数据采集(初级篇),在那篇文章中,我们介绍了关于网络爬虫的基础知识(基本的请求库,基本的解析库,CSS,正则表达式等),在那篇文 ...

  5. (数据科学学习手札47)基于Python的网络数据采集实战(2)

    一.简介 马上大四了,最近在暑期实习,在数据挖掘的主业之外,也帮助同事做了很多网络数据采集的内容,接下来的数篇文章就将一一罗列出来,来续写几个月前开的这个网络数据采集实战的坑. 二.马蜂窝评论数据采集 ...

  6. (数据科学学习手札32)Python中re模块的详细介绍

    一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...

  7. (数据科学学习手札80)用Python编写小工具下载OSM路网数据

    本文对应脚本已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们平时在数据可视化或空间数据分析的过程中经常会 ...

  8. (数据科学学习手札90)Python+Kepler.gl轻松制作时间轮播图

    本文示例代码及数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 Kepler.gl作为一款强大的开源地理信 ...

  9. (数据科学学习手札55)利用ggthemr来美化ggplot2图像

    一.简介 R中的ggplot2是一个非常强大灵活的数据可视化包,熟悉其绘图规则后便可以自由地生成各种可视化图像,但其默认的色彩和样式在很多时候难免有些过于朴素,本文将要介绍的ggthemr包专门针对原 ...

  10. (数据科学学习手札49)Scala中的模式匹配

    一.简介 Scala中的模式匹配类似Java中的switch语句,且更加稳健,本文就将针对Scala中模式匹配的一些基本实例进行介绍: 二.Scala中的模式匹配 2.1 基本格式 Scala中模式匹 ...

随机推荐

  1. java4

    1:如何制作帮助文档(了解) (1)写一个类 (2)加入文档注释 (3)通过javadoc工具生成即可 javadoc -d 目录 -author -version ArrayTool.java 2: ...

  2. 关于WPF中文件夹浏览对话框的方式

    文件夹浏览时dialogresult要写全引用路径 string path=null; FolderBrowserDialog fbd = new FolderBrowserDialog(); fbd ...

  3. 动态规划 - 最长公共子序列(LCS)

    最长公共子序列也是动态规划中的一个经典问题. 有两个字符串 S1 和 S2,求一个最长公共子串,即求字符串 S3,它同时为 S1 和 S2 的子串,且要求它的长度最长,并确定这个长度.这个问题被我们称 ...

  4. WP8.1:关于屏幕尺寸和分辨率的那些事儿

    目前市面上的Windows Phone设备越来越多,尺寸和分辨率也越来越多,特别是WP8.1时代的到来.做过wp开发的人都知道应用适配其实较安卓要简单太多了,其中有一个重要原因,就是微软号称所有WP设 ...

  5. Mac OS X 10.10 Yosemite下安装java、jdk、mysql、maven、idea

    Mac OS X Yosemite已经在2014年10月17日正式发布了. 作为一个java开发者,尝鲜第一时间安装了最新版本. 和之前的OS X系统还是有很多不同的.下面主要在java开发环境方面做 ...

  6. io外挂

    c++里最快的io方式是什么呢? 详见这里. 同时给出一个比较常用的方式,就是用fread.然后自己解析文本,而不是用cin或者scanf,见这里: //fast io test #include & ...

  7. SQL常用语句,随时用随时更新

    更多详细说明文档查询 http://www.postgres.cn/docs/9.5/infoschema-columns.html 1.1通过表名查询表的属性 SELECT * FROM sys.s ...

  8. 保证Activity启动时每次都调用create

    原文:https://stackoverflow.com/questions/41766547/run-oncreate-every-time-android-app-is-opened If you ...

  9. Educational Codeforces Round 44 (Rated for Div. 2)

    题目链接:https://codeforces.com/contest/985 ’A.Chess Placing 题意:给了一维的一个棋盘,共有n(n必为偶数)个格子.棋盘上是黑白相间的.现在棋盘上有 ...

  10. 在properties.xml中定义变量,在application.xml中取值问题

    如果为application.xml中的变量赋默认值,同时又在properties.xml中变量赋值,而加载后是取不到properties.xml中的值的问题. 解决这个问题需要加上黑体部分配置: & ...