Home > Software design >  How do I update ipywidget values while running code?
How do I update ipywidget values while running code?

Time:12-23

So I want to create a simple UI in Jupyter notebook where:

  1. A counter "number" is incremented every second
  2. If the checkbox "pause" is checked, "number" is not incremented
  3. If the button "trigger" is pressed, "number" is decremented, regardless of pause status

So far I tried a few variants of the code below but it doesn't work; it seems like the widget values aren't updating when running the while loop. Is there a way to fix it or another way to do this? Thanks!

import ipywidgets as widgets
import time
from IPython.display import display, clear_output

btn = widgets.Button(description = "Trigger")
pause = widgets.Checkbox(value = False, description = "Paused?")
number = widgets.Label("0")
wid = widgets.VBox([btn, number, pause])
display(wid)

def triggered(b):
    number.value = str(int(number.value) - 1)

btn.on_click(triggered)

while True:
    time.sleep(1)
    while (pause.value == True):
        time.sleep(3)
    number.value = str(int(number.value)   1)

CodePudding user response:

As mentioned by ac24, the trick is to run your counter function in a different thread. You can use the threading library to do that. Below, I defined a function counter and launched it in a different thread. That way, the user is still able to interact with the widgets while the counter function is running. An important thing to keep in mind is that once you launched your thread there isn't many elegant ways to kill it. This means that it's better to set up a total_duration variable rather than using while True.

See code below:

import ipywidgets as widgets
import time
from IPython.display import display, clear_output
import threading

btn = widgets.Button(description = "Trigger")
pause = widgets.Checkbox(value = False, description = "Paused?")
number = widgets.Label("0")

wid = widgets.VBox([btn,number,pause])
display(wid)

def triggered(b):
    number.value = str(int(number.value) - 1)
    
btn.on_click(triggered)
    
def counter(number,pause,total_duration):
    for t in range(total_duration):
        if not pause.value:
            time.sleep(1)
            number.value = str(int(number.value)   1)
        elif pause.value:
            time.sleep(3)
            
total_duration=60          
thread = threading.Thread(target=counter, args=(number,pause,total_duration,))
thread.start()
  • Related