ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

Output widget's clear_output not clearing when using append_stdout

Open jagaudin opened this issue 5 years ago • 5 comments

I stumbled upon a question on Stack Overflow where the first line printed in the output widget doesn't get cleared by the first call to clear_output.

import ipywidgets as widgets

def clear_output():
    change_output_button = widgets.Button(description="Change output?")
    the_output = widgets.Output()
    clear_output_widget = widgets.VBox([change_output_button, the_output])
    clear_output_widget.click_count = 0

    def button_clicked(_button):
        clear_output_widget.click_count += 1
        the_output.clear_output()
        the_output.append_stdout(f"button clicked {clear_output_widget.click_count} times.")

    change_output_button.on_click(button_clicked)

    return clear_output_widget`

Replacing append_stdout with the context manager fixes the issue:

    def button_clicked(_button):
        clear_output_widget.click_count += 1
        the_output.clear_output()
        with the_output:
            print(f"button clicked {clear_output_widget.click_count} times.")

but I am unsure of the reasons behind the erratic behaviour. I tried to look at the source of append_stdout but I haven't found it so far. Happy to submit a PR once I get to the bottom of this issue.

jagaudin avatar Oct 15 '19 22:10 jagaudin

Hi, is there an update?

Following code does not work:

import asyncio
import threading
from IPython.display import display, HTML
import ipywidgets as widgets
import time

SLEEP = 1

all_tasks = asyncio.all_tasks()
for task in all_tasks:
    task.cancel()

async def do(out):
    while True:
        await asyncio.sleep(SLEEP)
        out.append_display_data(HTML("<em>All done!</em>"))
        out.clear_output()

out = widgets.Output()
# Now the key: the container is displayed (while empty) in the main thread
display(out)
asyncio.create_task(do(out));

Not working means the output is not cleared :nerd_face:

katsar0v avatar Oct 16 '19 12:10 katsar0v

As mentioned on stackoverflow, clear_output is using Jupyter's display mechanism, and is the same as:

import IPython.display
with clear_output_widget:
  IPython.display.clear_output()

append_stdout is not using the display mechanism, but the context manager is.

I think there is room for improvement here, since now the Output widget is mixing two things (display mechanism and state syncing). I think we should be more consistent, use both, or one of them. We cannot avoid the display mechanism since that would not play nice with clear_display(wait=True). I would be in favor of using both, so the widget is always in a consistent state, even without a frontend connected.

This means that a frontend:

  • will initially first just display whatever outputs state is.
  • It reacts to changes in display/clear_output.
  • Changes to outputs are immediate, they do no respect clear_output.

maartenbreddels avatar Oct 16 '19 13:10 maartenbreddels

Hi!

I did have the same issue. But turned out that I could not even use the context manager, as I was trying to clear / update the Output from a thread, so that my notebook would still be available, and the output would update with data from rest calls. And that does not work very well. I assume that the with out: is using some static variable that don't play well with threading.

I worked around it by using a out = widgets.HTML() and calling out.value = f"<pref>{my_message}</pre>" in the thread function.

wonsjb avatar Oct 09 '20 13:10 wonsjb

I'm wondering if @wonsjb's workaround works if I'm already using the workaround with show_inline_matplotlib_plots(): https://github.com/jupyter-widgets/ipywidgets/issues/1853#issuecomment-349201240

StefanBrand avatar Apr 15 '21 11:04 StefanBrand

workaround for this is posted on another thread: https://github.com/jupyter-widgets/ipywidgets/issues/3260#issuecomment-907715980

pnsvk avatar Mar 15 '22 23:03 pnsvk