1

I'm trying to clear ipwidget outputs from inside a thread

For example, I want to make a counter that counts to 10, runs in a thread, and only shows the current number.

Code

import ipywidgets as widgets
import time
from IPython.display import display, HTML
from concurrent.futures import ThreadPoolExecutor

output = widgets.Output()
display(output)

def my_foo():
    for count in range(10):
        output.clear_output(wait=True)
        output.append_display_data(HTML(f"count {count}"))
        time.sleep(1)
        
with ThreadPoolExecutor() as executor:
    executor.submit(my_foo)

Desired Output

the final output for the above code should just be

count 9

Actual Ouput

count 0
count 1
count 2
count 3
count 4
count 5
count 6
count 7
count 8
count 9
Safak Ozdek
  • 906
  • 11
  • 18
Alter
  • 3,332
  • 4
  • 31
  • 56
  • It seems that this might be due to a problem with `Output.append_display_data` and `Output.clear_output`. The `append_display_data` function is used in ipywidgets threading documentation but doesn't seem to work with clear_output. Simply ignoring the recommendation to use `append_display_data` fixes it... – Alter Aug 08 '20 at 19:19
  • I'm mistaken, not using append_display_data means this breaks when using multiple threads and multiple outputs – Alter Aug 08 '20 at 19:49

1 Answers1

2

According to the docs, it appears you are using the right calls.

The best way to avoid surprises is to never use an output widget’s context manager in a context where multiple threads generate output.

However, I experienced the same issue from a background thread. I did manually set the outputs to an empty list which appears to work (although I'm not sure if it messes with the internal state of how ipywidgets tracks updates):

output.outputs = []  # instead of output.clear_output()
Christian Di Lorenzo
  • 3,562
  • 24
  • 33