Modifying sliders_app for image instead of line

Hi,
I am modifying the sliders applet (https://github.com/bokeh/bokeh/tree/master/examples/app/sliders_applet) to instead plot an image slice of a set of images stacked in a 3D numpy array. I create the 3D “images” array at the top of the file, outside of the SlidersApp class (i.e. images is global). Here are the basic modifications I made:

In def create(cls):

obj.source = ColumnDataSource(data=dict(image=))

obj.time = Slider(

title=“Time”, name=‘time’,

value=0, start=0, end=data255.shape[-1]-1,step=1

)

plot = figure(height = 600, width = 400, x_range=[0,1], y_range=[0,1])

obj.plot = plot.image(‘image’,source=obj.source,x=[0],y=[0],dw=[1],dh=[1],palette=pal)

``

In def update_data(self):

index = self.time.value

``

self.source.data = dict(image=[data255[…,index]])

``

``

I run bokeh-server --scripy slider_app_mod.py, and the page generates, but the image never shows. I tested the ColumnDataSource and image setup in a simplified code, using output_file, and the image shows fine. I tried modifying my modified slider_app.py to use instead a line plot like the usual slider app, and it works fine.

Any ideas what I’m doing wrong? May be a bug, just wanted to check before I submit a github issue.

Michael

···

Hi Michael,

It’s a bit hard to know what’s going on without any error messages. Can you post anything from the console or the command line? Or, give your complete code example.

Also with regard to server stuff, did you see Bryan’s post on it’s current status/future: https://groups.google.com/a/continuum.io/d/msg/bokeh/LORmlhbVqR0/ryzcsF0tDgAJ

Sincerely,

Sarah Bird

···

On Thursday, August 13, 2015 at 6:30:27 PM UTC+2, Michael wrote:

Hi,
I am modifying the sliders applet (https://github.com/bokeh/bokeh/tree/master/examples/app/sliders_applet) to instead plot an image slice of a set of images stacked in a 3D numpy array. I create the 3D “images” array at the top of the file, outside of the SlidersApp class (i.e. images is global). Here are the basic modifications I made:

In def create(cls):

obj.source = ColumnDataSource(data=dict(image=))

obj.time = Slider(

title=“Time”, name=‘time’,

value=0, start=0, end=data255.shape[-1]-1,step=1

)

plot = figure(height = 600, width = 400, x_range=[0,1], y_range=[0,1])

obj.plot = plot.image(‘image’,source=obj.source,x=[0],y=[0],dw=[1],dh=[1],palette=pal)

``

In def update_data(self):

index = self.time.value

``

self.source.data = dict(image=[data255[…,index]])

``

``

I run bokeh-server --scripy slider_app_mod.py, and the page generates, but the image never shows. I tested the ColumnDataSource and image setup in a simplified code, using output_file, and the image shows fine. I tried modifying my modified slider_app.py to use instead a line plot like the usual slider app, and it works fine.

Any ideas what I’m doing wrong? May be a bug, just wanted to check before I submit a github issue.

Michael

Hi Michael,

I’ve been trying to do something very similar, although in the context of an IPython notebook, and have also run into a problem. I got the first slice to display, but couldn’t get the interaction to work properly. My code is at this Stack Overflow link and is also pasted below.

Apologies for not being able to help, but since I know nothing of Javascript I figured the best I could do is only chime into note the potential similarity in our problems.

Curt

# 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 message:

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.

``

On Thursday, August 13, 2015 at 9:30:27 AM UTC-7, Michael wrote:

Hi,
I am modifying the sliders applet (https://github.com/bokeh/bokeh/tree/master/examples/app/sliders_applet) to instead plot an image slice of a set of images stacked in a 3D numpy array. I create the 3D “images” array at the top of the file, outside of the SlidersApp class (i.e. images is global). Here are the basic modifications I made:

In def create(cls):

obj.source = ColumnDataSource(data=dict(image=))

obj.time = Slider(

title=“Time”, name=‘time’,

value=0, start=0, end=data255.shape[-1]-1,step=1

)

plot = figure(height = 600, width = 400, x_range=[0,1], y_range=[0,1])

obj.plot = plot.image(‘image’,source=obj.source,x=[0],y=[0],dw=[1],dh=[1],palette=pal)

``

In def update_data(self):

index = self.time.value

``

self.source.data = dict(image=[data255[…,index]])

``

``

I run bokeh-server --scripy slider_app_mod.py, and the page generates, but the image never shows. I tested the ColumnDataSource and image setup in a simplified code, using output_file, and the image shows fine. I tried modifying my modified slider_app.py to use instead a line plot like the usual slider app, and it works fine.

Any ideas what I’m doing wrong? May be a bug, just wanted to check before I submit a github issue.

Michael

Hi Sarah,
Thanks for the reply. I’m posting the code and terminal output below for completeness (and if there is something glaringly wrong, there is an Error in the browser error console of 404, not found http://localhost:5001/bokehjs/static/js/jsnlog.js.map), but otherwise I will hold off on making Github issues or being too worried generally about issues that may be related to the current server implementation, as from your link it seems there will is a significant change scheduled for the end of September 2015.

Going forward, even with the new workflow with server models, I hope in the documentation (or a blog post) somewhere there can be added tips for debugging applications (beyond the documentation updates and fleshing out the server portions which are under-documented). I find that not knowing Flask and web frameworks in general, I don’t have a lot of intuition/direction on how to debug applications when something is going wrong. For example, I looked at the bokeh-server flags debugjs and splitjs, but didn’t understand how they could be used, and I also looked at --backend shelve, and was able to open the db files in Python, but didn’t know what was what, and how the pieces fit together to even begin to attempt to see what was incorrect.

~/python$ bokeh-server --script dashboard.py --port 5001

Bokeh Server Configuration

···

==========================

python version : 2.7.10

bokeh version : 0.9.2

listening : 127.0.0.1:5001

backend : memory

python options : debug:OFF, verbose:OFF, filter-logs:OFF, multi-user:OFF

js options : splitjs:OFF, debugjs:OFF

adding to python path

importing dashboard.py

/Users/me/anaconda/lib/python2.7/site-packages/bokeh/server/blaze/init.py:21: UserWarning: could not import multiuser blaze server No module named mbs.views. This is fine if you do not intend to use blaze capabilities in the bokeh server

warnings.warn(msg)

2015-08-18 10:49:36,790:INFO:tornado.access:200 GET / (127.0.0.1) 67.11ms

2015-08-18 10:49:36,950:INFO:tornado.access:304 GET /static/bootstrap/css/bootstrap.min.css (127.0.0.1) 56.89ms

2015-08-18 10:49:36,952:INFO:tornado.access:304 GET /bokehjs/static/js/bokeh.js (127.0.0.1) 1.32ms

2015-08-18 10:49:36,954:INFO:tornado.access:304 GET /bokehjs/static/css/bokeh.css (127.0.0.1) 1.79ms

2015-08-18 10:49:37,290:INFO:tornado.access:200 GET /bokeh/wsurl/ (127.0.0.1) 1.78ms

2015-08-18 10:49:37,406:INFO:tornado.access:200 GET /bokeh/userinfo/ (127.0.0.1) 1.05ms

index: 0

2015-08-18 10:49:40,676:INFO:tornado.access:200 GET /bokeh/dashboard/ (127.0.0.1) 2652.84ms

2015-08-18 10:49:40,688:INFO:tornado.access:304 GET /static/bootstrap/css/bootstrap.min.css (127.0.0.1) 2.23ms

2015-08-18 10:49:40,691:INFO:tornado.access:304 GET /bokehjs/static/js/bokeh.js (127.0.0.1) 1.50ms

2015-08-18 10:49:40,693:INFO:tornado.access:304 GET /bokehjs/static/css/bokeh.css (127.0.0.1) 1.27ms

2015-08-18 10:49:40,698:INFO:tornado.access:200 GET /bokeh/jsgenerate/VBox/dashboard/Dashboard (127.0.0.1) 4.67ms

2015-08-18 10:49:40,876:INFO:tornado.access:200 GET /bokeh/wsurl/ (127.0.0.1) 1.59ms

2015-08-18 10:49:41,633:INFO:tornado.access:200 GET /bokeh/objinfo/5f75f0e8-3526-47a5-b9e3-78079f3cc947/1422613c-e5af-40ac-8213-906645dc82eb (127.0.0.1) 735.75ms

index: 0

2015-08-18 10:49:54,827:INFO:tornado.access:200 GET /bokeh/dashboard/ (127.0.0.1) 380.24ms

2015-08-18 10:49:54,839:INFO:tornado.access:304 GET /static/bootstrap/css/bootstrap.min.css (127.0.0.1) 2.40ms

2015-08-18 10:49:54,841:INFO:tornado.access:200 GET /bokeh/jsgenerate/VBox/dashboard/Dashboard (127.0.0.1) 1.18ms

2015-08-18 10:49:54,843:INFO:tornado.access:304 GET /bokehjs/static/css/bokeh.css (127.0.0.1) 1.50ms

2015-08-18 10:49:54,845:INFO:tornado.access:304 GET /bokehjs/static/js/bokeh.js (127.0.0.1) 1.29ms

2015-08-18 10:49:55,033:INFO:tornado.access:200 GET /bokeh/wsurl/ (127.0.0.1) 1.13ms

2015-08-18 10:49:55,778:INFO:tornado.access:200 GET /bokeh/objinfo/2edf483d-7f30-4a78-b85e-e0e81e7621c7/8b5b7bf1-0e50-4b52-b5c8-f63dd9ff4f9f (127.0.0.1) 726.93ms

2015-08-18 10:50:02,202:WARNING:tornado.access:404 GET /bokehjs/static/js/jsnlog.js.map (127.0.0.1) 10.92ms

2015-08-18 10:50:22,386:INFO:bokeh.server.views.backbone:loading done 30

index: 1

2015-08-18 10:50:23,022:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 858.92ms

2015-08-18 10:50:25,170:INFO:bokeh.server.views.backbone:loading done 30

index: 2

2015-08-18 10:50:25,798:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1034.16ms

2015-08-18 10:50:26,918:INFO:bokeh.server.views.backbone:loading done 30

index: 3

2015-08-18 10:50:27,549:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1018.27ms

2015-08-18 10:50:28,370:INFO:bokeh.server.views.backbone:loading done 30

index: 4

2015-08-18 10:50:29,009:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1026.00ms

2015-08-18 10:50:29,815:INFO:bokeh.server.views.backbone:loading done 30

index: 5

2015-08-18 10:50:30,438:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1010.68ms

2015-08-18 10:50:31,259:INFO:bokeh.server.views.backbone:loading done 30

index: 6

2015-08-18 10:50:31,889:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1017.56ms

2015-08-18 10:50:32,698:INFO:bokeh.server.views.backbone:loading done 30

index: 7

2015-08-18 10:50:33,340:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1037.37ms

2015-08-18 10:50:34,179:INFO:bokeh.server.views.backbone:loading done 30

index: 8

2015-08-18 10:50:34,847:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1079.25ms

2015-08-18 10:50:35,643:INFO:bokeh.server.views.backbone:loading done 30

index: 9

2015-08-18 10:50:36,269:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1009.32ms

2015-08-18 10:50:37,095:INFO:bokeh.server.views.backbone:loading done 30

index: 10

2015-08-18 10:50:37,744:INFO:tornado.access:200 PUT /bokeh/bb/2edf483d-7f30-4a78-b85e-e0e81e7621c7/Slider/9a8d1101-0fb8-49ca-98bb-c38601cf9ff7/ (127.0.0.1) 1030.01ms

“”"
This file demonstrates a bokeh applet, which can be viewed directly
on a bokeh-server. See the README.md file in this directory for
instructions on running.
“”"

import logging

logging.basicConfig(level=logging.DEBUG)

import os

import numpy as np
import random
from matplotlib.tri import Triangulation, LinearTriInterpolator
import matplotlib.cm as cm
import matplotlib as mplib

from bokeh.plotting import figure
from bokeh.models import Plot, ColumnDataSource
from bokeh.properties import Instance
from bokeh.server.app import bokeh_app
from bokeh.server.utils.plugins import object_page
from bokeh.models.widgets import VBox, Slider, TextInput, VBoxForm
#test
from bokeh.io import vform

def bokehPalette(cmapStr):
colormap =cm.get_cmap(cmapStr) #choose any matplotlib colormap here
return [mplib.colors.rgb2hex(m) for m in colormap(np.arange(colormap.N))]

#create data
x = np.linspace(-2,2,400)
y = np.linspace(-4,4,600)
X,Y=np.meshgrid(x,y)
meansx = np.cos(np.linspace(0,2np.pi,200))
meansy = np.sin(np.linspace(0,2
np.pi,200))
stdevs = np.ones(meansx.shape)
tmp=
for mx,my in zip(meansx,meansy):
tmp.append(np.exp(-0.5*((X-mx)**2. + (Y-my)**2.)) / np.sqrt(2*np.pi) * 255)

data255=np.rollaxis(np.array(tmp),0,3)

class Dashboard(VBox):
“”“An example of a browser-based, interactive plot with slider controls.”“”

extra_generated_classes = [["dashboard", "Dashboard", "VBox"]]

inputs = Instance(VBoxForm)

text = Instance(TextInput)

time = Instance(Slider)

plot2D = Instance(Plot)
source = Instance(ColumnDataSource)

@classmethod
def create(cls):
    """One-time creation of app's objects.
    This function is called once, and is responsible for
    creating all objects (plots, datasources, etc)
    """
    obj = cls()

    obj.source = ColumnDataSource(data=dict(image=[data255[...,0]]))
    # obj.source = ColumnDataSource( data=dict(x=[],y=[]) )

    obj.text = TextInput(
        title="title", name='title', value='Dashboard'
    )

    obj.time = Slider(
        title="Time", name='time',
        value=0, start=0, end=data255.shape[-1]-1,step=1
    )

    toolset = "crosshair,pan,reset,resize,save,wheel_zoom"

    # Generate a figure container
    plot2D = figure(title_text_font_size="12pt",
                  height=data255.shape[0],
                  width=data255.shape[1],
                  # tools=toolset,
                  # title=obj.text.value,
                  x_range=[0, 1],
                  y_range=[0, 1]
    )

    # Plot the line by the x,y values in the source property
    plot2D.image('image', source=obj.source,
             x=[0],y=[0],dw=[1],dh=[1],
             palette=bokehPalette('jet')
    )
    # plot2D.line('x','y',source=obj.source)

    obj.plot2D = plot2D

    obj.update_data()

    obj.inputs = VBoxForm(
        children=[
            obj.text, obj.time
        ]
    )
   
    obj.children.append(obj.plot2D)
    obj.children.append(obj.inputs)
    return obj

def setup_events(self):
    """Attaches the on_change event to the value property of the widget.
    The callback is set to the input_change method of this app.
    """
    super(Dashboard, self).setup_events()
    if not self.text:
        return

    # Text box event registration
    self.text.on_change('value', self, 'input_change')

    # Slider event registration
    self.time.on_change('value',self,'input_change')
    for w in ["time"]:
        getattr(self, w).on_change('value', self, 'input_change')

def input_change(self, obj, attrname, old, new):
    """Executes whenever the input form changes.
    It is responsible for updating the plot, or anything else you want.
    Args:
        obj : the object that changed
        attrname : the attr that changed
        old : old value of attr
        new : new value of attr
    """
    self.update_data()
    self.plot2D.title = self.text.value

def update_data(self):
    """Called each time that any watched property changes.
    This updates the sin wave data with the most recent values of the
    sliders. This is stored as two numpy arrays in a dict into the app's
    data source property.
    """

    # Get the current slider values
    index = self.time.value
    # index = int(random.uniform(1,200))
    print 'index: '+str(index)
   
    logging.debug(
        "PARAMS: time: %s", self.time.value
    )

    self.source.data = dict(image=[data255[...,index]])
    # self.source.data = dict(x=data255[200,:,index],y=data255[:,300,index])

The following code adds a “/bokeh/dashboard/” url to the bokeh-server. This

URL will render this dashboard app. If you don’t want to serve this

applet from a Bokeh server (for instance if you are embedding in a separate

Flask application), then just remove this block of code.

@bokeh_app.route(“/bokeh/dashboard/”)
@object_page(“dashboard”)
def make_dashboard():
app = Dashboard.create()
return app

``

On Saturday, August 15, 2015 at 5:12:11 AM UTC-4, Sarah Bird wrote:

Hi Michael,

It’s a bit hard to know what’s going on without any error messages. Can you post anything from the console or the command line? Or, give your complete code example.

Also with regard to server stuff, did you see Bryan’s post on it’s current status/future: https://groups.google.com/a/continuum.io/d/msg/bokeh/LORmlhbVqR0/ryzcsF0tDgAJ

Sincerely,

Sarah Bird

On Thursday, August 13, 2015 at 6:30:27 PM UTC+2, Michael wrote:

Hi,
I am modifying the sliders applet (https://github.com/bokeh/bokeh/tree/master/examples/app/sliders_applet) to instead plot an image slice of a set of images stacked in a 3D numpy array. I create the 3D “images” array at the top of the file, outside of the SlidersApp class (i.e. images is global). Here are the basic modifications I made:

In def create(cls):

obj.source = ColumnDataSource(data=dict(image=))

obj.time = Slider(

title=“Time”, name=‘time’,

value=0, start=0, end=data255.shape[-1]-1,step=1

)

plot = figure(height = 600, width = 400, x_range=[0,1], y_range=[0,1])

obj.plot = plot.image(‘image’,source=obj.source,x=[0],y=[0],dw=[1],dh=[1],palette=pal)

``

In def update_data(self):

index = self.time.value

``

self.source.data = dict(image=[data255[…,index]])

``

``

I run bokeh-server --scripy slider_app_mod.py, and the page generates, but the image never shows. I tested the ColumnDataSource and image setup in a simplified code, using output_file, and the image shows fine. I tried modifying my modified slider_app.py to use instead a line plot like the usual slider app, and it works fine.

Any ideas what I’m doing wrong? May be a bug, just wanted to check before I submit a github issue.

Michael