当滑块回调与自定义函数一起使用时,绘图不会更新
Plot does not update when slider callback is used with self-defined function
我尝试实现多个滑块并使用自己的函数 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。如果有人想 post 使用服务器的解决方案,我暂时保留这个问题。然后我要么接受这个答案,添加自己的答案,要么在没有答案出现时再次删除问题。
你是对的,你很可能需要服务器,特别是如果你想使用一些你不能轻易用 JavaScript 表达的 Python 功能。
这是有效的代码。你可以 运行 它与 bokeh serve
。另请注意,您将一些无效数字传递给 np.power
因为例如-100 ** 2.1
是 nan
。
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)
我尝试实现多个滑块并使用自己的函数 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。如果有人想 post 使用服务器的解决方案,我暂时保留这个问题。然后我要么接受这个答案,添加自己的答案,要么在没有答案出现时再次删除问题。
你是对的,你很可能需要服务器,特别是如果你想使用一些你不能轻易用 JavaScript 表达的 Python 功能。
这是有效的代码。你可以 运行 它与 bokeh serve
。另请注意,您将一些无效数字传递给 np.power
因为例如-100 ** 2.1
是 nan
。
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)