# Is it possible to get the current value of a widget slider from a function without using multithreading?

**URL:** <https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524>\
**Category:** Widgets\
**Tags:** how-to, help-wanted\
**Created:** [August 26, 2022, 8:54am UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524 "2022-08-26T08:54:21Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![richardstardust](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/richardstardust/32/7815_2.png) [@richardstardust](https://discourse.jupyter.org/u/richardstardust)\
**Post date:** [August 26, 2022, 8:54am UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/1 "2022-08-26T08:54:21Z")

</div>

I am trying to access the current slider value from a function, but it seems that it can only get the value that the slider had when the function was called.  
Is there a way to do this without using multi threading?

Code example:

```auto
import ipywidgets as widgets
import time

slider = widgets.IntSlider(
    value=5,
    min=0,
    max=10,
    step=1,
    description='Test:',
    disabled=False,
    continuous_update=False,
    orientation='horizontal',
    readout=True,
    readout_format='d'
)

def test(slider, output):
    i = 0
    while slider.value != 10:
        i = i+1
        time.sleep(0.1)
        with output:
            output.clear_output()
            print('test ' + str(slider.value) + ' - ' + str(i))

output = widgets.Output()
display(slider, output)

test(slider, output)

```

---

<div class="post-metadata">

**Author:** ![bollwyvl](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/bollwyvl/32/904_2.png) [@bollwyvl](https://discourse.jupyter.org/u/bollwyvl)\
**Post date:** [August 26, 2022, 9:46pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/2 "2022-08-26T21:46:29Z")

</div>

Inside a modern ipython/ipykernel, you’ll pretty much always be inside an asyncio-compatible event loop. If you block, though, then things stop flowing.

`Output` is kind of an implementation nightmare, with each frontend being slightly different. However, `display(..., display_id=True).update` works great.

So:

```python
import ipywidgets as widgets
import asyncio

slider = widgets.IntSlider(
    value=5,
    min=0,
    max=10,
    step=1,
    description='Test:',
    disabled=False,
    continuous_update=False,
    orientation='horizontal',
    readout=True,
    readout_format='d'
)

async def test(slider, output):
    i = 0
    while slider.value != 10:
        i = i+1
        await asyncio.sleep(0.1)
        output.update('test ' + str(slider.value) + ' - ' + str(i))

output = display("tbd", display_id=True)
display(slider)

asyncio.create_task(test(slider, output));

```

Related: [Threading with Matplotlib and ipywidgets - #2 by bollwyvl](https://discourse.jupyter.org/t/threading-with-matplotlib-and-ipywidgets/14674/2)

---

<div class="post-metadata">

**Author:** ![richardstardust](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/richardstardust/32/7815_2.png) [@richardstardust](https://discourse.jupyter.org/u/richardstardust)\
**Post date:** [August 29, 2022, 7:25am UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/3 "2022-08-29T07:25:42Z")

</div>

Thank you! Great solution!  
It was exactly the type of solution I was looking for.  
I will suggest that they add this as an example to the manual.

---

<div class="post-metadata">

**Author:** ![tanaga9](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/tanaga9/32/9200_2.png) [@tanaga9](https://discourse.jupyter.org/u/tanaga9)\
**Post date:** [August 28, 2023, 1:03pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/4 "2023-08-28T13:03:36Z")

</div>

Thank you.  
I had success with this.

```auto
import ipywidgets as widgets
import asyncio

slider = widgets.IntSlider()

async def job(slider, output):
    for i in range(100): # 10 sec job
        await asyncio.sleep(0.1)
        output.update('job ' + str(slider.value))

output = display("tbd", display_id=True)
display(slider)
asyncio.create_task(job(slider, output))

```

I want to retain the right to manually cancel the job mid-way.  
But I failed this.

```auto
import ipywidgets as widgets
import asyncio

slider = widgets.IntSlider()

async def job(slider, output):
    for i in range(100): # 10 sec job
        await asyncio.sleep(0.1)
        output.update('job ' + str(slider.value))

output = display("tbd", display_id=True)
display(slider)
await asyncio.gather(
    asyncio.create_task(job(slider, output))
)

```

How can I manually cancel a job mid-way?

---

<div class="post-metadata">

**Author:** ![tanaga9](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/tanaga9/32/9200_2.png) [@tanaga9](https://discourse.jupyter.org/u/tanaga9)\
**Post date:** [August 28, 2023, 1:24pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/5 "2023-08-28T13:24:24Z")

</div>

I cannot retain the right to manually cancel the job midway (using Jupyter’s standard UI)… (only during the first call)

```auto
import ipywidgets as widgets
import asyncio, time

output = display("tbd", display_id=True)

slider = widgets.IntSlider()
display(slider)

def callback(count):
  output.update(slider.value)
  time.sleep(1)
  if count < 10:
    asyncio.get_running_loop().call_soon_threadsafe(callback, count+1)
callback(0)

```

---

<div class="post-metadata">

**Author:** ![bollwyvl](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/bollwyvl/32/904_2.png) [@bollwyvl](https://discourse.jupyter.org/u/bollwyvl)\
**Post date:** [August 28, 2023, 1:32pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/6 "2023-08-28T13:32:03Z")

</div>

`asyncio.create_task` returns an `asyncio.Task` which has a `.cancel()` method.

Calling that that will raise a `asyncio.CancelledError`, which can be caught and handled. Applying this pattern to the previous example:

```python
import ipywidgets as widgets
import asyncio

slider = widgets.IntSlider(
    value=5,
    min=0,
    max=10,
    step=1,
    description='Test:',
    disabled=False,
    continuous_update=False,
    orientation='horizontal',
    readout=True,
    readout_format='d'
)

button = widgets.Button(description="cancel")

task = None

def cancel(*args):
    task.cancel()

button.on_click(cancel)

async def test(slider, output):
    i = 0
    try:
        while slider.value != 10:
            i = i+1
            await asyncio.sleep(0.1)
            output.update('test ' + str(slider.value) + ' - ' + str(i))
    except asyncio.CancelledError:
        output.update('CANCELLED ' + str(slider.value) + ' - ' + str(i))
        return

output = display("tbd", display_id=True)
display(slider, button)

task = asyncio.create_task(test(slider, output));

```

---

<div class="post-metadata">

**Author:** ![bollwyvl](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/bollwyvl/32/904_2.png) [@bollwyvl](https://discourse.jupyter.org/u/bollwyvl)\
**Post date:** [August 28, 2023, 1:40pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/7 "2023-08-28T13:40:00Z")

</div>

> `call_soon_threadsafe`
> 
> `time.sleep`

In general, `asyncio` primitives should only be mixed with `threading` (or `time.sleep`) with great care, ideally via some primitive like [collections.deque](https://docs.python.org/3/library/collections.html#collections.deque). The `call_soon_threadsafe` won’t reliably protect from all the ways things can Go Wrong. The [anyio](https://anyio.readthedocs.io/en/3.x/) also provides some nice wrappers for things one would be tempted to use threading for (processes, file IO), and is used in a number of core jupyter projects already.

---

<div class="post-metadata">

**Author:** ![tanaga9](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/tanaga9/32/9200_2.png) [@tanaga9](https://discourse.jupyter.org/u/tanaga9)\
**Post date:** [August 28, 2023, 1:41pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/8 "2023-08-28T13:41:18Z")

</div>

> asyncio.create\_task returns an asyncio.Task which has a .cancel() method.

Thank you! bollwyvl  
worked very well !!

But perfect control is difficult, like a kite connected by a weak string…  
(If I run the cell many times while the job is still running…)

---

<div class="post-metadata">

**Author:** ![tanaga9](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/tanaga9/32/9200_2.png) [@tanaga9](https://discourse.jupyter.org/u/tanaga9)\
**Post date:** [August 28, 2023, 1:47pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/9 "2023-08-28T13:47:27Z")

</div>

It is necessary to block so that multiple jobs do not run at the same time

---

<div class="post-metadata">

**Author:** ![bollwyvl](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/bollwyvl/32/904_2.png) [@bollwyvl](https://discourse.jupyter.org/u/bollwyvl)\
**Post date:** [August 28, 2023, 1:55pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/10 "2023-08-28T13:55:00Z")

</div>

> [@tanaga9](#):
>
> multiple jobs do not run at the same time

Little context is given, but keep in mind: if a “user-space” activity blocks the IO loop, shared with the underlying kernel machinery, then sending and receiving of non-interrupt kernel messages (like widget updates) will cease, leaving the UI unresponsive.

---

<div class="post-metadata">

**Author:** ![tanaga9](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/tanaga9/32/9200_2.png) [@tanaga9](https://discourse.jupyter.org/u/tanaga9)\
**Post date:** [August 28, 2023, 3:43pm UTC](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/11 "2023-08-28T15:43:31Z")

</div>

Thank you  
I understand.

By the way…  
I was running the code and noticed that the screen display didn’t change unless I moved the slider.  
I couldn’t see the logs that the jobs printed in the background.
