8

In my notebook I've a loop in which I want to ask the user to binary "Yes" or "No". On this choice the algorithm is suppposed to continue.

for i in range(n_total):
    display.clear_output(wait=True)
    waiting_for_scoring = True
    print("True or False?")
    display.display(widgets.HBox((true_button, false_button)))
    a = true_button.on_click(on_true_button)
    a = false_button.on_click(on_false_button)
    while waiting_for_scoring == True:
        #waiting for user input
        pass

How can I make the loop to wait, after the widgets HBox creation, and wait for user input (button click) to continue with the new value answered?

Here's my two functions for the buttons:

def on_true_button(x):
    global waiting_for_scoring
    print('NO!!!!')
    y_new = 1
    waiting_for_scoring = False
    return y_new

def on_false_button(x):
    global waiting_for_scoring
    print('YES')
    y_new = 0
    waiting_for_scoring = False
    return y_new

Could you help me to stop the loop until the user presses the button and then use this input? Thank you in advance

TheInterestedOne
  • 748
  • 3
  • 12
  • 33

1 Answers1

0

We need to explicitly poll the UI events

There's a neat little library called jupyter-ui-poll which handles exactly this use case! The rest of the button setup you have can stay the same. We just need to wrap a pollable scope around the loop like so:

from jupyter_ui_poll import ui_events
...
with ui_events() as poll:
    while waiting_for_scoring == True:
        #waiting for user input
        poll(10) # poll queued UI events including button
        pass

You might also want to add a time.sleep(...) in the loop to avoid too much spinning.


The issue is that the IPython kernel executes a queue of events, but there's one queue for both UI event callbacks and cell execution. So once it's busy working on a cell, UI events don't get processed. jupyter-ui-poll temporarily (inside the scope) adjusts this queueing behaviour to allow for explicit polling.

Oly
  • 2,329
  • 1
  • 18
  • 23