Reputation: 10150
Im using bokeh server to plot a line graph, where theres a checkbox button that will flip the line if its checked. If its unchecked I want to see the original version of the line (unflipped). Following the flip/unflip, a second function is called to perform some other calculations:
import numpy as np
from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox, layout
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import CheckboxGroup
from bokeh.plotting import figure
def flip_signal(signal, flip):
if flip:
signal = -signal
else:
signal = signal
return signal
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))
plot = figure(plot_height=500, plot_width=850, title="test",
tools="crosshair,pan,reset,save,wheel_zoom")
line_orig = plot.line('x', 'y', source=source, line_width=1, line_alpha=1)
flip_signal_btn = CheckboxGroup(labels=["Flip signal"])
def update_flip(attrname, old, new):
if 0 in flip_signal_btn.active:
flip = True
else:
flip = False
# Update plot
source.data = dict(x=source.data['x'], y=flip_signal(source.data['y'], flip))
def update_peaks(attrname, old, new):
# do something else
pass
for w in [flip_signal_btn]:
w.on_change('active', update_flip)
w.on_change('active', update_peaks)
options = widgetbox(flip_signal_btn)
doc_layout = layout(row([options], height=200))
curdoc().add_root(row(plot, doc_layout, width=800))
curdoc().title = "checkbox"
The checkbox only seems to call update_flip
when its checked, so in order to flip (or unflip) the signal I need to click it twice. For example, when I uncheck the box nothing happens, but I'm expecting it to unflip the signal. Rather it only unflips the signal if I uncheck and then check the box again
Upvotes: 1
Views: 1678
Reputation: 34568
The callback is being invoked with the correct values on every button click, as can be verified with some print
statements. The error is in your logic. Since you are operating on the current signal, rather than some original signal, you presumably always want to flip every time, unconditionally. Currently, you are only flipping every other button push, because this flip_signal(..., False)
just returns the signal passed in, as-is. Changing the update_flip
callback to always flip yields the behavior you want:
def update_flip(attrname, old, new):
# flip the *current* data on *every* button toggle
source.data = dict(x=source.data['x'], y=flip_signal(source.data['y'], True))
For your logic to work you would need a different function than your current flip_signal
. You would need a function that always returns the original unflipped signal on False
, and always returns the flipped signal on True
. Contrast this with the current flip_signal
, if you call it with False
it gives you back whatever you passed in, regardless of whether it is the flipped or unflipped signal.
Upvotes: 1