与 ipywidgets 事件交互和绘图会生成许多图表

FZN*_*ZNB 6 interactive widget matplotlib python-3.x jupyter-notebook

我正在尝试使用小部件事件来制作交互式图表。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

import ipywidgets as widgets

def myplot(n):
    x = np.linspace(-5, 5, 30)
    y = x**n

    fig, ax = plt.subplots(nrows=1, ncols=1);
    ax.plot(x, y)
    ax.set_xlabel('x')
    ax.set_ylabel('y')

    plt.show()
Run Code Online (Sandbox Code Playgroud)

Interact 按预期工作(它以交互方式更改数字):

widgets.interact(myplot, n=(0,5));
Run Code Online (Sandbox Code Playgroud)

然而,下面的代码片段创建了当您与滑块交互时出现在下面的几个图形。

n_widget = widgets.IntSlider(
                value=2,
                min=0,
                max=5)

def on_value_change(change):
    myplot(n=n_widget.value)

n_widget.observe(on_value_change)
display(n_widget)
Run Code Online (Sandbox Code Playgroud)

我可以像使用 widgets.interact() 一样更新绘图吗?


我当前的安装是使用 conda 和 Python 3.6(Windows 机器)。

ipywidgets                7.1.0                     
jupyter                   1.0.0              
jupyter_client            5.2.1                  
jupyter_console           5.2.0             
jupyter_core              4.4.0              
matplotlib                2.1.1             
notebook                  5.3.1               
numpy                     1.14.0     
Run Code Online (Sandbox Code Playgroud)

Imp*_*est 5

请注意,以下是 ipywidgets 版本 < 7.0 的工作解决方案。有关 ipywidgets >= 7.0 的解决方案,请参阅此 GitHub 问题

虽然在许多简单的情况下plt.show()可以很好地替换单元格的输出,但情况并非总是如此。在 Jupyter 中使用交互元素时,使用IPython.display.display.

在这里,您可能不想为每个交互创建一个新的绘图。相反,只需为绘图设置新数据就足够了。然后,您可以自动缩放新数据的绘图并显示图形。IPython.display.clear_output一旦显示新图形,您可以使用清除输出。这确保了输出单元格中始终存在单个图,而与interact或的使用无关observe

def myplot(n):
    line.set_ydata(x**n)
    ax.relim()
    ax.autoscale()
    display(fig)
    clear_output(wait=True)
Run Code Online (Sandbox Code Playgroud)

完整的笔记本:

# cell 1
%%capture
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display, clear_output
import ipywidgets as widgets

fig, ax = plt.subplots(nrows=1, ncols=1);
x = np.linspace(-5, 5, 30)
y = x**0

line, = ax.plot(x, y)
ax.set_xlabel('x')
ax.set_ylabel('y')

def myplot(n):
    line.set_ydata(x**n)
    ax.relim()
    ax.autoscale()
    display(fig)
    clear_output(wait=True)

#cell2
widgets.interact(myplot, n=(0,5));

#cell3
n_widget = widgets.IntSlider(
                value=2,
                min=0,
                max=5)

def on_value_change(change):
    myplot(n=n_widget.value)

n_widget.observe(on_value_change)
display(n_widget)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述