0

I am using this code to create a simple plot:

from ipywidgets import interact
import numpy as np

from bokeh.io import push_notebook, show, output_notebook
from bokeh.plotting import figure
output_notebook()

x = np.linspace(0, 2*np.pi, 2000)
y = np.sin(x)

p = figure(title="simple line example", plot_height=300, plot_width=600, y_range=(-5,5),
           background_fill_color='#efefef')
show(p)

By running this code a plot with multiple line will be created succesfully as expected. enter image description here

My goal was to bring the interactivity of bokeh to this plot by using this code:

r1=p.line(x, y)
def update(f, w=1, A=1, phi=0):
    if   f == "sin": func = np.sin
    elif f == "cos": func = np.cos
    for k in range(1,4):
        r1=p.line(x, y)
        r1.data_source.data['y'] = A * func(w * k*x + phi)
        push_notebook()

And show and update the plot using this code:

show(p, notebook_handle=True)
interact(update, f=["sin", "cos"], w=(0,50), A=(1,10), phi=(0, 20, 0.1))

Once I run the code above I get this reult:

enter image description here

I was expecting by changing the variables like phi, A etc the whole plot including 4 lines would be updated. But what I get when I for e.g. change sin to cos, looks like this: enter image description here

This means the plot dioesnt really "update" but overdraw the new data on the old plot. What am I missing here? And I want stay with the loop.

1 Answer 1

1

What am I missing here?

Two things:

  • push_notebook is specifically for making incremental updates to an existing plot, without replacing anything that is there

  • every call to p.line adds a new line to a plot.

If you want to have just a fixed set of lines that update in response to widgets, then your callback should not call p.line at all. You should set up the lines you want, once, up front. Then in the callback, only update the data sources for those lines, before calling push_notebook to update the JavaScript side.

Also BTW the best practice for updating a data source is assigning to the .data property to update everything all at once, e.g.

source.data = new_data_dict
Sign up to request clarification or add additional context in comments.

5 Comments

So this means for each line I have to write r[x]=p.line(x, y) and repeat assigning new data in the update function.
Do you know any way to create those variables without using globals()[]?
You should ask about separate question with code. I can't imagine any reason you would need to use the globals() function here, so I'm not sure at all what you are suggesting.
BEcause you said "You should set up the lines you want, once, up front." So I assume I have to define r1, r2 r3 ... for each line.
You could put them in a list or dict rather than individually naming them, then loop over that structure. But even if you name them, there is no need to use globals()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.