I'm interested in using Bokeh to put images inside IPython notebooks. In particular a datatype I often interact with is a multidimensional NumPy array with 3 or more dimensions. Take the example of a 3-dimensional array. An oft-encountered example is RGB images. The three dimensions are x
, y
, and color
I'm interested in using Bokeh to plot a single image channel in an IPython notebook. I'd like to provide an interactive slider that allows the user of the IPython notebook to click through each index of the 3rd dimension, in this example, color.
My code below (when run in an IPython notebook) successfully shows the plot of the first color channel. But I can't figure out what is causing the error in my call to interact
. Do I have my ColumnDataSource
defined correctly and referenced correctly in the Bokeh plot construction?
# imports
import numpy as np
from scipy.misc import imread
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import ColumnDataSource
from bokeh.palettes import Greys9
from IPython.html.widgets import interact
# enable Bokeh to plot to the notebook
output_notebook()
# Make the Bokeh plot of the "first" layer of the 3D data
## This part works
TOOLS="pan, box_zoom, reset, save"
# The image from https://windycitizensports.files.wordpress.com/2011/10/baboon.jpg?w=595
RGB_image = imread('/Users/curt/Downloads/BaboonRGB.jpg')
nx, ny, n_colors = RGB_image.shape
source = ColumnDataSource(data={'image': RGB_image[:, :, 0]})
p = figure(title="ColorChannel",
tools=TOOLS,
x_range=[0, nx],
y_range=[0, ny],
)
p.image([source.data['image'][::-1, :]-1],
x=0,
y=0,
dh=[ny],
dw=[nx],
palette=Greys9,
source=source,
)
show(p)
# try to add interactive slider
## This part does not work & gives a JavaScript error
def update(idx=0):
global RGB_image
source.data['image'] = RGB_image[:, :, idx]
source.push_notebook()
interact(update, idx=(0, 2))
The Javascript error is:
Javascript error adding output!
TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided float value is non-finite.
See your browser Javascript console for more details.
I'm not sure how this can be. I tried coercing RGB_Image
to a float by doing RGB_Image = RGB_Image.astype(float)
immediately after defining it but I got the same error.
In essence, the data format is not consistent between your predefined image and what you are trying to update.
A workaround which does work:
def update(idx=0):
global RGB_image
source.data['image'] = RGB_image[:, :, idx]
p.image([source.data['image'][::-1, :]-1],
x=0,
y=0,
dh=[ny],
dw=[nx],
palette=Greys9,
source=source,
)
show(p)
interact(update, idx=(0, 2))
I'll acknowledge that defining the image over and over again is not the preferred way of doing this, but it should at least give you a handle as to where to look.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With