Interactive Graphics Sandbox

Can we use the bokeh library to make an interactive image plot? All we need is to be able to capture an (x,y) pixel position on an image, so we can use it in our lens model. Let's start by following this tutorial and see how far we get.


In [ ]:
# !conda install bokeh

In [28]:
import numpy
import bokeh.plotting
import bokeh.models

In [2]:
# Set the output to 'notebook' mode
bokeh.plotting.output_notebook()


Loading BokehJS ...

In [3]:
# Simple numpy calculation of a sine wave:

x = numpy.arange(0.0, 100.0, 0.1)
y = numpy.sin(x)

In [4]:
# Make a basic interactive plot with bokeh:

p = bokeh.plotting.figure(title="Sin(x)", plot_width=300, plot_height=300)

p.line(x,y, line_width=3.0)

bokeh.plotting.show(p)


Out[4]:

<Bokeh Notebook handle for In[4]>

Recording Mouse Clicks

Bokeh provides a HoverTool that keeps track of where the cursor is, and a TapTool to enable actions on mouse clicks (see the API reference guide for more details about the available tools). We can use both in concert to enable positions to be recorded in the notebook when a click is made.


In [32]:
# Make a data point (a "source") to move around:
s = bokeh.plotting.ColumnDataSource(data = dict(x=[0],y=[0])) # initialize source at the origin (although this doesn't matter)

# Set up a TapTool to listen for mouse clicks, extract the source position, and reset the notebook x, y variables:
tcallback = bokeh.models.CustomJS(args=dict(s=s), code="""
        var x = s.get('data')['x']; // pointer to source x position
        var y = s.get('data')['y']; // pointer to source y position
        var kernel = IPython.notebook.kernel; // not sure why this needs to be declared?
        IPython.notebook.kernel.execute("x = " + x);
        IPython.notebook.kernel.execute("y = " + y);
    """)
tap_tool = bokeh.models.TapTool(callback=tcallback)

# Set up a HoverTool that continuously changes the source position, ready for it to be read by the TapTool:
hcallback = bokeh.models.CustomJS(args=dict(s=s), code="""
        var geometry = cb_data['geometry'];
        var x_data = geometry.x; // current mouse x position in plot coordinates (set by x_range)
        var y_data = geometry.y; // current mouse y position in plot coordinates (set by y_range)
        var x = s.get('data')['x']; // pointer to source x position
        var y = s.get('data')['y']; // pointer to source y position
        console.log("(x,y)=" + x_data+","+y_data); // enable monitoring of values in Javascript console
        x[0] = x_data; // update source x position
        y[0] = y_data; // update source y position
        s.trigger('change');
    """)
hover_tool = bokeh.models.HoverTool(callback=hcallback,tooltips=None)

# "Plot" the point in the figure, with very small size so we only see the cursor in practice:
p = bokeh.plotting.figure(x_range=(0,100), y_range=(0,100), tools=[hover_tool,tap_tool])
p.scatter(x='x',y='y',size=0.001,source=s)
bokeh.plotting.show(p)


Out[32]:

<Bokeh Notebook handle for In[1]>

The x and y variables now contain the position of the last click!


In [31]:
print x, y


52.296875 30.45

In [ ]: