Updatable Displays

Note: This feature requires notebook >= 5.0 or JupyterLab, and

IPython 6 implements a new API as part of the Jupyter Protocol version 5.1 for easily updating displays.

When you display something, you can now pass a display_id argument to attach an id to that output.

Any future display with the same ID will also update other displays that had the same ID.

display with a display_id will return a DisplayHandle object, which gives you easy access to update the output:

In [1]:
from IPython.display import display, update_display
In [2]:
handle = display('x', display_id='update-me')
handle
'z'
Out[2]:
<DisplayHandle display_id=update-me>

When we call handle.display('y'), we get a new display of 'y', but in addition to that, we updated the previous display.

In [3]:
handle.display('y')
'z'

We can also just update the existing displays, without creating a new display:

In [4]:
handle.update('z')

You don't have to generate display_ids yourself, if you specify display_id=True, then a unique ID will be assigned:

In [5]:
handle = display("hello", display_id=True)
handle
'hello'
Out[5]:
<DisplayHandle display_id=118a56127f42348f8893440da7181c57>

Calling handle.display(obj) is the same as calling display(obj, handle.display_id), so you don't need to use the handle objects if you don't want to:

In [6]:
display('x', display_id='here');
'z'
In [7]:
display('y', display_id='here');
'z'

And just like display, there is now update_display, which is what DisplayHandle.update calls:

In [8]:
update_display('z', display_id='here')

More detailed example

One of the motivating use cases for this is simple progress bars.

Here is an example ProgressBar using these APIs:

In [9]:
from IPython.display import ProgressBar

bar = ProgressBar(10)
bar.display()

And the ProgressBar has .display and .update methods:

In [10]:
import time

bar.display()

for i in range(11):
    bar.progress = i
    bar.update()
    time.sleep(0.25)

The ProgressBar also has an update built into iteration:

In [11]:
for i in ProgressBar(10):
    time.sleep(0.25)

We would encourage any updatable-display objects that track their own display_ids to follow-suit with .display() and .update() or .update_display() methods.