将按钮与@interact 一起使用

Using buttons with @interact

编辑:为清楚起见重写于 2019 年 9 月 8 日 1330 UTC

在 Jupyter 笔记本中,我想浏览日期选择器小部件选择的日期。我已经知道这样做的方法是使用 @interact 并将日期选择器小部件作为交互函数的参数,如下所示:

def explore_dates(d1=widgets.DatePicker(value=pd.to_datetime('2018-07-10', format='%Y-%m-%d'), description='Date')):

但我需要“下一个假期”和“上一个假期”按钮才能从所选日期移动到下一个假期。我已经将一组假期存储为 datetime.datetime 个对象。

所以我尝试将按钮对象添加到 @interact 函数的参数中,如下所示:

@interact

def explore_dates(d1=widgets.DatePicker(value=pd.to_datetime('2018-07-10', format='%Y-%m-%d'), description='Date'),
                 prev_button = widgets.Button(description="Prev Holiday"),
                 next_button = widgets.Button(description="Next Holiday")):

那没用。错误说带有按钮小部件的行“无法转换为小部件”。嗯,我以为它已经是一个小部件了...

我的下一个想法是将按钮代码放在函数中,而不是作为参数:

def explore_dates(d1=widgets.DatePicker(value=pd.to_datetime('2018-07-10', format='%Y-%m-%d'), description='Date')):

prev_button = widgets.Button(description="Prev Holiday")
next_button = widgets.Button(description="Next Holiday")
prev_button.on_click(prev_holiday_callback)
next_button.on_click(next_holiday_callback)
box=widgets.HBox([prev_button,next_button])
display(box)

屏幕上有按钮,我可以按下它们和我的回调例程 运行。但是当日期选择器被设置(按照上面)作为 @interact 的参数时,似乎不再可能使用它的 .value 属性来重置它的日期。 (参见上面的代码)尝试设置 d1.value 会导致错误。

我想我可以完全摆脱 @interact,只需将日期选择器和两个按钮放入主线代码中即可。 但我不知道如何重现@interact当时的功能。除了 @interact 之外,没有等待来自其中一个小部件的点击或观察事件的无限循环,我不知道如何告诉 Python/Jupyter “嘿,冷静下来直到小部件事件导致回调唤醒代码。

如果有帮助,这里是我的按钮回调例程。

def button_click_common():
    global button_flag
    global button_date
    global holidays
    
    for i in range(len(holidays)):
        if(holidays[i]<button_date): # haven't passed the prior holiday yet
            continue
        
        # Now holidays[i] has to either be same as or after button_date
        
        prior_holiday = i-1 # prior holiday is the one we just passed that was prior
        next_holiday = i    # assume at first we are between dates
        if holidays[i]==button_date:
            next_holiday +=1        # if we were already on a holiday date, next becomes the following one
        return prior_holiday, next_holiday

def prev_holiday_callback(_):
    global button_flag
    global button_date
    global holidays
    
    prior_holiday,_ = button_click_common()
    
    button_date = holidays[prior_holiday]
    button_flag = True
    
def next_holiday_callback(_):
    global button_flag
    global button_date
    global holidays
    
    _,next_holiday = button_click_common()
    
    button_date = holidays[next_holiday]    
    button_flag = True  

这里的想法是回调将 button_date 更新为下一个假期的日期,并设置标志 button_flag。然后 explore_dates 函数中的代码(未显示)将测试该标志。但是当日期选择器小部件被定义为 @interact 函数的参数时,我无法弄清楚如何使用新日期更新日期选择器小部件。

感觉我做错了。欢迎任何建议或指导...

提前致谢!

我不确定我是否理解您要实现的确切目标,但交互最适合采用数字输入的函数,而不是离散输入或 python 对象(如日期)。

我整理了一些代码来说明我将如何使用前进和后退按钮来更新日期选择器,它可能不是您要找的东西,但也许您可以从那里描述更改?

import ipywidgets as ipyw
from datetime import date

idx = 0
date_picker = ipyw.DatePicker()
date_picker.value = month_starts[idx]
start_button = ipyw.Button(description='Prev')
end_button = ipyw.Button(description='Next')

display(date_picker, start_button, end_button)

def change_date(button):
    global idx
    if button.description=='Prev':
        if idx-1<0:
            pass
        else:
            date_picker.value = month_starts[idx-1]
            idx -= 1

    elif button.description=='Next':
        if idx+1>=len(month_starts):
            pass
        else:
            date_picker.value = month_starts[idx+1]
            idx += 1

start_button.on_click(change_date)
end_button.on_click(change_date)