<jupyter_start><jupyter_text>Widgets in threads Widget interactions are blocked when something is running in the kernel. I have not succeeded in modifying the kernel event loop to overcome this. So try threads.  After https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Asynchronous.htmlUpdating-a-widget-in-the-background, with hacks:  Setup<jupyter_code>import trio
import threading
from IPython.display import display
import ipywidgets as widgets
import math
import time<jupyter_output><empty_output><jupyter_text>A global state object<jupyter_code>class Thing:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
g = Thing()<jupyter_output><empty_output><jupyter_text>A function that does work in a threadThis will update a widget's value from a supplied function. It also runs a task at `g.threadwork`.<jupyter_code>def work(w, valfun=lambda t:0.5):

    async def track_value(w, valfun):
        while not g.stop_requested:
            w.value = valfun()
            await trio.sleep(0.1) #DEBUG

    async def worker():
        while not g.stop_requested:
            await trio.sleep(await g.threadwork())

    
    async def threadloop(w, valfun):
        async with trio.open_nursery() as nursery:
            nursery.start_soon(track_value, w, valfun)
            nursery.start_soon(worker)
        
    trio.run(threadloop, w, valfun)<jupyter_output><empty_output><jupyter_text>The widgets<jupyter_code>progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0)
s_w = widgets.FloatSlider(value=0.5, min=0.0, max=1.0, step=0.01)
b_w = widgets.Button(
    description='stop',
    disabled=False,
    button_style='', # 'success', 'info', 'warning', 'danger' or ''
    tooltip='click to stop thread',
    icon='stop' # (FontAwesome names without the `fa-` prefix)
)
out_w = widgets.Output()<jupyter_output><empty_output><jupyter_text>and their behavior<jupyter_code>g.stop_requested = False
def request_stop(b):
    g.stop_requested = True
    #with out_w:
    #    print("stop requested")
b_w.on_click(request_stop)

display(progress, s_w, b_w, out_w)<jupyter_output><empty_output><jupyter_text>Create the background thread<jupyter_code>thread = threading.Thread(target=work, args=(progress, lambda: s_w.value))<jupyter_output><empty_output><jupyter_text>Set up a pretend job and start the thread<jupyter_code>g.work_ctr = 0
async def just_one():
    g.work_ctr += 1
    return 1
g.threadwork = just_one
g.stop_requested = False
thread.start()<jupyter_output><empty_output><jupyter_text>Testing* Move the slider and see the progress bar track* Examine g.work_ctr to see it growing* Hit the stop button and see the tracking and work stops  Join up if it's done, and examine work results<jupyter_code>thread.is_alive() or thread.join()
print(f"{g.work_ctr}")
async def fastly():
    g.work_ctr += 1
    return .01
g.threadwork = fastly
g.work_ctr = 0
import numpy as np
a = np.random.randn(2048,3072)
%timeit a@a.T<jupyter_output><empty_output><jupyter_text>Burn cycles with `numpy`<jupyter_code>async def mmul():
    p = a @ a.T
    g.work_product = np.einsum('ij,ij', p, p)
    g.work_ctr += 1
    return 0
g.threadwork = mmul
g.work_ctr
async def worked_enough(v):
    if g.work_ctr >= v:
        g.threadwork = lambda: 1
    await trio.sleep(1)
    
trio.run(worked_enough, 100)
g.threadwork
threading.active_count()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11061946902654868, 'fraction_numerical': 0.012684365781710914, 'mean_word_length': 4.469354838709678, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 38, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '532790', 'license': 'MIT', 'n_tokens_mistral': 1229, 'n_tokens_neox': 1194, 'n_words': 290, 'path': 'nbs/widgets-in-threads.ipynb', 'repo_name': 'pramasoul/aix', 'size': '3390'}