ipywidgets
简单事件#
Button
不是用来表示数据类型的。相反,按钮小部件用于处理鼠标点击。Button
的 on_click
方法可以用来注册当按钮被点击时要调用的函数。on_click
的文档字符串可以在下面看到。
# 为了保证 `JupyterLite` 可用,需要 notebook 开头添加:
%pip install -q ipywidgets
Note: you may need to restart the kernel to use updated packages.
import ipywidgets as widgets
print(widgets.Button.on_click.__doc__)
Register a callback to execute when the button is clicked.
The callback will be called with one argument, the clicked button
widget instance.
Parameters
----------
remove: bool (optional)
Set to true to remove the callback from the list of callbacks.
示例#
由于按钮点击是无状态的,它们通过自定义消息从前端传输到后端。通过使用 on_click
方法,下面展示了在点击时打印消息的按钮。要捕获 print
(或其他任何类型的输出)并确保其显示,请确保将其发送到 Output
小部件(或将您想要显示的信息放入 HTML
小部件)。
from IPython.display import display
import ipywidgets as widgets
button = widgets.Button(description="点击")
output = widgets.Output(layout={'border': '1px solid black'})
def on_button_clicked(b):
with output:
print("Button clicked.")
button.on_click(on_button_clicked, remove=False)
display(button, output)
Traitlet 事件#
小部件属性是 IPython traitlets,而 traitlets 是有事件的。要处理变化,可以使用小部件的 observe
方法注册回调函数。observe
的文档字符串可以在下面看到。
print(widgets.Widget.observe.__doc__)
Setup a handler to be called when a trait changes.
This is used to setup dynamic notifications of trait changes.
Parameters
----------
handler : callable
A callable that is called when a trait changes. Its
signature should be ``handler(change)``, where ``change`` is a
dictionary. The change dictionary at least holds a 'type' key.
* ``type``: the type of notification.
Other keys may be passed depending on the value of 'type'. In the
case where type is 'change', we also have the following keys:
* ``owner`` : the HasTraits instance
* ``old`` : the old value of the modified trait attribute
* ``new`` : the new value of the modified trait attribute
* ``name`` : the name of the modified trait attribute.
names : list, str, All
If names is All, the handler will apply to all traits. If a list
of str, handler will apply to all names in the list. If a
str, the handler will apply just to that name.
type : str, All (default: 'change')
The type of notification to filter by. If equal to All, then all
notifications are passed to the observe handler.
签名#
在文档字符串中提到,注册的回调函数必须具有 handler(change)
的形式,其中 change
是一个字典,用于保存有关更改的信息。
通过使用该方法,下面是一个示例,展示了如何在 IntSlider
的值发生变化时输出其值。
int_range = widgets.IntSlider()
output2 = widgets.Output(layout={'border': '1px solid black'})
display(int_range, output2)
def on_value_change(change):
with output2:
print(change['new'])
int_range.observe(on_value_change, names='value')
链接小部件#
通常,您可能希望简单地将小部件属性链接在一起。与使用裸 traitlets
事件相比,属性同步可以通过更简单的方式进行。
在内核中链接 traitlets
属性#
第一种方法是使用 traitlets
模块中的 link
和 dlink
函数(这两个函数由 ipywidgets
模块重新导出以方便使用)。这只适用于我们正在与实时内核进行交互的情况。
caption = widgets.Label(value='The values of slider1 and slider2 are synchronized')
sliders1, slider2 = widgets.IntSlider(description='Slider 1'),\
widgets.IntSlider(description='Slider 2')
l = widgets.link((sliders1, 'value'), (slider2, 'value'))
display(caption, sliders1, slider2)
caption = widgets.Label(value='Changes in source values are reflected in target1')
source, target1 = widgets.IntSlider(description='Source'),\
widgets.IntSlider(description='Target 1')
dl = widgets.dlink((source, 'value'), (target1, 'value'))
display(caption, source, target1)
traitlets.link
和 traitlets.dlink
函数返回 Link
或 DLink
对象。通过调用 unlink
方法可以断开链接。
# l.unlink()
# dl.unlink()
在内核中注册回调以响应 trait
的变化#
由于 Python 端的部件属性是 traitlets
,因此每当模型从前端获取更新时,您可以注册处理程序来处理更改事件。
传递给 observe
的处理程序将使用 change
参数进行调用。change
对象至少包含 type
键和 name
键,分别对应于通知的类型和触发通知的属性的名称。
根据 type
的值,可能会传递其他键。在 type
为 change
的情况下,我们还有以下几个键:
owner
:HasTraits
实例old
: 修改后的trait
属性的旧值new
: 修改后的trait
属性的新值name
: 修改后的trait
属性的名称。
caption = widgets.Label(value='The slider value is in its initial position.')
slider = widgets.IntSlider(min=-5, max=5, value=1, description='Slider')
def handle_slider_change(change):
caption.value = 'The slider value is ' + (
'negative' if change.new < 0 else 'nonnegative'
)
slider.observe(handle_slider_change, names='value')
display(caption, slider)
从客户端链接小部件属性#
在同步 traitlets
属性时,由于往返服务器端的延迟,您可能会遇到延迟。您还可以使用链接小部件直接在浏览器中链接小部件属性,可以选择单向或双向方式。
在没有内核的情况下将小部件嵌入到 html
网页中时,Javascript 链接会持续存在。
caption = widgets.Label(value='The values of range1 and range2 are synchronized')
range1, range2 = widgets.IntSlider(description='Range 1'),\
widgets.IntSlider(description='Range 2')
l = widgets.jslink((range1, 'value'), (range2, 'value'))
display(caption, range1, range2)
caption = widgets.Label(value='Changes in source_range values are reflected in target_range1')
source_range, target_range1 = widgets.IntSlider(description='Source range'),\
widgets.IntSlider(description='Target range 1')
dl = widgets.jsdlink((source_range, 'value'), (target_range1, 'value'))
display(caption, source_range, target_range1)
widgets.jslink
函数返回 Link
小部件。通过调用 unlink
方法可以断开链接。
# l.unlink()
# dl.unlink()
内核链接和客户端链接的区别#
内核链接是指通过 Python 进行链接。如果在内核中链接了两个滑块,当一个滑块发生变化时,浏览器会向内核(在这种情况下是 Python)发送消息,更新变化的滑块,然后内核中的链接小部件将更改传播到内核中的另一个滑块对象,然后另一个滑块的内核对象会向浏览器发送消息,以更新浏览器中另一个滑块的视图。如果内核没有运行(如在静态网页中),那么控件将不会被链接。
使用 jslink
(即,在浏览器端)进行链接意味着在 JavaScript 中构建链接。当一个滑块发生变化时,浏览器中运行的 JavaScript 会更改浏览器中另一个滑块的值,完全不需要与内核进行通信。如果滑块附加到内核对象,每个滑块将独立地更新它们在内核端的对象。
要了解两者之间的区别,请访问 ipywidgets
文档中此页面的静态版本,并尝试使用页面底部附近的滑块。使用 link
和 dlink
在内核中链接的那些滑块不再链接,但是使用 jslink
和 jsdlink
在浏览器中链接的那些滑块仍然保持链接。
持续更新#
一些部件提供了在其 continuous_update
属性中进行选择的选项,可以在持续更新值和仅在用户提交值时(例如,通过按下 Enter 键或从控件导航离开)才更新值之间进行选择。在接下来的示例中,我们看到“延迟”控件仅在用户完成拖动滑块或提交文本框后传输其值。而“连续”控件则在其值发生变化时持续传输它们的值。尝试在每个文本框中输入一个两位数,或拖动每个滑块,以观察差异。
a = widgets.IntSlider(description="Delayed", continuous_update=False)
b = widgets.IntText(description="Delayed", continuous_update=False)
c = widgets.IntSlider(description="Continuous", continuous_update=True)
d = widgets.IntText(description="Continuous", continuous_update=True)
widgets.jslink((a, 'value'), (b, 'value'))
widgets.jslink((a, 'value'), (c, 'value'))
widgets.jslink((a, 'value'), (d, 'value'))
widgets.VBox([a,b,c,d])
滑块、Text
和 Textarea
控件默认设置为 continuous_update=True
。IntText
和其他用于输入整数或浮点数的文本框默认设置为 continuous_update=False
(因为通常你会想在按下 Enter 键或导航离开文本框之前输入完整的数字)。