Python 实施";重置";在Jupyter中使用@interact decorator时的按钮

Python 实施";重置";在Jupyter中使用@interact decorator时的按钮,python,jupyter,ipywidgets,Python,Jupyter,Ipywidgets,我试图用一个简单的按钮将小部件“重置”为某些默认值。我正在Jupyter实验室环境中使用@interact装饰器。问题是小部件标识符的值被复制到函数中用作浮点变量的相同标识符,因此我无法在这个新范围内再访问它们。下面是一个简短的示例(不起作用): 有人知道如何向修饰函数的作用域发送对原始小部件对象的引用吗?我也会接受简单的方法来实现一个按钮来重置这些滑块 :-D 编辑:更正了文本流我可以在不使用@interact装饰器的情况下找到它(现在它正在工作),但我不满意最终的结果。因此,我仍然愿意为那些

我试图用一个简单的按钮将小部件“重置”为某些默认值。我正在Jupyter实验室环境中使用
@interact
装饰器。问题是小部件标识符的值被复制到函数中用作浮点变量的相同标识符,因此我无法在这个新范围内再访问它们。下面是一个简短的示例(不起作用):

有人知道如何向修饰函数的作用域发送对原始小部件对象的引用吗?我也会接受简单的方法来实现一个按钮来重置这些滑块

:-D

编辑:更正了文本流

我可以在不使用
@interact
装饰器的情况下找到它(现在它正在工作),但我不满意最终的结果。因此,我仍然愿意为那些能够清楚/更容易地解释这个问题的人提供正确的答案

无论如何,以下是工作代码:

import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, Button, FloatSlider

def plot_graph(starts_at, ends_at):
    f = lambda x : sum(1/a*np.sin(a*x + np.pi/a) for a in range(1,6))
    x = np.linspace(0, 2*np.pi, 1000)
    plt.plot(x, f(x))
    plt.xlim([starts_at, ends_at])
    
starts_at = FloatSlider(min=0, max=np.pi*0.9, value=0, step=np.pi*0.1)
ends_at = FloatSlider(min=np.pi, max=2*np.pi, value=2*np.pi, step=np.pi*0.1)

def on_button_clicked(_):
    starts_at.value = 0
    ends_at.value = 2*np.pi

button = Button(description="Reset")
button.on_click(on_button_clicked)
display(button)
_ = interact(plot_graph, starts_at=starts_at, ends_at=ends_at)
编辑:从这一点开始的新方法==============================

我选择@Ianhi-answer作为正确答案,因为他指出了在我的问题中需要考虑的问题。谢谢

无论如何,我在这里发布了我使用的最终方案,该方案非常简单,可以满足我的需要,并且我可以在所有交互中重复使用我的重置按钮:

# Preamble ----
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, Button, FloatSlider

def reset_button(defaults={}):
    def on_button_clicked(_):
        for k, v in defaults.items(): 
            k.value = v
    button = Button(description='Reset')
    button.on_click(on_button_clicked)
    display(button)

# Code ----
slider1 = FloatSlider(min=0, max=np.pi*0.9, value=0, step=np.pi*0.1)
slider2 = FloatSlider(min=np.pi, max=2*np.pi, value=2*np.pi, step=np.pi*0.1)
reset_button(defaults={slider1: 0, slider2: 2*np.pi})

@interact(starts_at=slider1, ends_at=slider2)
def plot_graph(starts_at, ends_at):
    f = lambda x : sum(1/a*np.sin(a*x + np.pi/a) for a in range(1,6))
    x = np.linspace(0, 2*np.pi, 1000)
    plt.plot(x, f(x))
    plt.xlim([starts_at, ends_at])

要实现这一点,您必须使用更手动的
交互式输出功能。该功能允许您预先创建小部件,然后将其传入:

将IPyWidget作为小部件导入
将numpy作为np导入
将matplotlib.pyplot作为plt导入
开始\u slider=widgets.FloatSlider(
val=0,
最小值=0,
最大值=np.pi*0.9,
阶跃=np.pi*0.1,
description='开始于'
)
end_slider=widgets.FloatSlider(
val=np.pi,
min=np.pi,
最大值=2*np.pi,
阶跃=np.pi*0.1,
description='结束于'
)
def on_按钮_单击(u):
开始滑动条。值=0
end_slider.value=2*np.pi
按钮=按钮(description=“Reset”)
按钮。单击时(单击时)
def绘图图(从=0开始,到=2*np.pi结束):
f=λx:和(1.6)范围内a的1/a*np.sin(a*x+np.pi/a)
x=np.linspace(0,2*np.pi,1000)
平面图(x,f(x))
plt.xlim([开始于,结束于])
显示(widgets.VBox([start\u slider,end\u slider,button]))
交互式输出(绘图图,{'starts\'at':start\'u slider,'ends\'at':end\'u slider})
然而,每次你更新它时,它都会完全重新生成情节,这可能会导致一个不稳定的体验。因此,如果在笔记本中使用交互式matplotlib后端,也可以使用matplotlib方法(如
.set_data
)重新编写此文件。因此,如果要使用,可以按照中的示例进行操作

通过另一个图书馆 我编写了一个库,以便使用ipywidgets滑块更容易地控制matplotlib绘图。它提供了一个类似于
ipywidgets.interact
的函数,因为它可以为您创建小部件,但它的优点是专注于matplotlib,因此您只需要提供数据。更多关于ipywidgets的差异

%matplotlib ipympl
将mpl_interactions.ipyplot作为iplt导入
将matplotlib.pyplot作为plt导入
将numpy作为np导入
将IPyWidget作为小部件导入
def绘图图(从=0开始,到=2*np.pi结束):
x=np.linspace(开始于,结束于,1000)
f=λx:和(1.6)范围内a的1/a*np.sin(a*x+np.pi/a)
返回np.array([x,f(x)]).T
图,ax=plt.子批次()
button=widgets.button(描述='reset')
显示(按钮)
controls=iplt.plot(plot\u图形,起始点=(0,np.pi),结束点=(np.pi,2*np.pi),xlim='auto',参数=True)
单击时的def(事件):
对于controls.controls.values()中的hbox:
slider=hbox.children[0]
slider.value=slider.min
按钮。单击时(单击时)

根据@iperetta的答案,您可以创建一个简单的装饰器,为每次使用添加一个重置按钮:

根据上述答案重置按钮:

def reset_按钮(默认值={}):
def on_按钮_单击(u):
对于默认值中的k,v.items():
k、 值=v
按钮=小部件。按钮(description='Reset')
按钮。单击时(单击时)
显示(按钮)
装饰师:

def interact\u plus\u reset(**\u小部件):
默认值_vals={wid:wid._trait_k的值['value'],wid在_widgets.items()中
重置按钮(默认值=默认值)
def wrap(函数):
@包装(func)
@widgets.interactive(**\u widgets)
def内部(*args,**kwargs):
返回函数(*args,**kwargs)
返回内部
回程包装
然后按如下方式使用:

@交互加重置(
a=widgets.FloatSlider(最小值=1,最大值=2000,值=35,步长=1),
b=widgets.FloatSlider(最小值=1,最大值=2000,值=1000,步长=1),
)
def运行(a、b):
打印(a+b)

oops错过了你在发布我的答案之前发布的内容,因为我吃午饭时分心了。我的手动解决方案有点不同,因为它使用了
交互式输出
。但我认为,您所提出的基本上是使用
ipywidgets
来实现这一点的正确方法。mpl交互解决方案之所以有效,是因为与
interact
不同,它将返回它生成的小部件,以便您可以使用它们做更多的事情
# Preamble ----
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, Button, FloatSlider

def reset_button(defaults={}):
    def on_button_clicked(_):
        for k, v in defaults.items(): 
            k.value = v
    button = Button(description='Reset')
    button.on_click(on_button_clicked)
    display(button)

# Code ----
slider1 = FloatSlider(min=0, max=np.pi*0.9, value=0, step=np.pi*0.1)
slider2 = FloatSlider(min=np.pi, max=2*np.pi, value=2*np.pi, step=np.pi*0.1)
reset_button(defaults={slider1: 0, slider2: 2*np.pi})

@interact(starts_at=slider1, ends_at=slider2)
def plot_graph(starts_at, ends_at):
    f = lambda x : sum(1/a*np.sin(a*x + np.pi/a) for a in range(1,6))
    x = np.linspace(0, 2*np.pi, 1000)
    plt.plot(x, f(x))
    plt.xlim([starts_at, ends_at])