ipywidgets: Update one widget based on results from another

别等时光非礼了梦想. 提交于 2019-11-30 14:20:38

You can hold notifications for during the assignment to options:

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

Thus:

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

See hmelberg's explanation below

"The root of the error is that the widget also has a value property and the value may not be in the new list of options. Because of this, widget value may be "orphaned" for a short time and an error is produced."

ch41rmn

I encountered this exact problem an hour ago. I have hacked together a solution using the minimum example here: Dynamically changing dropdowns in IPython notebook widgets and Spyre, since my own requirements were to have dynamically linked lists. I am sure you'll be able to adapt your requirements using this solution.

The key is to pre-generate all Dropdowns/Select. For some reason, w.options = l only sets w._options_labels but not w.options. Subsequent validation of the selected value of w will then fail horribly.

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)

Note lastly that it is not trivial to obtain the most up-to-date state of the widgets. These are

  • directly from the children's values, via get_current_state. This can be trusted.
  • from the interactive instance, via i.kwargs
  • from the supplied args to print_city

The latter two can sometimes be out of date, for various reasons I don't wish to find out further.

Hope this helps.

The root of the error is that the widget also has a value property and the value may not be in the new list of options. Because of this, widget value may be "orphaned" for a short time and an error is produced.

The solution is either to assign the widget value to the option list before assigning it to the widget (and remove the value/option after if desired), or as Dan writes: use create a hold_trait-notifications()

Dan's approach is the best. The above just explains the cause of the problem.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!