ipywidgets:根据另一个小部件的结果更新一个小部件

时间:2016-05-10 16:31:56

标签: python widget ipython ipywidgets

我在IPython中使用小部件,允许用户重复搜索短语并在另一个小部件(选择小部件)中查看结果(不同的标题),然后选择其中一个结果。

简而言之:

search_text = widgets.Text(description = 'Search') 
search_result = widgets.Select(description = 'Select table')

def search_action(sender):
    phrase = search_text.value
    df = search(phrase) # A function that returns the results in a pandas df
    titles = df['title'].tolist()
    search_result.options = titles

search_text.on_submit(search_action)

这曾经工作正常,但在更新到最新版本的ipywidgets(5.1.3从4.0.1)之后,似乎

search_selection.options = titles

产生以下错误(一个或两个,它会有所不同):

TraitError: Invalid selection
TypeError: 'list' object is not callable

它仍然有效,因为小部件会根据来自其他小部件的搜索结果更新结果,但它会出错。

根据另一个小部件的结果在一个小部件中设置选项的正确方法是什么?

(编辑:添加更详细的错误消息)

4 个答案:

答案 0 :(得分:4)

一小时前我遇到了这个确切的问题。我使用这里的最小示例({3}}一起攻击了一个解决方案,因为我自己的要求是拥有动态链接列表。我相信您将能够使用此解决方案调整您的要求。

关键是预先生成所有Dropdown / Select。出于某种原因,w.options = l仅设置w._options_labels,但不设置w.options。然后,对w的选定值的后续验证将会失败。

import ipywidgets as widgets
from IPython.display import display

geo={'USA':['CHI','NYC'],'Russia':['MOW','LED']}
geoWs = {key: widgets.Select(options=geo[key]) for key in geo}

def get_current_state():
    return {'country': i.children[0].value,
            'city': i.children[1].value}

def print_city(**func_kwargs):
    print('func_kwargs', func_kwargs)
    print('i.kwargs', i.kwargs)
    print('get_current_state', get_current_state())

def select_country(country):
    new_i = widgets.interactive(print_city, country=countryW, city=geoWs[country['new']])
    i.children = new_i.children

countryW = widgets.Select(options=list(geo.keys()))
init = countryW.value
cityW = geoWs[init]

countryW.observe(select_country, 'value')

i = widgets.interactive(print_city, country=countryW, city=cityW)

display(i)

最后请注意,获取小部件的最新状态并非易事。这些是

  • 直接来自儿童的价值观,通过get_current_state。这可以信任。
  • 来自交互式实例的
  • ,通过i.kwargs
  • 从提供的参数到print_city

后两者有时会过时,出于各种原因我不想进一步了解。

希望这有帮助。

答案 1 :(得分:4)

您可以在分配到options期间保留通知:

with search_result.hold_trait_notifications():
    search_result.options = titles

因此:

search_text = widgets.Text(description = 'Search') 
search_result = widgets.Select(description = 'Select table')

def search_action(sender):
    phrase = search_text.value
    df = search(phrase) # A function that returns the results in a pandas df
    titles = df['title'].tolist()
    with search_result.hold_trait_notifications():
        search_result.options = titles

请参阅下面的hmelberg解释

  

“错误的根源是窗口小部件也有一个值属性,并且该值可能不在新的选项列表中。因此,窗口小部件值可能会在短时间内”孤立“,并且错误是生产的“。

答案 2 :(得分:2)

我遇到了类似的问题并已解决Registering callbacks to trait changes in the kernel

caption = widgets.Label(value='The values of range1 and range2 are synchronized')
slider = widgets.IntSlider(min=-5, max=5, value=1, description='Slider')

def handle_slider_change(change):
    caption.value = 'The slider value is ' + (
        'negative' if change.new < 0 else 'nonnegative'
    )

slider.observe(handle_slider_change, names='value')

display(caption, slider)

我想这个解决方案早在 2016 年就没有了,或者我的问题不像想象的那么相似。

答案 3 :(得分:0)

错误的根源是窗口小部件还具有值属性,并且该值可能不在新的选项列表中。因此,窗口小部件值可能是&#34;孤立的&#34;在短时间内产生错误。

解决方案是将窗口小部件值分配给选项列表,然后再将其分配给窗口小部件(如果需要,可以删除值/选项),或者如Dan所写:使用create a hold_trait-notifications()

丹的方法是最好的。以上只是解释了问题的原因。