“作为数据分析的重要一环,把得到的数据或者分析结果以图表的方式展示,是一种直观、优雅的方式。Dash是基于Flask的Python可视化工具,我在学习之余尝试着翻译官方的Tutorial,有不足之处,还望不吝指正”
Dash Callbacks
本章节描述了如何使Dash应用程序具有可交互性。
01.Dash APP Layout
让我们从一个简单的例子开始
试着在输入框里输入信息,输出组件的子项就会立即更新。让我们分解一下这里发生的事情:
1. 我们应用程序的输入(Input)和输出(Output)接口,都是通过装饰器app.callback来方式声明的。
2. 在Dash里,我们应用程序的输入和输出只是特定组件的属性。在例子当中,我们的输入是ID为“my-id”组件的value属性,我们的输出是ID为“my-div”组件的children属性。
3. 每当输入属性发生改变时,都会自动调用被回调装饰器callback包装的函数。Dash使用输入属性的新值作为输入参数,提供给函数调用,接着Dash使用函数返回的内容更新输出组件的属性。
4. component_id和component_property关键字是可选的(每个对象只有两个参数),为了清晰可见,例子中包含了它们,但是为了简洁和可读性,可以省略它们。
5. 不要混淆了dash.dependencies.Input对象和dash_core_components.Input对象,前者只应用于回调,而后者则是真实的组件。
6. 请注意我们时怎么在布局中给my-div组件的children属性赋值的,当Dash程序启动时,它会自动使用输入组件的初始值来调用回调函数,以填充输出组件的初始状态。所以,即使我们使用了类似html.Div(id='my-div', children='Hello world')这种的写法,也会在程序启动时被覆盖的。
有点像Microsoft Excel的编程,每当输入单元格发生变化时,依赖于该单元格的所有单元格都会自动更新,这成为“反应是编程”。
还记得每个组件是如何通过其关键字参数集来被完整描述的吗?那些属性现在很重要,通过与Dash交互,我们可以使用回调函数动态更新任何属性。我们经常会更新组件的子节点以显示新文本或dcc.Graph组件的图形以显示新数据,但我们也可以更新组件的样式甚至更新dcc.Dropdown组件的可用选项!
让我们看一下dcc.Slider更新dcc.Graph的另一个例子:
在例子当中,Slider的“value”属性是app的输入,而app的输出则是Graph的“figure”属性。当Slider的value变化时,Dash都会使用新的数据来调用callback函数update_figure。该函数使用此新值过滤数据集,构造一个图形对象,并将其返回到Dash应用程序。
这个例子中有一些不错的模式:
1. 我们使用Pandas库导入和过滤内存中的数据集。
2. 我们在app的最开始节点加载数据集df = pd.read_csv(‘…’),这个数据集df处于程序的全局状态,可以在回调函数的内部读取。
3. 加载数据到内存中可能很昂贵,通过在应用程序开始时而不是在回调函数内部加载查询数据,可以确保我们只在应用程序启动时执行此操作。当用户访问应用程序会与程序交互时,数据(df)已经在内存当中了。可能的情况下,昂贵的初始化(如下载或查询数据)应该在应用程序的全局范围而不是在回调函数中完成。
4. 回调函数不会改变原始数据,它只是通过Pandas过滤器过滤来创建数据集副本。这一点非常重要:你的回调函数不应该改变其范围之外的变量。如果你的回调函数改变了全局变量,那么一个用户的会话可能会影响下一个用户的会话,同时当应用程序是以多进程或者多线程的方式部署时,这些修改不会在会话中共享。
02.多输入
在Dash程序中,任何“output”都可以有多个“input”组件。这里有一个绑定了5个输入到1个输出的例子,注意下app.callback是如何在第二个参数的列表里展示所有的5个输入的。
在例子当中,当Dropdown、Slider或者RadioItems的value属性变化时,update_graph函数都会被调用。
update_graph函数的输入参数是每个input属性的最新值或者当前值,按照其指定的顺序排列。
即使一次只有一个输入发生变化,Dash程序可以搜集所有指定的输入属性的当前状态,并将它们传递给你的函数。
03.多输出
每一个Dash回调函数只能更新唯一的输出属性,如果想实现多输出,需要编写多个函数。
你还可以将输入和输出连接在一起:一个回调函数的输出可以是另一个回调函数的输入。
此模式可以用于创建动态UI,其中一个输入组件更新下一个输入组件的可选项。一个简单的例子:
第一个回调函数根据第一个RadioItems组件中的选定值来更新第二个RadioItems组件的可选项。
第二个回调函数options属性改变时设置初始值,将它设置为options数组中的第一个值
最后一个回调函数展示了每个组件的选定值。如果更改了国家/地区的RadioItems组件的值,Dash将会等待,直到cities组件的值也被更新了,才会调用最终的回调函数。这时为了防止回调函数以不一致的状态被调用,例如“USA”和“Montréal”。
04. 综述
我们已经介绍了Dash中回调函数的基本原理,Dash应用程序是基于一系列简单但是强大的原则构建的:声明UI,可以通过反应性和功能性Python回调函数来自定义。声明性组件的每个元素属性都可以通过回调函数进行更新,属性的子集(如dcc.Dropdown的value属性)可以由用户在界面中编辑。