交互函数#
ipywidgets.interact
自动创建用户界面(UI)控件,用于以交互方式探索代码和数据。
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
基础的 interact
#
在最基本的层面上,interact
自动为函数参数生成 UI 控件,然后在你交互式地操作这些控件时,使用这些参数调用函数。要使用 interact
,你需要定义你想要探索的函数。
这里有函数,它返回其唯一的参数 x
。
def f(x):
return x
当你将这个函数作为第一个参数传递给 interact
,并提供一个整数关键字参数(x=10
)时,会生成一个滑块并与函数参数绑定。
interact(f, x=10);
当你移动滑块时,函数会被调用,并打印其返回值。
如果你传递 True
或 False
,interact
将生成复选框:
interact(f, x=True);
如果你传递字符串,interact
将生成文本框。
interact(f, x='Hi there!');
interact
也可以作为装饰器使用。这允许你定义函数并立即与之交互。正如这个例子所展示的,interact
也适用于具有多个参数的函数。
@interact(x=True, y=1.0)
def g(x, y):
return (x, y)
使用 fixed
固定参数#
有时你可能想要使用 interact
探索函数,但将一个或多个参数固定为特定值。这可以通过用 fixed
函数包装这些值来实现。
def h(p, q):
return (p, q)
当调用 interact
时,传递 fixed(20)
给 q
以将其固定在值 20
。
interact(h, p=5, q=fixed(20));
注意,只为 p
生成了滑块,因为 q
的值是固定的。
小部件缩写#
当你向 interact
传递整数值的关键字参数 10
(x=10
)时,它会生成整数滑块控件,范围为 [-10,+3*10]
。在这种情况下,10
是实际滑块小部件的缩写:
IntSlider(min=-10, max=30, step=1, value=10)
实际上,如果我们将这个 IntSlider
作为 x
的关键字参数传递,我们可以得到相同的结果:
interact(f, x=widgets.IntSlider(min=-10, max=30, step=1, value=10));
下表概述了不同的参数类型以及它们如何映射到交互控件:
关键字参数 |
小部件 |
---|---|
|
|
|
|
如果传递的是整数,则为 |
|
如果传递的是浮点数,则为 |
|
|
|
注意,如果给定一个列表或元组列表(表示离散选择),则使用下拉菜单;如果给定一个元组(表示范围),则使用滑块。
你已经看到了上面的复选框和文本小部件是如何工作的。在这里,我们提供了有关滑块和下拉菜单不同缩写的更多细节。
如果传递了一个整数的2元组 (min, max)
,则会生成具有这些最小值和最大值(包括边界)的整数滑块。在这种情况下,默认步长为 1
。
interact(f, x=(0,4));
如果传递了一个整数的 3 元组 (min,max,step)
,则还可以设置步长。
interact(f, x=(0,8,2));
如果元组中的 任何 元素是浮点数,则会产生浮点值滑块。这里最小值是 0.0
,最大值是 10.0
,步长是 0.1
(默认值)。
interact(f, x=(0.0,10.0));
通过在元组中传递第三个元素,可以更改步长。
interact(f, x=(0.0,10.0,0.01));
对于整数和浮点值滑块,你可以通过将默认关键字参数传递给底层的 Python 函数来设置小部件的初始值。在这里,我们将一个浮点滑块的初始值设置为 5.5
。
@interact(x=(0.0,20.0,0.5))
def h(x=5.5):
return x
通过传递字符串列表来构造下拉菜单(Dropdown
)。在这种情况下,这些字符串既用作下拉菜单 UI 中的名称,又传递给底层的 Python 函数。
interact(f, x=['apples','oranges']);
如果你想要向下传递非字符串值到 Python 函数的下拉菜单,你可以传递 ('label', value)
对的列表。第一个项是下拉菜单 UI 中的名称,第二个项是传递给底层 Python 函数的参数值。
interact(f, x=[('one', 10), ('two', 20)]);
最后,如果你需要比缩写提供的更精细的控制,你可以传递 ValueWidget
实例作为参数。ValueWidget
是旨在控制单个值的小部件。大多数与 ipywidgets
捆绑在一起的小部件都继承自 ValueWidget
。有关更多信息,请参阅关于小部件类型的 WidgetCustom。
interact(f, x=widgets.Combobox(options=["Chicago", "New York", "Washington"], value="Chicago"));
interactive
#
除了 interact
,IPython 还提供了另一个函数 interactive
,当你想重用生成的小部件或访问绑定到 UI 控件的数据时,这个函数非常有用。
请注意,与 interact
不同,函数的返回值不会自动显示,但是你可以在函数内部使用 IPython.display.display
来显示值。
这是显示其两个参数之和并返回该和的函数。如果不希望显示函数的结果,可以省略 display
行。
from IPython.display import display
def f(a, b):
display(a + b)
return a+b
与 interact
不同,interactive
返回 Widget
实例,而不是立即显示小部件。
w = interactive(f, a=10, b=20)
这个小部件是 interactive
,它是 VBox
的子类,VBox
是其他小部件的容器。
type(w)
ipywidgets.widgets.interaction.interactive
这个 interactive
的子对象是两个整数值滑块和一个输出小部件,由上述的小部件缩写生成。
w.children
(IntSlider(value=10, description='a', max=30, min=-10),
IntSlider(value=20, description='b', max=60, min=-20),
Output())
要实际显示这些小部件,你可以使用 IPython 的 display
函数。
display(w)
此时,UI 控件的工作方式就像使用了 interact
一样。你可以交互地操作它们,函数将被调用。然而,interactive
返回的小部件实例还允许你访问底层 Python 函数的当前关键字参数和返回值。
以下是当前的关键字参数。如果你在操作滑块后重新运行这个单元格,这些值将会发生变化。
w.kwargs
{'a': 10, 'b': 20}
这是函数当前的返回值。
w.result
30
禁用连续更新#
在与长时间运行的函数进行交互时,实时反馈不是有帮助的,反而是一种负担。请参阅以下示例:
def slow_function(i):
print(int(i),list(x for x in range(int(i)) if
str(x)==str(x)[::-1] and
str(x**2)==str(x**2)[::-1]))
return
%%time
slow_function(1e6)
1000000 [0, 1, 2, 3, 11, 22, 101, 111, 121, 202, 212, 1001, 1111, 2002, 10001, 10101, 10201, 11011, 11111, 11211, 20002, 20102, 100001, 101101, 110011, 111111, 200002]
CPU times: user 767 ms, sys: 0 ns, total: 767 ms
Wall time: 766 ms
请注意,即使在滑块上拖动鼠标时,输出也会更新。这对于长时间运行的函数来说并不有用,因为会导致卡顿:
from ipywidgets import FloatSlider
interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5));
有两种方法可以缓解这个问题。你可以仅在需求时执行,或者将执行限制在鼠标释放事件上。
interact_manual
#
interact_manual
函数提供了一种交互的变体,允许你限制执行,使其仅在需求时进行。在交互控件中添加了一个按钮,允许你触发执行事件。
interact_manual(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5));
通过使用 dict
作为第二个参数,你也可以在 interactive
中实现同样的功能,如下所示。
slow = interactive(slow_function, {'manual': True}, i=widgets.FloatSlider(min=1e4, max=1e6, step=1e4))
# slow
continuous_update
#
如果你正在使用滑块小部件,可以将 continuous_update
参数设置为 False
。continuous_update
是滑块小部件的一个参数,它将执行限制在鼠标释放事件上。
# interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5, continuous_update=False));
对用户界面的更多控制:interactive_output
#
interactive_output
提供了额外的灵活性:你可以控制 UI 元素如何布局。
与 interact
、interactive
和 interact_manual
不同,interactive_output
不会为小部件生成用户界面。这是强大的,因为这意味着你可以创建小部件,将其放入盒子中,然后将小部件传递给 interactive_output
,并对小部件及其布局进行控制。
a = widgets.IntSlider()
b = widgets.IntSlider()
c = widgets.IntSlider()
ui = widgets.HBox([a, b, c])
def f(a, b, c):
print((a, b, c))
out = widgets.interactive_output(f, {'a': a, 'b': b, 'c': c})
# display(ui, out)
相互依赖的参数#
使用 observe
可以手动表达相互依赖的参数。请参阅以下示例,其中一个变量用来描述另一个变量的边界。欲了解更多信息,请查看 小部件事件示例笔记本。
x_widget = FloatSlider(min=0.0, max=10.0, step=0.05)
y_widget = FloatSlider(min=0.5, max=10.0, step=0.05, value=5.0)
def update_x_range(*args):
x_widget.max = 2.0 * y_widget.value
y_widget.observe(update_x_range, 'value')
def printer(x, y):
print(x, y)
# interact(printer,x=x_widget, y=y_widget);
闪烁和跳动的输出#
有时,你可能会注意到交互输出会闪烁和跳动,导致笔记本滚动位置在更新输出时发生变化。交互控件有一个布局,因此我们可以将其高度设置为一个合适的值(目前是手动选择的),以便在更新时不会改变大小。
%matplotlib inline
from ipywidgets import interactive
import matplotlib.pyplot as plt
import numpy as np
def f(m, b):
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
plt.show()
interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
# interactive_plot
与多个函数交互#
你可能想要让一个单独的小部件与多个函数进行交互。这可以通过简单地使用 interactive_output()
函数将小部件链接到两个函数来实现。这些函数的执行顺序将是它们被链接到小部件的顺序。
import ipywidgets as widgets
from IPython.display import display
a = widgets.IntSlider(value=5, min=0, max=10)
def f1(a):
display(a)
def f2(a):
display(a * 2)
out1 = widgets.interactive_output(f1, {'a': a})
out2 = widgets.interactive_output(f2, {'a': a})
display(a)
display(out1)
display(out2)