Update slider attributes with server

Hey all,

I’ve started playing with bokeh server applications recently after deciding that my affection for/skill with java was falling far behind that required for some of the applications I wanted to implement. I’ve really loved the extent to which it’s opened up my plotting capabilities, but I’ve run into a bit of a wall with one specific application recently. I want a set of sliders that will control a large number of attributes (which take on values in various ranges and scales). I would like to keep a small number of sliders on the screen at once (say three or four), and have a selection box tied to each one that selects the parameter for that slider to control. Therefore, in the on_change function for the selection boxes, I would like to be able to control the start, end, step, and value of the slider tied to the box. Right now, I do this by simply calling (where param is the current value of slider’s selection box)

slider.start = data[param].min()

slider.end = data[param].max()

…etc.

But this doesn’t seem to be working. Is this currently possible, or should I start looking for an alternative solution?

-Alec

Which version of server, 0.10 or 0.11dev?

This should work in 0.11.dev I think, if not can you share a full running example showing the issue so we can debug?

In 0.10 it’s harder to say; there are several ways to do things in 0.10 and “it depends.”

Havoc

···

On Nov 18, 2015, at 8:09 PM, Alec Gunny [email protected] wrote:

Hey all,

I’ve started playing with bokeh server applications recently after deciding that my affection for/skill with java was falling far behind that required for some of the applications I wanted to implement. I’ve really loved the extent to which it’s opened up my plotting capabilities, but I’ve run into a bit of a wall with one specific application recently. I want a set of sliders that will control a large number of attributes (which take on values in various ranges and scales). I would like to keep a small number of sliders on the screen at once (say three or four), and have a selection box tied to each one that selects the parameter for that slider to control. Therefore, in the on_change function for the selection boxes, I would like to be able to control the start, end, step, and value of the slider tied to the box. Right now, I do this by simply calling (where param is the current value of slider’s selection box)

slider.start = data[param].min()

slider.end = data[param].max()

…etc.

But this doesn’t seem to be working. Is this currently possible, or should I start looking for an alternative solution?

-Alec

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/c63e2e31-c55c-4cae-b6b3-b111a0d84616%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

I’m using version 0.11.0dev

Here is a quick dummy example ripping off the sliders server example in the gallery that closely resembles in principle what I’m trying to do. Note that when you change a parameter selection, the slider will begin to control that parameter, but the start, end, and step values will not adjust accordingly. Any suggestions as to what I might be missing?

import numpy as np

from bokeh.plotting import Figure

from bokeh.models import ColumnDataSource

from bokeh.models.widgets import HBox, Slider, VBoxForm, Select

from bokeh.client import push_session

from bokeh.document import Document

class sinplotter(object):

def init(self, N=200):

self.document = Document()

self.params = {‘amplitude’: 1,

‘frequency’: 1,

‘phase’: 0,

‘offset’: 0

}

self.param_limits = {‘amplitude’: [-5.0, 5.0, 0.2],

‘frequency’: [0.1, 5.1, 0.1],

‘phase’: [0, 2np.pi, 2np.pi/50],

‘offset’: [-5.0, 5.0, 0.1]

}

keys = self.params.keys()

self.selectors = {n: Select(title=“Parameter %i” % (n+1),

value=keys[n],

options=keys)

for n in range(2)

}

self.sliders = {n: Slider(value=self.params[keys[n]],

start=self.param_limits[keys[n]][0],

end=self.param_limits[keys[n]][1],

step=self.param_limits[keys[n]][2]

)

for n in range(2)

}

selection_layout = VBoxForm(children=[VBoxForm(children=[self.selectors[n],

self.sliders[n]

]

) for n in range(2)

]

)

for slider in self.sliders.values():

slider.on_change(‘value’, self.update_sliders)

self.selector_values = {}

for num, selector in self.selectors.items():

selector.on_change(‘value’, self.update_selectors)

self.selector_values[num] = selector.value

self.resetting_selectors = False # keeps from updating plot when we update selection

self.N = N

self.source = ColumnDataSource()

self.update_data()

plot = Figure(plot_height=400, plot_width=400, title=“my sine wave”,

tools=“crosshair,pan,reset,resize,save,wheel_zoom”,

x_range=[0, 4*np.pi], y_range=[-2.5, 2.5]

)

plot.line(‘x’, ‘y’, source=self.source, line_width=3, line_alpha=0.6)

self.document.add(HBox(selection_layout, plot))

self.session = push_session(self.document)

def update_selectors(self, attrname, old, new):

self.resetting_selectors = True # don’t update plot

for num in range(2):

param_name = self.selectors[num].value

if param_name == self.selector_values[num]: # don’t update

continue

self.selector_values[num] = param_name

slider = self.sliders[num]

slider.value = self.params[param_name] # this calls update_sliders

slider.start = self.param_limits[param_name][0]

slider.end = self.param_limits[param_name][1]

slider.step = self.param_limits[param_name][2]

self.resetting_selectors = False # ok to start updating plot again

def update_sliders(self, attrname, old, new):

if self.resetting_selectors:

return

for num in range(2):

self.params[self.selectors[num].value] = self.sliders[num].value

self.update_data()

def update_data(self):

a = self.params[‘amplitude’]

b = self.params[‘offset’]

w = self.params[‘phase’]

k = self.params[‘frequency’]

x = np.linspace(0, 4*np.pi, self.N)

y = anp.sin(kx + w) + b

self.source.data = dict(x=x, y=y)

def run(self, do_view=False, poll_interval=0.5):

if do_view:

self.session.show()

self.session.loop_until_closed()

if name == “main”:

plotter = sinplotter()

plotter.run(do_view=True)

···

On Thursday, November 19, 2015 at 5:49:47 AM UTC-8, Havoc Pennington wrote:

Which version of server, 0.10 or 0.11dev?

This should work in 0.11.dev I think, if not can you share a full running example showing the issue so we can debug?

In 0.10 it’s harder to say; there are several ways to do things in 0.10 and “it depends.”

Havoc

On Nov 18, 2015, at 8:09 PM, Alec Gunny [email protected] wrote:

Hey all,

I’ve started playing with bokeh server applications recently after deciding that my affection for/skill with java was falling far behind that required for some of the applications I wanted to implement. I’ve really loved the extent to which it’s opened up my plotting capabilities, but I’ve run into a bit of a wall with one specific application recently. I want a set of sliders that will control a large number of attributes (which take on values in various ranges and scales). I would like to keep a small number of sliders on the screen at once (say three or four), and have a selection box tied to each one that selects the parameter for that slider to control. Therefore, in the on_change function for the selection boxes, I would like to be able to control the start, end, step, and value of the slider tied to the box. Right now, I do this by simply calling (where param is the current value of slider’s selection box)

slider.start = data[param].min()

slider.end = data[param].max()

…etc.

But this doesn’t seem to be working. Is this currently possible, or should I start looking for an alternative solution?

-Alec

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/c63e2e31-c55c-4cae-b6b3-b111a0d84616%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Hi,

Thanks for the code! It looks to me like the problem is that the Slider view in coffeescript does not watch for changes to the model.

It needs a thing like @listenTo(@model, 'change', @render), except that doesn’t work (maybe @render isn’t expecting to be run more than once, I didn’t figure that part out yet).

Here’s an example of another widget, Icon, that does listen for changes:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/widget/icon.coffee#L11

Here’s the problem file:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/widget/slider.coffee

I filed this issue:

https://github.com/bokeh/bokeh/issues/3169

This would be a great issue for anyone looking to contribute to Bokeh btw (should be pretty straightforward, at least for the javascript-oriented among us). :slight_smile:

The only workaround I can think of in the meantime would be to make a new Slider each time and remove the old one.

Havoc

Havoc

···

On Thu, Nov 19, 2015 at 2:11 PM, Alec Gunny [email protected] wrote:

I’m using version 0.11.0dev

Here is a quick dummy example ripping off the sliders server example in the gallery that closely resembles in principle what I’m trying to do. Note that when you change a parameter selection, the slider will begin to control that parameter, but the start, end, and step values will not adjust accordingly. Any suggestions as to what I might be missing?

import numpy as np

from bokeh.plotting import Figure

from bokeh.models import ColumnDataSource

from bokeh.models.widgets import HBox, Slider, VBoxForm, Select

from bokeh.client import push_session

from bokeh.document import Document

class sinplotter(object):

def init(self, N=200):

self.document = Document()

self.params = {‘amplitude’: 1,

‘frequency’: 1,

‘phase’: 0,

‘offset’: 0

}

self.param_limits = {‘amplitude’: [-5.0, 5.0, 0.2],

‘frequency’: [0.1, 5.1, 0.1],

‘phase’: [0, 2np.pi, 2np.pi/50],

‘offset’: [-5.0, 5.0, 0.1]

}

keys = self.params.keys()

self.selectors = {n: Select(title=“Parameter %i” % (n+1),

value=keys[n],

options=keys)

for n in range(2)

}

self.sliders = {n: Slider(value=self.params[keys[n]],

start=self.param_limits[keys[n]][0],

end=self.param_limits[keys[n]][1],

step=self.param_limits[keys[n]][2]

)

for n in range(2)

}

selection_layout = VBoxForm(children=[VBoxForm(children=[self.selectors[n],

self.sliders[n]

]

) for n in range(2)

]

)

for slider in self.sliders.values():

slider.on_change(‘value’, self.update_sliders)

self.selector_values = {}

for num, selector in self.selectors.items():

selector.on_change(‘value’, self.update_selectors)

self.selector_values[num] = selector.value

self.resetting_selectors = False # keeps from updating plot when we update selection

self.N = N

self.source = ColumnDataSource()

self.update_data()

plot = Figure(plot_height=400, plot_width=400, title=“my sine wave”,

tools=“crosshair,pan,reset,resize,save,wheel_zoom”,

x_range=[0, 4*np.pi], y_range=[-2.5, 2.5]

)

plot.line(‘x’, ‘y’, source=self.source, line_width=3, line_alpha=0.6)

self.document.add(HBox(selection_layout, plot))

self.session = push_session(self.document)

def update_selectors(self, attrname, old, new):

self.resetting_selectors = True # don’t update plot

for num in range(2):

param_name = self.selectors[num].value

if param_name == self.selector_values[num]: # don’t update

continue

self.selector_values[num] = param_name

slider = self.sliders[num]

slider.value = self.params[param_name] # this calls update_sliders

slider.start = self.param_limits[param_name][0]

slider.end = self.param_limits[param_name][1]

slider.step = self.param_limits[param_name][2]

self.resetting_selectors = False # ok to start updating plot again

def update_sliders(self, attrname, old, new):

if self.resetting_selectors:

return

for num in range(2):

self.params[self.selectors[num].value] = self.sliders[num].value

self.update_data()

def update_data(self):

a = self.params[‘amplitude’]

b = self.params[‘offset’]

w = self.params[‘phase’]

k = self.params[‘frequency’]

x = np.linspace(0, 4*np.pi, self.N)

y = anp.sin(kx + w) + b

self.source.data = dict(x=x, y=y)

def run(self, do_view=False, poll_interval=0.5):

if do_view:

self.session.show()

self.session.loop_until_closed()

if name == “main”:

plotter = sinplotter()

plotter.run(do_view=True)

On Thursday, November 19, 2015 at 5:49:47 AM UTC-8, Havoc Pennington wrote:

Which version of server, 0.10 or 0.11dev?

This should work in 0.11.dev I think, if not can you share a full running example showing the issue so we can debug?

In 0.10 it’s harder to say; there are several ways to do things in 0.10 and “it depends.”

Havoc

On Nov 18, 2015, at 8:09 PM, Alec Gunny [email protected] wrote:

Hey all,

I’ve started playing with bokeh server applications recently after deciding that my affection for/skill with java was falling far behind that required for some of the applications I wanted to implement. I’ve really loved the extent to which it’s opened up my plotting capabilities, but I’ve run into a bit of a wall with one specific application recently. I want a set of sliders that will control a large number of attributes (which take on values in various ranges and scales). I would like to keep a small number of sliders on the screen at once (say three or four), and have a selection box tied to each one that selects the parameter for that slider to control. Therefore, in the on_change function for the selection boxes, I would like to be able to control the start, end, step, and value of the slider tied to the box. Right now, I do this by simply calling (where param is the current value of slider’s selection box)

slider.start = data[param].min()

slider.end = data[param].max()

…etc.

But this doesn’t seem to be working. Is this currently possible, or should I start looking for an alternative solution?

-Alec

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/c63e2e31-c55c-4cae-b6b3-b111a0d84616%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/9f441780-e061-4f58-9fdd-88f317bf8106%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Havoc Pennington

Senior Software Architect

Hi Havoc,

Thanks for your help! I’ll take a look at the code today and see what I can throw together

-Alec

···

On Fri, Nov 20, 2015 at 2:30 PM, Havoc Pennington [email protected] wrote:

Hi,

Thanks for the code! It looks to me like the problem is that the Slider view in coffeescript does not watch for changes to the model.

It needs a thing like @listenTo(@model, 'change', @render), except that doesn’t work (maybe @render isn’t expecting to be run more than once, I didn’t figure that part out yet).

Here’s an example of another widget, Icon, that does listen for changes:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/widget/icon.coffee#L11

Here’s the problem file:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/widget/slider.coffee

I filed this issue:

https://github.com/bokeh/bokeh/issues/3169

This would be a great issue for anyone looking to contribute to Bokeh btw (should be pretty straightforward, at least for the javascript-oriented among us). :slight_smile:

The only workaround I can think of in the meantime would be to make a new Slider each time and remove the old one.

Havoc

Havoc

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAC%2B_nE1-CkTHeLXk%3DUdamVzNiuWnDsRV90X6vsHjT8tG1nVKVw%40mail.gmail.com.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

On Thu, Nov 19, 2015 at 2:11 PM, Alec Gunny [email protected] wrote:

I’m using version 0.11.0dev

Here is a quick dummy example ripping off the sliders server example in the gallery that closely resembles in principle what I’m trying to do. Note that when you change a parameter selection, the slider will begin to control that parameter, but the start, end, and step values will not adjust accordingly. Any suggestions as to what I might be missing?

import numpy as np

from bokeh.plotting import Figure

from bokeh.models import ColumnDataSource

from bokeh.models.widgets import HBox, Slider, VBoxForm, Select

from bokeh.client import push_session

from bokeh.document import Document

class sinplotter(object):

def init(self, N=200):

self.document = Document()

self.params = {‘amplitude’: 1,

‘frequency’: 1,

‘phase’: 0,

‘offset’: 0

}

self.param_limits = {‘amplitude’: [-5.0, 5.0, 0.2],

‘frequency’: [0.1, 5.1, 0.1],

‘phase’: [0, 2np.pi, 2np.pi/50],

‘offset’: [-5.0, 5.0, 0.1]

}

keys = self.params.keys()

self.selectors = {n: Select(title=“Parameter %i” % (n+1),

value=keys[n],

options=keys)

for n in range(2)

}

self.sliders = {n: Slider(value=self.params[keys[n]],

start=self.param_limits[keys[n]][0],

end=self.param_limits[keys[n]][1],

step=self.param_limits[keys[n]][2]

)

for n in range(2)

}

selection_layout = VBoxForm(children=[VBoxForm(children=[self.selectors[n],

self.sliders[n]

]

) for n in range(2)

]

)

for slider in self.sliders.values():

slider.on_change(‘value’, self.update_sliders)

self.selector_values = {}

for num, selector in self.selectors.items():

selector.on_change(‘value’, self.update_selectors)

self.selector_values[num] = selector.value

self.resetting_selectors = False # keeps from updating plot when we update selection

self.N = N

self.source = ColumnDataSource()

self.update_data()

plot = Figure(plot_height=400, plot_width=400, title=“my sine wave”,

tools=“crosshair,pan,reset,resize,save,wheel_zoom”,

x_range=[0, 4*np.pi], y_range=[-2.5, 2.5]

)

plot.line(‘x’, ‘y’, source=self.source, line_width=3, line_alpha=0.6)

self.document.add(HBox(selection_layout, plot))

self.session = push_session(self.document)

def update_selectors(self, attrname, old, new):

self.resetting_selectors = True # don’t update plot

for num in range(2):

param_name = self.selectors[num].value

if param_name == self.selector_values[num]: # don’t update

continue

self.selector_values[num] = param_name

slider = self.sliders[num]

slider.value = self.params[param_name] # this calls update_sliders

slider.start = self.param_limits[param_name][0]

slider.end = self.param_limits[param_name][1]

slider.step = self.param_limits[param_name][2]

self.resetting_selectors = False # ok to start updating plot again

def update_sliders(self, attrname, old, new):

if self.resetting_selectors:

return

for num in range(2):

self.params[self.selectors[num].value] = self.sliders[num].value

self.update_data()

def update_data(self):

a = self.params[‘amplitude’]

b = self.params[‘offset’]

w = self.params[‘phase’]

k = self.params[‘frequency’]

x = np.linspace(0, 4*np.pi, self.N)

y = anp.sin(kx + w) + b

self.source.data = dict(x=x, y=y)

def run(self, do_view=False, poll_interval=0.5):

if do_view:

self.session.show()

self.session.loop_until_closed()

if name == “main”:

plotter = sinplotter()

plotter.run(do_view=True)

On Thursday, November 19, 2015 at 5:49:47 AM UTC-8, Havoc Pennington wrote:

Which version of server, 0.10 or 0.11dev?

This should work in 0.11.dev I think, if not can you share a full running example showing the issue so we can debug?

In 0.10 it’s harder to say; there are several ways to do things in 0.10 and “it depends.”

Havoc

On Nov 18, 2015, at 8:09 PM, Alec Gunny [email protected] wrote:

Hey all,

I’ve started playing with bokeh server applications recently after deciding that my affection for/skill with java was falling far behind that required for some of the applications I wanted to implement. I’ve really loved the extent to which it’s opened up my plotting capabilities, but I’ve run into a bit of a wall with one specific application recently. I want a set of sliders that will control a large number of attributes (which take on values in various ranges and scales). I would like to keep a small number of sliders on the screen at once (say three or four), and have a selection box tied to each one that selects the parameter for that slider to control. Therefore, in the on_change function for the selection boxes, I would like to be able to control the start, end, step, and value of the slider tied to the box. Right now, I do this by simply calling (where param is the current value of slider’s selection box)

slider.start = data[param].min()

slider.end = data[param].max()

…etc.

But this doesn’t seem to be working. Is this currently possible, or should I start looking for an alternative solution?

-Alec

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/c63e2e31-c55c-4cae-b6b3-b111a0d84616%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.

You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/9f441780-e061-4f58-9fdd-88f317bf8106%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.


Havoc Pennington

Senior Software Architect