使用Interact#
interact 函数 (ipywidgets.interact) 自动创建用户界面(UI)控件,用于交互式探索代码和数据。这是开始使用 IPython 部件的最简单方式。
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 的值是固定的。
Widget 缩写#
当你传递一个整数值关键字参数 10(x=10)给 interact 时,它会生成一个整数值滑块控件,其范围为 [-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));
下表概述了不同类型的参数及其如何映射到交互式控件:
| 关键字参数 | Widget |
| `True` 或 `False` | Checkbox |
| `'Hi there'` | 文本 |
| `value` 或 `(最小,最大)` 或 `(最小,最大,步长)` 如果传递的是整数 | IntSlider |
| 如果传递的是浮点数,则为`value`或`(min,max)`或`(min,max,step)` | FloatSlider |
| `['orange','apple']` 或 `[('one', 1), ('two', 2)] | Dropdown |
您已经了解了上述复选框和文本小部件的工作方式。这里,将提供关于滑块和下拉菜单不同缩写的更多详细信息。
如果传入一个包含两个整数的元组 (min, max),将生成一个具有这些最小和最大值(包含在内)的整数值滑块。在这种情况下,将使用默认步长 1。
interact(f, x=(0,4));
如果传入一个由三个整数组成的元组 (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
下拉菜单通过传递一个字符串列表来构建。在这种情况下,这些字符串既用于下拉菜单界面中的名称,也传递给底层的Python函数。
interact(f, x=['apples','oranges']);
如果你想要一个下拉菜单,它将非字符串值传递给Python函数,你可以传递一个('label', value)对的列表。第一项是下拉菜单用户界面中的名称,第二项是传递给底层Python函数的参数值。
interact(f, x=[('one', 10), ('two', 20)]);
最后,如果您需要比缩写提供更精细的控制,可以传递一个ValueWidget实例作为参数。ValueWidget是一个旨在控制单个值的小部件。大多数bundled with ipywidgets的小部件都继承自ValueWidget。有关更多信息,请参阅this section关于小部件类型。
interact(f, x=widgets.Combobox(options=["Chicago", "New York", "Washington"], value="Chicago"));
类型注解#
如果您与interact一起使用的函数使用了类型注解,interact或许可以利用它们来确定在自动生成的UI中使用哪些UI组件。例如,给定一个拥有类型为float的参数注解的函数
def f(x: float):
return x
那么interact将创建一个带有FloatText组件的用户界面,无需传递任何值或缩写。
interact(f);
下表列出了不同的标注类型及其如何映射到交互式控件:
| 类型注解 | Widget |
| `bool` | 复选框 |
| `str` | 文本 |
| `int` | 整数文本 |
| `float` | 浮点文本 |
| `Enum` 子类 | Dropdown |
其他类型标注将被忽略。
如果值或缩写被传递给interact函数,在确定创建哪些小部件时,这些将覆盖任何类型注解。
被标注为Enum子类的参数将创建一个下拉菜单,其标签为枚举名称,并将对应的值传递给函数参数。
from enum import Enum
class Color(Enum):
red = 0
green = 1
blue = 2
def h(color: Color):
return color
当interact与函数h一起使用时,它创建的 Dropdown 小部件将具有选项"red"、"green"和"blue",而传递给函数的相应值将是Color.red、Color.green和Color.blue。
interact(h);
交互式#
除了 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的子类,作为其他部件的容器。
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(outputs=({'output_type': 'display_data', 'metadata': {}, 'data': {'text/plain': '30'}},)))
要实际显示这些部件,您可以使用IPython的display函数。
display(w)
此时,用户界面控件的运作方式与使用 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 130 ms, sys: 1.12 ms, total: 131 ms
Wall time: 131 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));
您可以使用interactive通过dict作为第二个参数实现相同的效果,如下所示。
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手动表达。请参见以下示例,其中一个变量用于描述另一个变量的边界。更多信息,请参阅widget events example notebook。
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)