例如,我正在尝试使用Bokeh回调根据其alpha值过滤RGBA图像。我学习这个库不到一个星期,所以我对它的了解真的很原始。在API example中,我不太了解如何使用这些回调。实现我想要的目标的方法如下:
### RGBA Image
N = 20
img = np.empty((N,N, 4), dtype=np.uint8)
for i in range(N):
for j in range(N):
img[i, j, 0] = int(i/N*255)
img[i, j, 1] = 158
img[i, j, 2] = int(j/N*255)
img[i, j, 3] = np.random.randint(1, 255)
mask = img[:, :, 3]
img = np.squeeze(img.view(np.uint32))
source = ColumnDataSource(data=(dict(image=[img],
x=[0],
y=[0],
dw=[10],
dh=[10])))
p = figure(x_range=(0,10), y_range=(0,10))
p.image_rgba(source=source, image='image', x='x', y='y', dw='dw', dh='dh')
### Threshold Slider
def slider_callback(source=source):
data = source.data
img = data['image']
img = img * (mask > cb_obj.value).astype(int)
source.change.emit();
t_slider = Slider(start=0, end=255, value=255, step=1,
title="Threshold", width=140,
callback=CustomJS.from_py_func(slider_callback))
l = layout([t_slider, p])
curdoc().add_root(l)
show(l)
由于在更改滑块值时我看不到绘图中的任何变化,因此我想不到如何使用此回调。
答案 0 :(得分:2)
首先,作为一个温和的建议:请不要在示例代码中忽略导入。为他人提供帮助的最快方法是能够直接按原样直接运行示例代码,这对于不完整的代码是不可能的
此代码有几个不同的问题,我将尝试解决它们:
CustomJS.from_py_func
已过时,以后将被删除,不应使用
即使不是这种情况,from_py_func
最终也会生成在您的浏览器中运行的 JavaScript 代码。它只能转换简单的普通Python dode,而不能转换任何依赖于诸如Numpy或Pandas之类的真实Python库的python代码。您对astype
的调用和所有花哨的切片都是 Numpy 函数,浏览器对此一无所知,因此这种方法可能行不通。
因此,要能够在回调中运行真实的Python代码,您必须制作一个Bokeh Server application,但要明确一点,Bokeh服务器应用必须使用 运行bokeh服务器,即类似于
bokeh serve --show myapp.py
回调的逻辑也不正确。它将新值分配给局部变量img
,然后将其丢弃。它不会不指定source.data
的值,而该值将触发Bokeh根据新数据更新绘图。您将需要回调和连接,例如:
t_slider = Slider(start=0, end=255, value=255, step=1,
title="Threshold", width=140)
def slider_callback(attr, old, new):
source.data['image'] = [(mask > t_slider.value).astype(int)]
t_slider.on_change('value', slider_callback)
还要注意source.data['image']
的列表值,该值必须是图像的列表/数组(因为image
可以一次显示多个图像),因此该列表是相关的。
如果进行上述更改并使用bokeh serve
运行代码,则在清理滑块时绘图会更新的意义上说“工作”。但是回调逻辑将大多数图像数组设置为零,从而导致空白图。如果不了解您要实际完成的工作,就无法通过回调逻辑提供更多帮助。
编辑:如果您打算使用遮罩以某种方式更新显示的图像,则还应注意,每次在回调中都必须复制原始图像。否则,您将基于原始的第一次在回调运行时进行更新,但是随后的回调将永远修改已修改的版本。即您将需要以下内容:
def slider_callback(attr, old, new):
newimg = img.copy()
newimg[(mask > t_slider.value).astype(int)] = 0
source.data['image'] = [newimg]