3

I am experiencing a weird behavior with the Output widget from ipywidgets. I replicate it with the below code in a jupyter notebook:

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

In another cell, I input

clear_output()

which displays the button as intended.

Below are the sequence of outputs I get:

  • click 1
button clicked 1 times.
  • click 2
button clicked 1 times.button clicked 2 times.
  • click 3
button clicked 3 times.
  • click 4
button clicked 4 times.

and so on...

I do not understand the click 2 behavior. Am I doing something wrong?

Below is my About Jupyter Notebook info:

Server Information: You are using Jupyter notebook.

The version of the notebook server is: 6.0.1 The server is running on this version of Python:

Python 3.7.4 (default, Aug  9 2019, 18:22:51) [MSC v.1915 32 bit (Intel)]

Current Kernel Information:

Python 3.7.4 (default, Aug  9 2019, 18:22:51) [MSC v.1915 32 bit (Intel)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.8.0 -- An enhanced Interactive Python. Type '?' for help.

Thanks for you help!

dj K
  • 180
  • 2
  • 11

1 Answers1

4

It seems to be due to using append_stdout rather than the context manager. Probably a buffering problem.

In the meantime you can do:

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()
        with the_output:
            print(f"button clicked {clear_output_widget.click_count} times.")


    change_output_button.on_click(button_clicked)

    return clear_output_widget
Jacques Gaudin
  • 15,779
  • 10
  • 54
  • 75
  • 1
    thanks, this solves the problem indeed! I assume you're a contributor to the project. I'll be watching for a bug fix and in the meantime I will use this trick. – dj K Oct 14 '19 at 18:39
  • Always a pleasure, I'm not a contributor but it seems to be a fairly simple issue. I'll try to submit a PR if I can understand what is going on. – Jacques Gaudin Oct 14 '19 at 22:09
  • I've opened an [issue](https://github.com/jupyter-widgets/ipywidgets/issues/2584) on github. It seems that `append_output` is the culprit. – Jacques Gaudin Oct 15 '19 at 22:07
  • Yes, the clear_output is using Jupyter's display mechanism, and append_stdout is not. I think there is room for improvement here (can discuss on github). – Maarten Breddels Oct 16 '19 at 13:10