NumesSanguis
NumesSanguis

Reputation: 6332

HoloViews DynamicMap with stream only passes display output once to IPython

I'm struggling with that code inside a stream function is only once passed on to IPython. In other words, display() calls from DynamicMap is only executed once (click = hv.DynamicMap(interactive_click, streams=[SingleTap()])).

This is just a simple example, but in my real use-case I have display(Javascript('')) code there which I need to have executed.

# problem: display statement not returned to Jupyter Notebook
import numpy as np
import holoviews as hv
from holoviews import opts
from holoviews.streams import SingleTap
# from IPython.display import Javascript
hv.extension('bokeh')

# triggered when clicking on a plot
def interactive_click(x, y):
    # problem: Only executed once
    display("init")
    if None not in [x, y]:
        # problem: never executed, because `display()` is not passed to Jupyter Notebook
        display(x)
    else:
        x = 0
    return hv.VLine(x).opts(color='green')

# random plot: http://holoviews.org/reference/elements/bokeh/Image.html
ls = np.linspace(0, 10, 200)
xx, yy = np.meshgrid(ls, ls)

bounds=(-1,-1,1,1)   # Coordinate system: (left, bottom, right, top)
img = hv.Image(np.sin(xx)*np.cos(yy), bounds=bounds)

# do something when clicked on plot
click = hv.DynamicMap(interactive_click, streams=[SingleTap()])

# show plot and trigger code on-press
img * click

display("init") is only once shown in the output cell and display(x) never (because the first input is (None, None)). This is just a simple example, but in my case I want to execute Javascript, however that can only be executed if the display() output is pass on to the IPython kernel.

I know the code is executed, because the green line in the plot moves:

HoloViews plot interaction

Question

Anyone knows how I can make display(x) show output in the given example (meaning the display output is passed on to IPython kernel in Jupyter Notebook)?

Upvotes: 0

Views: 385

Answers (1)

NumesSanguis
NumesSanguis

Reputation: 6332

The solution is made possible with display_id as hinted by @philippjfr on the pyviz Gitter.

We add the following code above def interactive_click(x, y):

# create a display that we later update
display("None", display_id="click_value")

and update display(x) to display(x, display_id="click_value")

If now click on the plot, we see "None" change to the x value of your mouse click.

This also works with Javascript: display(Javascript('element.text("test");'), display_id="click_value")


Full code:

# problem: display statement not returned to Jupyter Notebook
import numpy as np
import holoviews as hv
from holoviews import opts
from holoviews.streams import SingleTap
# from IPython.display import Javascript
hv.extension('bokeh')

# create a display that we later update
display("None", display_id="click_value")

# triggered when clicking on a plot
def interactive_click(x, y):
    # problem: Only executed once
    # display("init")
    if None not in [x, y]:
        # problem solved
        display(x, display_id="click_value")
        # display(Javascript('element.text("test");'), display_id="click_value")
    else:
        x = 0
    return hv.VLine(x).opts(color='green')

# random plot: http://holoviews.org/reference/elements/bokeh/Image.html
ls = np.linspace(0, 10, 200)
xx, yy = np.meshgrid(ls, ls)

bounds=(-1,-1,1,1)   # Coordinate system: (left, bottom, right, top)
img = hv.Image(np.sin(xx)*np.cos(yy), bounds=bounds)

# do something when clicked on plot
click = hv.DynamicMap(interactive_click, streams=[SingleTap()])

# show plot and trigger code on-press
img * click

Upvotes: 1

Related Questions