Обработка выбора из виджетов Jupyter внутри функции
Я пишу функцию, позволяющую пользователю выбирать из ряда параметров, а затем возвращать значения на основе этих вариантов. Я используюJupyter Widgets
для выбора и запуска в JupyterLab. Моя функция выбора отлично работает сама по себе, но как только она была встроена в другую функцию, она перестает работать. Пример:
import ipywidgets as widgets
def get_choices():
selections = [
widgets.ToggleButtons(
options=['Not Included', 'Included', 'Favorite'],
description=f"{choice}",
disabled=False,
style= {'description_width': '300px'}
)
for choice in ['choice1', 'choice2', 'choice3']
]
for e in selections:
display(e)
## waiting for user input
print("\n\nPRESS ENTER WHEN FINISHED")
input()
return wiki_edges_select
choices = get_choices()
print(choices)
>> [ToggleButtons(description='choice1', index=1, options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Included'),
ToggleButtons(description='choice2', index=1, options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Included'),
ToggleButtons(description='choice3', index=2, options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Favorite')]
(Обратите внимание, что значения ,Included
,Favorite
). Однако при внедрении в функцию-оболочку:
def get_choices_and_process():
choices = get_choices()
print(choices)
get_choices_and_process()
>> [ToggleButtons(description='choice1', options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Not Included'), ToggleButtons(description='choice2', options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Not Included'), ToggleButtons(description='choice3', options=('Not Included', 'Included', 'Favorite'), style=ToggleButtonsStyle(description_width='300px'), value='Not Included')]
(Обратите внимание, что значения , ,Not Included
)
Я хотел бы иметьchoices
вернулся в течениеget_choices_and_process()
функция отражает выбор пользователя, как если бы онget_choices()
вызывается вне оболочки. Как я могу заставить это работать?
2 ответа
Если я неправильно понимаю, что вы пытаетесь сделать, вы можете использовать интерактивную функцию ipywidgets , чтобы позволить ipywidgets обрабатывать настройку пользовательского интерфейса и делать его интерактивным. А также поддерживать эту интерактивность. Вы можете получить доступ к настройкам по мере их обновления, используя аргументы ключевого слова, назначенные экземпляру интерактивной функции. Например, если вы назначаете экземплярw
,w.kwargs
даст вам текущие значения.
Он работает встроенный в другую функцию, как я могу показать на демонстрации. (Это было разработано в JupyterLab.)
Пример настроек
Поместите следующее в ячейку JupyterLab:
#based on https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, ToggleButtons
def print_choices(choice1, choice2, choice3):
print(choice1)
print(choice2)
print(choice3)
choice1Select = ToggleButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice1:',disabled=False,style= {'description_width': '300px'})
choice2Select = ToggleButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice2:',disabled=False,style= {'description_width': '300px'})
choice3Select = ToggleButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice3:',disabled=False,style= {'description_width': '300px'})
w = interactive(print_choices, choice1=choice1Select, choice2=choice2Select, choice3=choice3Select)
w
Вы можете выбрать настройки и увидеть обновления ниже.
Пример, встроенный в функцию-оболочку
Для функции-оболочки попробуйте это в другой ячейке ниже этой:
def get_choices_and_process(choices):
for tag,choice in choices.items():
print(f"{tag} is {choice}.")
#print(f"choices are:{choices}")
get_choices_and_process(w.kwargs)
Теперь поднимитесь и измените выбор в предыдущей ячейке. А затем снова запустите эту ячейку.
Альтернативный вариант с пониманием списка, определяющий ToggleButtons больше в соответствии с OP:
#based on https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, ToggleButtons
def print_choices(choice1,choice2, choice3):
print(choice1)
print(choice2)
print(choice3)
choice1Select, choice2Select, choice3Select = [
ToggleButtons(
options=['Not Included', 'Included', 'Favorite'],
description=f"{choice}",
disabled=False,
style= {'description_width': '300px'}
)
for choice in ['choice1', 'choice2', 'choice3']
]
w = interactive(print_choices, choice1=choice1Select, choice2=choice2Select, choice3=choice3Select)
w
Asyncio может быть подходящим вариантом, если его нельзя использовать
Может быть полезно указать на это решениеМожно ли получить текущее значение ползунка виджета из функции без использования многопоточности?потому что использование asyncio позволяет получать обновленную информацию от виджета, который выбирает значение, позволяя использоватьtime.sleep()
который, кажется, блокируетinteractive()
от работы.
Я еще не придумал, как адаптировать это к OP.
Я не смог сделать это точно, но это решение оказалось достаточно хорошим. Оставить открытым, так как это точно не отвечает на вопрос.
%gui asyncio
import asyncio
import ipywidgets as widgets
def get_choices():
selections = [
widgets.ToggleButtons(
options=['Not Included', 'Included', 'Favorite'],
description=f"{choice}",
disabled=False,
style= {'description_width': '300px'}
)
for choice in ['choice1', 'choice2', 'choice3']
]
for e in selections:
display(e)
return wiki_edges_select
def process_choices(choices):
included_choices, favorite_choices = [], []
for choice in choices:
if choice.value == "Included":
included_choices.append(choice)
if choice.value == "Favorite":
favorite_choices.append(choice)
return included_choices, favorite_choices
def wait_for_change(widget):
"""
This function found here: https://stackoverflow.com/questions/55244865/pause-jupyter-notebook-widgets-waiting-for-user-input
"""
future = asyncio.Future()
def getvalue(change):
future.set_result(change.description)
widget.on_click(getvalue, remove=True)
widget.on_click(getvalue)
return future
async def get_choices_and_process():
choices = get_choices()
## Waiting for selections
button = widgets.Button(description="Click to Continue")
display(button)
x = await wait_for_change(button)
included_choices, favorite_choices = process_choices(choices)
return my_results
processed_choices = asyncio.create_task(get_choices_and_process() )
processed_choices.result()
>> ["choice1", "choice2"], ["choice3"]
Кроме того, это работает только на ноутбуке Jupyter, а не на Jupyter-lab, что подходит для моего приложения.