ipywidgets: actualiza un widget basado en los resultados de otro

Estoy utilizando widgets en IPython que le permiten al usuario buscar repetidamente una frase y ver los resultados (títulos diferentes) en otro widget (un widget de selección) y luego seleccionar uno de los resultados.

En breve:

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) 

Esto solía funcionar bien, pero después de actualizar a la última versión de ipywidgets (5.1.3 de 4.0.1) parece que

 search_selection.options = titles 

Produce los siguientes errores (uno o ambos, varía):

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

Todavía funciona en el sentido de que el widget se actualiza con los resultados basados ​​en la búsqueda del otro widget, pero da un error.

¿Cuál es la forma correcta de configurar las opciones en un widget en función de los resultados de otro widget?

(Editar: añadido un mensaje de error más detallado)

Puede mantener las notificaciones durante la asignación de options :

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

Así:

 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 

Vea la explicación de hmelberg a continuación.

“La raíz del error es que el widget también tiene una propiedad de valor y es posible que el valor no esté en la nueva lista de opciones. Debido a esto, el valor del widget puede” quedar huérfano “por un corto tiempo y se produce un error”.

Encontré este problema exacto hace una hora. He hackeado una solución utilizando el ejemplo mínimo aquí: Cambio dynamic de menús desplegables en los widgets de notebook IPython y Spyre , ya que mis propios requisitos eran tener listas enlazadas dinámicamente. Estoy seguro de que podrá adaptar sus requisitos con esta solución.

La clave es generar previamente todos los menús desplegables / Seleccionar. Por alguna razón, w.options = l solo establece w._options_labels pero no w.options . La validación posterior del valor seleccionado de w fallará horriblemente.

 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) 

Tenga en cuenta, por último, que no es trivial obtener el estado más actualizado de los widgets. Estos son

  • directamente de los valores de los niños, a través de get_current_state . Esto se puede confiar.
  • desde la instancia interactiva, via i.kwargs
  • desde los print_city proporcionados hasta print_city

Los dos últimos a veces pueden estar desactualizados, por diversas razones que no deseo averiguar más.

Espero que esto ayude.

La raíz del error es que el widget también tiene una propiedad de valor y es posible que el valor no esté en la nueva lista de opciones. Debido a esto, el valor del widget puede quedar “huérfano” por un corto tiempo y se produce un error.

La solución es asignar el valor del widget a la lista de opciones antes de asignarlo al widget (y eliminar el valor / opción después de lo deseado), o como lo escribe Dan: use create a hold_trait-notifications ()

El enfoque de Dan es el mejor. Lo anterior solo explica la causa del problema.