当滑块回调与自定义函数

时间:2018-02-13 13:49:59

标签: python callback bokeh interactive

我尝试实现几个滑块并使用自己的函数foo来计算新值以更新绘图。我试图修改示例from the documentation,但没有成功;页面加载,我可以移动滑块,但情节不会更新(请注意我想使用我无法在javascript中定义的函数;我现在使用foo仅用于说明目的)。

callback一定存在问题(请参阅下面的完整代码):

def callback(source=source):
    data = source.data
    a_dynamic = cb_obj.a_slider.value  # cb_obj.get('a_slider')
    b_dynamic = cb_obj.b_slider.value
    x, y = data['x'], data['y']

    y = foo(x, a_dynamic, b_dynamic)

    source.change.emit()

我不知道如何

1)正确访问滑块值(使用cb_obj.<slider_id>.value,或cb_obj.get(<slider_id>)或完全不同的东西?)

2)给滑块一个实际的ID; title参数只是滑块上方显示的文本,但可能不是它的ID,并且使用id参数不能像我使用它那样工作。

我该如何正确地做到这一点?

import numpy as np
from bokeh.layouts import row, widgetbox
from bokeh.models import CustomJS, Slider
from bokeh.plotting import figure, output_file, show, ColumnDataSource
import bokeh

bokeh.io.reset_output()


def foo(xval, a, b):
    return np.power(xval, a) + b


# some artificial data
a0 = 2.
b0 = 1.
x = np.linspace(-100., 100, 1000)
y = foo(x, a0, b0)


source = ColumnDataSource(data=dict(x=x, y=y))

plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)


def callback(source=source):
    data = source.data
    a_dynamic = cb_obj.a_slider.value  # cb_obj.get('a_slider')
    b_dynamic = cb_obj.b_slider.value
    x, y = data['x'], data['y']

    y = foo(x, a_dynamic, b_dynamic)

    source.change.emit()


a_slider_obj = Slider(start=0, end=3, value=a0, step=0.1, id='a_slider',
                      title="a_slider", callback=CustomJS.from_py_func(callback))
# callback.args["a_slider"] = a_slider_obj

b_slider_obj = Slider(start=-4, end=4, value=b0, step=0.5, id='b_slider',
                      title="b_slider", callback=CustomJS.from_py_func(callback))
# callback.args["b_slider"] = b_slider_obj

layout = row(
    plot,
    widgetbox(a_slider_obj, b_slider_obj),
)

show(layout)

编辑:

似乎这实际上不起作用,但应该使用bokeh server。我现在暂时打开这个问题,以防有人想要使用服务器发布解决方案。然后我接受这个答案,添加一个答案或者如果没有答案就再次删除问题。

1 个答案:

答案 0 :(得分:1)

你很可能需要服务器,特别是如果你想使用一些你用JavaScript无法轻易表达的Python函数。

这是有效的代码。您可以使用bokeh serve运行它。另请注意,您将一些无效的号码传递给np.power,例如-100 ** 2.1nan

import numpy as np

from bokeh.layouts import row, widgetbox
from bokeh.models import Slider
from bokeh.plotting import figure, ColumnDataSource, curdoc


def foo(xval, a, b):
    print(xval.min(), xval.max(), np.isnan(xval).any(), a, b)
    return np.power(xval, a) + b


# some artificial data
a0 = 2.
b0 = 1.
x = np.linspace(-100., 100, 1000)
y = foo(x, a0, b0)

source = ColumnDataSource(data=dict(x=x, y=y))

plot = figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

a_slider_obj = Slider(start=0, end=3, value=a0, step=0.1, id='a_slider', title="a_slider")
b_slider_obj = Slider(start=-4, end=4, value=b0, step=0.5, id='b_slider', title="b_slider")


def callback(attr, old, new):
    data = source.data
    # Since the callback is used by two sliders, we can't just use the `new` argument
    a_dynamic = a_slider_obj.value
    b_dynamic = b_slider_obj.value

    # Here I assume that you wanted to change the value and not just create an unused variable
    data['y'] = foo(data['x'], a_dynamic, b_dynamic)


a_slider_obj.on_change('value', callback)
b_slider_obj.on_change('value', callback)

layout = row(
    plot,
    widgetbox(a_slider_obj, b_slider_obj),
)

curdoc().add_root(layout)