【问题标题】:Filter image with slider in Bokeh在散景中使用滑块过滤图像
【发布时间】:2019-02-19 18:47:10
【问题描述】:

我正在尝试根据其 alpha 值过滤 RGBA 图像,例如,使用 Bokeh 回调。我研究这个图书馆不到一个星期,所以我对它的了解真的很原始。从 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)

由于我在更改滑块值时没有看到绘图有任何变化,所以我想我不知道如何使用此回调。

【问题讨论】:

    标签: python callback bokeh


    【解决方案1】:

    首先,作为一个温和的建议:请不要在示例代码中省略导入。其他人提供帮助的最快方法是能够立即、直接、按原样运行示例代码,这对于不完整的代码是不可能的

    这段代码有几个不同的问题,我会尝试解决它们:

    • 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 运行您的代码,那么在滑动滑块时绘图会更新的意义上,事情“有效”。但是回调逻辑将大部分图像数组设置为零,从而导致空白图。如果不了解您要实际完成的工作,就无法在回调逻辑方面提供更多帮助。

    编辑:如果您的意图是使用掩码来更新显示的图像,您还应该知道,您必须在每次回调中复制原始图像。否则,您将在回调运行时第一次根据原始版本进行更新,但随后的回调将永远修改已修改的版本。 IE。你需要这样的东西:

    def slider_callback(attr, old, new):
        newimg = img.copy()
        newimg[(mask > t_slider.value).astype(int)] = 0
        source.data['image'] = [newimg]
    

    【讨论】:

    • 我能再问你一个愚蠢的问题吗?这是否已弃用(remote_jupyter_proxy_url,来自bokeh.pydata.org/en/latest/docs/user_guide/…)?我尝试使用所以我不必腌制所有数据并且仍然收到警告错误:You are generating standalone HTML/JS output, but trying to use real Python callbacks.
    • 它没有被弃用,但我想不出它会在散景应用程序或jupyter笔记本之外使用的任何情况,所以我真的可以想象你正在尝试的细节。
    • 我试图在 jupyter 笔记本中调用您的示例。
    • 使用 Bokeh 对象调用 show 只会生成纯 HTML/JS,无论是否在笔记本中。真正的 Python 回调永远不能与 show 一起工作,除非通过传递一个应用程序定义的 function。您可以通过传递这样一个函数在笔记本中运行/嵌入散景服务器应用程序,示例笔记本在这里github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 2023-03-09
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    相关资源
    最近更新 更多