ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

Callbacks not triggered when using observe

Open fses91 opened this issue 7 years ago • 7 comments

Hi I have the following problem.

When I use:

import ipywidgets as widgets

toggle = widgets.ToggleButton(description='click me')

def on_click(change):
    print(change['new'])

toggle.observe(on_click, 'value')

the callback does not get triggered, but if I use

import ipywidgets as widgets

@interact
def clicked(a=widgets.ToggleButton()):
    print(a)

the call back gets triggered.

I am using Jupyter Lab: Jupyter Notebook version: 5.6.0 ipywidgets version: 7.2.1

fses91 avatar Jul 25 '18 08:07 fses91

You'll need to use an output widget to capture the printed output: http://ipywidgets.readthedocs.io/en/stable/examples/Output%20Widget.html.

out = Output()
display(out)

@out.capture()
def on_click(change):
    print(change['new'])

jasongrout avatar Jul 25 '18 15:07 jasongrout

This has come up often enough, we should add a note specifically to the output widget documentation, and perhaps to the events documentation as well.

Actually, we should just change the examples in the events documentation so they work in JLab: http://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Events.html#Example

jasongrout avatar Jul 25 '18 15:07 jasongrout

@jasongrout This has come up in my use case: this code cell works in Classic Notebook Server, but not JupyterLab

from ipywidgets import *
from IPython.display import display, HTML
w = IntSlider()
display(w)

def callback(change):
    display(HTML('<h3>Arbitrary HTML</h3>'))

w.observe(callback, names=['value'])

Based on your comments, this is an expected backwards-incompatible breaking change, and the correct solution is an Output widget. The links you provide do give some guidance -- However, this does not completely solve my use case. I need the callback to directly add to the output cell's HTML, not just modify an in-memory JS object in the output cell. We generate HTML outputs from notebooks that get all JavaScript scrubbed from it, and it works well with Classic Notebook Server (Run that code cell, move the slider around, and export to HTML: you should see all the output cell content).

I have yet to figure out a JupyterLab solution to this problem -- Do you have any thoughts?

DavidJVitale avatar Nov 14 '18 20:11 DavidJVitale

@DavidJVitale Are you thinking something like this?

from ipywidgets import *
from IPython.display import display, HTML
w = IntSlider()
display(w)

out = Output()
display(out)

@out.capture()
def callback(change):
    display(HTML('<h3>Arbitrary HTML</h3>'))

w.observe(callback, names=['value'])

vidartf avatar Nov 15 '18 12:11 vidartf

@vidartf Thanks for your help. That code snippet functions the same in the live notebook on Classic server and JupyterLab: The problem is that it still stores all those <h3> HTML elements inside of a dynamic JS widget. If you run your code and export to HTML, you need JS enabled (and some libraries loaded from CDN) to view the Arbitrary HTML text. Try running your cell, exporting to HTML, and doing an 'Inspect Element'. You'll just see <script> tags in the output, and no text.

Luckily, I have a found a solution for my problem, using the display_handler = IPython.display.display("foo", display_id="id") and display_handler.update() functionality. Below is the code snippet that works in both JupyterLab and Classic Notebook Server. If you export after running it, you will see the raw <h3> element in the output cell.

from ipywidgets import *
from IPython.display import display, HTML
from uuid import uuid4
w = IntSlider()
pure_html_display_hander = display(HTML('starting text'),
                                   display_id = str(uuid4()))

out = Output()
display(out)
display(w)

@out.capture()
def callback(change):
    display_html = HTML(f'<h3>Arbitrary HTML {uuid4()}</h3>')
    pure_html_display_hander.update(display_html)

w.observe(callback, names=['value'])

It's a bit hacky updating a global from inside a callback, but it fits my need. I am not sure if anyone else has ran into this issue, but this is the best way to dynamically update output cell HTML of the underlying notebook file asyncronously in both JupyterLab and Classic Notebook Server.

DavidJVitale avatar Nov 15 '18 16:11 DavidJVitale

I began adding this to the documentation.

Looks like the changes have already been made on the ipywidgets master branch, but they are not yet reflected on the stable version of the webpage.

(I assume website update is in progress; this is just a note to others that come across the issue).

dustinmichels avatar Jun 18 '19 22:06 dustinmichels