将按钮与@interact结合使用

时间:2019-09-08 01:31:28

标签: python jupyter-notebook ipywidgets

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

在Jupyter笔记本中,我想浏览由日期选择器小部件选择的日期。我已经知道这样做的方法是使用@interact并使datepicker小部件成为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,只需将datepicker和两个按钮都放在主代码中即可。 但是我当时不知道如何重现@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。然后explor_dates函数中的代码(未显示)将测试该标志。但是当将它定义为@interact函数的参数时,我不知道如何用新日期更新datepicker小部件。

感觉就像我要解决这个问题。欢迎任何建议或指导...

谢谢!

1 个答案:

答案 0 :(得分:0)

我不确定我是否了解您要达到的确切目标,但是与带数字输入的功能(而不是离散输入或日期之类的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)