强制更新散景小部件?

Force update of bokeh widgets?

我是散景的新手,正在编写一个小型散景服务器应用程序,其中包含绘图和按钮。按下按钮时,将重新计算数据并更新绘图。这个想法是,一旦按下按钮,它就会改变颜色和标签,还会出现文本 "calculating..." 。计算完成后,绘图更新并且文本消失。

但是,当按下按钮时,它不会改变颜色并且在计算完成之前不会出现文本(需要几秒钟)。所有这些小部件更新都发生在计算之后。问题,是否可以强制更新小部件,例如 flush=True 在 print() 或类似的情况下?

我在散景文档中找不到任何内容。我也尝试过将小部件更改和计算分开并在两个单独的函数中执行它们,但它没有帮助。在按钮更改和调用计算功能之间设置延迟也无济于事。似乎,小部件的更新只发生在退出回调函数时甚至更晚。我唯一没有检查的是CustomJS,但我不知道如何编写用于按钮更新的js代码。

感谢您的帮助!

这是一个接近我实际使用的代码示例:

from bokeh.plotting import figure
from bokeh.models import Button, PreText, ColumnDataSource
from bokeh.layouts import row

p = figure()
source = ColumnDataSource(data={"x":[0], "y":[0]})
p.line(x="x", y="y", source=source)
variable = False

# initialise widgets
switchButton = Button(label='Anticrossing OFF', button_type="default")
process_markup = PreText(text='Calculating...', visible=False)

def callback(arg):
    global variable
    global process_markup

    variable = not variable

    # change button style
    if variable:
        switchButton.update(label = 'Anticrossing ON',
                              button_type = 'success')
    else:
        switchButton.update(label = 'Anticrossing OFF',
                              button_type = 'default')
    # show "calculating..."
    process_markup.update(visible=True)

    # do long calculations
    x, y = calculate_data(variable)
    source.data = {"x":x, "y":y}

    # hide "calculating..."
    process_markup.update(visible=False)

switchButton.on_click(callback)
col = column(switchButton, process_markup)
curdoc().add_root(row(col, p))

Bokeh 只能在控件返回到服务器事件循环时发送数据更新。在您的情况下,您 运行 计算没有每次都放弃控制,因此它会在回调完成后发送所有更新。

在您的情况下,最简单的做法是将回调拆分为需要同步的块,并且 运行 每个块在下一个报价回调中:

def callback(arg):
    global variable
    global process_markup

    variable = not variable

    # change button style
    if variable:
        switchButton.update(label = 'Anticrossing ON',
                              button_type = 'success')
    else:
        switchButton.update(label = 'Anticrossing OFF',
                              button_type = 'default')
    # show "calculating..."
    process_markup.update(visible=True)

    def calc():
        # do long calculations
        x, y = calculate_data(variable)
        source.data = {"x":x, "y":y}

        # hide "calculating..."
        process_markup.update(visible=False)

    curdoc().add_next_tick_callback(calc)

但是请注意,这种解决方案仅适用于您是唯一用户并且在计算 运行ning 期间不需要执行任何操作的情况。原因是计算是阻塞的——当它处于 运行ning 时,你无法以任何方式与 Bokeh 通信。一个合适的解决方案需要一些异步,例如线程。有关详细信息,请查看 Bokeh 用户指南的 Updating From Threads 部分。