Estoy usando widgets en IPython que 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 resumen:

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

Produzca 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: mensaje de error agregado más detallado)

9
hmelberg 10 may. 2016 a las 19:31

3 respuestas

La mejor respuesta

Puede retener notificaciones durante la asignación a 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

Ver 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 el valor puede no estar 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".

5
Dan Schien 10 jun. 2016 a las 04:32

Encontré este problema exacto hace una hora. He pirateado una solución usando el ejemplo mínimo aquí: Cambiando dinámicamente menús desplegables en widgets de portátiles IPython y Spyre, ya que mis propios requisitos eran tener listas vinculadas dinámicamente. Estoy seguro de que podrá adaptar sus requisitos utilizando esta solución.

La clave es pregenerar 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, a través de i.kwargs
  • desde los argumentos suministrados hasta print_city

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

Espero que esto ayude.

5
Community 23 may. 2017 a las 12:02

La raíz del error es que el widget también tiene una propiedad de valor y el valor puede no estar 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 si lo desea), o como Dan escribe: use create a hold_trait-notifications ()

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

0
hmelberg 8 jun. 2016 a las 16:29