animation within bokeh app

Hi all,

I have a bokeh app that, depending on user input, may require a lengthy (~10 second) processing/calculation step. Because I don’t want to the user to just sit there thinking the app is broken, I’d like to use a PreText field that displays the status. So normally the PreText text will be something like “Please select an option”, but when a user select the option that triggers the long calculation, I’d like to update that text with “Pulling data from the database”, “Calculating metrics”, etc.

The example below shows the concept of what I’d like to do. It’s just a select widget and a PreText field. The select widget has a callback that triggers a set_selection method, which runs a for-loop that should result in the PreText reading ‘testing 1’, followed by a 1 second delay, then ‘testing 2’, etc. However, the increments are never displayed. The app waits until the loop is completely finished and then displays the final ‘testing 3’. How can I get the PreText field to update at each stage of the loop - not just the last one?

I looked at the slideshow example in the repository, but that relies on cursession, which doesn’t seem to work when loading a script into bokeh server from the command line.

Many thanks,

Schaun

from bokeh.properties import Instance, String

from bokeh.models.widgets.markups import PreText

from bokeh.models.widgets.layouts import VBox, VBoxForm

from bokeh.models.widgets.inputs import Select

from bokeh.server.app import bokeh_app

from bokeh.server.utils.plugins import object_page

from bokeh.plotting import curdoc

from time import sleep

class Progress(VBox):

extra_generated_classes = [[“Progress”, “Progress”, “VBox”]]

jsmodel = “VBox”

layout boxes

input_box = Instance(VBoxForm)

paragraph = Instance(PreText)

inputs

type_select = Instance(Select)

types = String(default=‘1’)

def init(self, *args, **kwargs):

super(Progress, self).init(*args, **kwargs)

@classmethod

def create(cls):

obj = cls()

obj.input_box = VBoxForm()

obj.paragraph = PreText(text=‘Select something.’)

obj.set_inputs()

obj.set_children()

return obj

def set_inputs(self):

self.type_select = Select(value=‘1’, options=[‘1’, ‘2’, ‘3’])

def set_children(self):

self.input_box.children = [self.type_select]

self.children = [self.input_box, self.paragraph]

curdoc().add(self)

def set_selection(self, obj, attr, old, new):

if obj == self.type_select:

self.types = new

for i in range(1, 4):

self.paragraph.text = ‘testing {ind}’.format(ind=i)

self.set_children()

sleep(1.0)

def setup_events(self):

super(Progress, self).setup_events()

if self.type_select:

self.type_select.on_change(‘value’, self, ‘set_selection’)

@bokeh_app.route("/bokeh/progress/")

@object_page(“progress”)

def make_menu():

app = Progress.create()

return app

``

Any suggestions on this?

···

On Tuesday, May 5, 2015 at 9:48:11 PM UTC-4, Schaun Wheeler wrote:

Hi all,

I have a bokeh app that, depending on user input, may require a lengthy (~10 second) processing/calculation step. Because I don’t want to the user to just sit there thinking the app is broken, I’d like to use a PreText field that displays the status. So normally the PreText text will be something like “Please select an option”, but when a user select the option that triggers the long calculation, I’d like to update that text with “Pulling data from the database”, “Calculating metrics”, etc.

The example below shows the concept of what I’d like to do. It’s just a select widget and a PreText field. The select widget has a callback that triggers a set_selection method, which runs a for-loop that should result in the PreText reading ‘testing 1’, followed by a 1 second delay, then ‘testing 2’, etc. However, the increments are never displayed. The app waits until the loop is completely finished and then displays the final ‘testing 3’. How can I get the PreText field to update at each stage of the loop - not just the last one?

I looked at the slideshow example in the repository, but that relies on cursession, which doesn’t seem to work when loading a script into bokeh server from the command line.

Many thanks,

Schaun

from bokeh.properties import Instance, String

from bokeh.models.widgets.markups import PreText

from bokeh.models.widgets.layouts import VBox, VBoxForm

from bokeh.models.widgets.inputs import Select

from bokeh.server.app import bokeh_app

from bokeh.server.utils.plugins import object_page

from bokeh.plotting import curdoc

from time import sleep

class Progress(VBox):

extra_generated_classes = [[“Progress”, “Progress”, “VBox”]]

jsmodel = “VBox”

layout boxes

input_box = Instance(VBoxForm)

paragraph = Instance(PreText)

inputs

type_select = Instance(Select)

types = String(default=‘1’)

def init(self, *args, **kwargs):

super(Progress, self).init(*args, **kwargs)

@classmethod

def create(cls):

obj = cls()

obj.input_box = VBoxForm()

obj.paragraph = PreText(text=‘Select something.’)

obj.set_inputs()

obj.set_children()

return obj

def set_inputs(self):

self.type_select = Select(value=‘1’, options=[‘1’, ‘2’, ‘3’])

def set_children(self):

self.input_box.children = [self.type_select]

self.children = [self.input_box, self.paragraph]

curdoc().add(self)

def set_selection(self, obj, attr, old, new):

if obj == self.type_select:

self.types = new

for i in range(1, 4):

self.paragraph.text = ‘testing {ind}’.format(ind=i)

self.set_children()

sleep(1.0)

def setup_events(self):

super(Progress, self).setup_events()

if self.type_select:

self.type_select.on_change(‘value’, self, ‘set_selection’)

@bokeh_app.route("/bokeh/progress/")

@object_page(“progress”)

def make_menu():

app = Progress.create()

return app

``

I opened a github issue here since I am also interested in this. I think as of now the bokeh-server is only designed to send a single response for every request (e.g. on your Select callback) it receives. A hack would be to use multiple request-response cycles, where each request is generated by updating some hidden model attribute on the js side. For example, the PreText could store a counter of the number of updates it sees, increment and publish that counter to bokeh-server every time its text attribute is updated, and the downstream script can listen to changes in the counter and determine what new text the PreText should display. I did a similar thing with an icon’s spin state in this commit.

···

On Thursday, May 7, 2015 at 11:37:10 AM UTC-4, Schaun Wheeler wrote:

Any suggestions on this?

On Tuesday, May 5, 2015 at 9:48:11 PM UTC-4, Schaun Wheeler wrote:

Hi all,

I have a bokeh app that, depending on user input, may require a lengthy (~10 second) processing/calculation step. Because I don’t want to the user to just sit there thinking the app is broken, I’d like to use a PreText field that displays the status. So normally the PreText text will be something like “Please select an option”, but when a user select the option that triggers the long calculation, I’d like to update that text with “Pulling data from the database”, “Calculating metrics”, etc.

The example below shows the concept of what I’d like to do. It’s just a select widget and a PreText field. The select widget has a callback that triggers a set_selection method, which runs a for-loop that should result in the PreText reading ‘testing 1’, followed by a 1 second delay, then ‘testing 2’, etc. However, the increments are never displayed. The app waits until the loop is completely finished and then displays the final ‘testing 3’. How can I get the PreText field to update at each stage of the loop - not just the last one?

I looked at the slideshow example in the repository, but that relies on cursession, which doesn’t seem to work when loading a script into bokeh server from the command line.

Many thanks,

Schaun

from bokeh.properties import Instance, String

from bokeh.models.widgets.markups import PreText

from bokeh.models.widgets.layouts import VBox, VBoxForm

from bokeh.models.widgets.inputs import Select

from bokeh.server.app import bokeh_app

from bokeh.server.utils.plugins import object_page

from bokeh.plotting import curdoc

from time import sleep

class Progress(VBox):

extra_generated_classes = [[“Progress”, “Progress”, “VBox”]]

jsmodel = “VBox”

layout boxes

input_box = Instance(VBoxForm)

paragraph = Instance(PreText)

inputs

type_select = Instance(Select)

types = String(default=‘1’)

def init(self, *args, **kwargs):

super(Progress, self).init(*args, **kwargs)

@classmethod

def create(cls):

obj = cls()

obj.input_box = VBoxForm()

obj.paragraph = PreText(text=‘Select something.’)

obj.set_inputs()

obj.set_children()

return obj

def set_inputs(self):

self.type_select = Select(value=‘1’, options=[‘1’, ‘2’, ‘3’])

def set_children(self):

self.input_box.children = [self.type_select]

self.children = [self.input_box, self.paragraph]

curdoc().add(self)

def set_selection(self, obj, attr, old, new):

if obj == self.type_select:

self.types = new

for i in range(1, 4):

self.paragraph.text = ‘testing {ind}’.format(ind=i)

self.set_children()

sleep(1.0)

def setup_events(self):

super(Progress, self).setup_events()

if self.type_select:

self.type_select.on_change(‘value’, self, ‘set_selection’)

@bokeh_app.route("/bokeh/progress/")

@object_page(“progress”)

def make_menu():

app = Progress.create()

return app

``