Reputation: 462
I am having troubles understanding the functioning of update
on an IPython display
.
It seems that to be updated the widget needs to be instantiated at the top level and cannot be instantiated from the callback of an ipywidget.
Here is a non-working exampled of an IPython display
called by a ipywidget Button
:
import functools
import ipywidgets as widgets
from IPython.display import display
import random
def foo(b):
label = display('Initial text', display_id = True)
def on_button_click(b, label):
label.update('New number {}'.format(random.random()))
button = widgets.Button(description="New number")
display(button)
button.on_click(functools.partial(on_button_click, label=label))
button = widgets.Button(description="Button")
button.on_click(foo)
display(button)
In this example clicking on Button displays a text label
and a new button (New number).
However, clicking on New number does not update the text label
.
Calling foo(0)
directly works correctly. When the New number button is clicked, the text label
is updated.
Is something wrong with the code example? Why can't an ipywidget be updated if it is instantiated from the callback of another widget?
Upvotes: 2
Views: 7017
Reputation: 3443
I think what you mean to achieve is this:
import ipywidgets as widgets
from IPython.display import display
import random
text = widgets.Text('Initial text')
out = widgets.HBox([text])
def foo(b):
text.value = 'New number {}'.format(random.random())
# alternatively: out.children = [widgets.Text('New number {}'.format(random.random()))]
button = widgets.Button(description="Button")
button.on_click(foo)
display(button)
display(out)
Upvotes: 0
Reputation: 5575
I have seen this issue before and it can be due with where the output is routed when using display
. I can get the desired behaviour by wrapping your function with a context manager Output widget.
For anything more complex I would consider building a class deriving from HBox, containing an Output widget and various buttons.
import functools
import ipywidgets as widgets
from IPython.display import display
import random
out = widgets.Output()
def foo(b):
with out:
label = display('Initial text', display_id = True)
def on_button_click(b, label):
label.update('New number {}'.format(random.random()))
button = widgets.Button(description="New number")
display(button)
button.on_click(functools.partial(on_button_click, label=label))
button = widgets.Button(description="Button")
button.on_click(foo)
display(button)
display(out)
Upvotes: 3