Reputation: 877
Inspired by this example on the Bokeh gallery, I tried to implement a slider to slide through huge amounts of collected data (essentially a time-lapse of biological data). Instead of using a custom javascript callback on the slider, I tried to go with the widgets. I do not know whether this can work. Find my minimal working example. It displays the slider, and the image, correctly, but it seems like the update just does not happen.
##Creating the 15 different pictures
#Want to make 15 different pictures of a certain field function evaluated on a grid of img_size_x x img_size_y
import numpy as np
img_size_x,img_size_y = (512,512)
variations=15
#Make the field
xx,yy=np.meshgrid( np.arange(img_size_x),np.arange(img_size_y))
#Broadcast the field into as many copies as there are variations to make use of the ufuncs
xx= np.tile(xx,variations).reshape(variations,img_size_x,img_size_y)
yy= np.asarray(map(np.transpose,np.tile(yy.T,variations).reshape(variations,img_size_x,img_size_y)))
varied_parameter=np.linspace(.01,0.5,variations) #frequencies of a sin/cos function, for example
varied_parameter=np.repeat(varied_parameter,img_size_x*img_size_y).reshape(variations,img_size_x,img_size_y) #broadcast
matrix_images=np.cos(varied_parameter*xx)+np.sin(varied_parameter*yy) # field function evaluated for diff frequencies.
##Creation of the Bokeh interface to slide through these pictures
from bokeh.plotting import figure, show, output_file, output_notebook
from bokeh.models import ColumnDataSource
from bokeh.layouts import row, widgetbox
from bokeh.models.widgets import Slider
import bokeh.palettes as pal
output_notebook()
data=matrix_images[0] #starting value for the column data source
source = ColumnDataSource(dict(image=[data])) #the figure.image function takes a vector of matrices
image_sl = Slider(title="Image number", value=0, start=0, end=variations-1, step=1) #slider to go through the images
def update_img(attrname, old, new):
curr_value = image_sl.value
x=matrix_images[int(curr_value)] #make sure index is int to select image number 'curr_value'
source.data = dict(image=[x])
image_sl.on_change('value', update_img) #give slider its callback function
inputs = widgetbox(image_sl) #wrap the slider into a display object
p = figure(x_range=(0, 10), y_range=(0, 10))
# must give a vector of image data for image parameter
p.image('image', source=source,x=0, y=0, dw=10, dh=10, palette=pal.Greys256)
show(row([p,image_sl]) ) # open a browser
Upvotes: 4
Views: 849
Reputation: 215
The kind of update you are trying to use will only work with Bokeh Server. When output_notebook
or output_file
is used with show
the generated output is HTML with embedded JavaScript that renders the actual plot. What this means is that these plots should be thought of as stand-alone files that run within the browser. This means that these plots cannot directly access or run any Python code.
Bokeh provides a few ways for you to write callbacks for your plots in Python. The first is to use Bokeh Server. You can read about it here. Since you've written your callback to work with Bokeh Server it was pretty easy to get working this way. I commented out these lines, which cause an Error.
xx= np.tile(xx,variations).reshape(...
yy= np.asarray(map(np.transpose, ...
Then adding an import for curdoc from bokeh.io import curdoc
and replacing show(row([p,image_ls]))
with curdoc().add_root(row([p,image_ls]))
. From there the example can be ran with $ bokeh serve --show name_of_your_file.py
.
If you are want something that will run in a notebook or in a standalone file. You also have the option of using a PyScript callback. This callback looks like python and it is written in the same file as your Python code. However, it will be interpreted as a language called PyScript to compile your "Python code" to JavaAcript. Again, this won't have access to your python runtime environment. It is possible to pass Bokeh objects to these callbacks but, that is it. This probably won't fit your use case because your callback needs to have access to matrix_images
. You can read more here. I would recommend reading the entire section on adding interactions there, it has lots of good examples of how to use CustomJS callbacks.
Another option is using Jupyter Notebook Widgets. This solution will only work in your notebook though. You can read about this approach here.
Upvotes: 1