Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interactive slider to vary slice used in Bokeh image plot

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.

like image 474
Curt F. Avatar asked Aug 13 '15 04:08

Curt F.


1 Answers

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.

like image 161
Uvar Avatar answered Oct 12 '22 14:10

Uvar