Python 强制更新bokeh小部件?

Python 强制更新bokeh小部件?,python,bokeh,Python,Bokeh,我是bokeh的新手,正在编写一个小的bokeh服务器应用程序,它有绘图和按钮。按下按钮后,数据将重新计算并更新打印。这个想法是,只要按下按钮,它就会改变颜色和标签,还会出现一个文本“计算…”。计算完成后,打印更新,文本消失 但是,当按下按钮时,它不会改变颜色,并且在计算完成之前不会显示文本(需要几秒钟)。所有这些小部件更新都发生在计算之后。问题,有没有可能强制小部件更新,比如print()中的flush=True或者类似的东西 我在博克文档中找不到任何东西。我还尝试将小部件的更改和计算分离,并

我是bokeh的新手,正在编写一个小的bokeh服务器应用程序,它有绘图和按钮。按下按钮后,数据将重新计算并更新打印。这个想法是,只要按下按钮,它就会改变颜色和标签,还会出现一个文本“计算…”。计算完成后,打印更新,文本消失

但是,当按下按钮时,它不会改变颜色,并且在计算完成之前不会显示文本(需要几秒钟)。所有这些小部件更新都发生在计算之后。问题,有没有可能强制小部件更新,比如print()中的flush=True或者类似的东西

我在博克文档中找不到任何东西。我还尝试将小部件的更改和计算分离,并在两个单独的函数中执行它们,但没有帮助。设置按钮更改和调用计算函数之间的延迟也没有帮助。看起来,小部件的更新只在退出回调函数时发生,甚至更晚。我唯一没有检查的是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才能发送数据更新。在您的例子中,您在运行计算时不会每次都产生控件,因此当回调已经完成时,它会发送所有更新

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

def回调(arg):
全局变量
全局过程标记
变量=非变量
#更改按钮样式
如果变量为:
switchButton.update(标签='Anticrossing ON',
按钮(类型='success')
其他:
switchButton.update(标签='Anticrossing OFF',
按钮类型='默认')
#显示“计算…”
process_markup.update(可见=真)
def calc():
#长时间计算
x、 y=计算_数据(变量)
source.data={“x”:x,“y”:y}
#隐藏“计算…”
process_markup.update(可见=假)
curdoc().添加下一个勾选回调(计算)

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

只有当控件返回到服务器事件循环时,Bokeh才能发送数据更新。在您的例子中,您在运行计算时不会每次都产生控件,因此当回调已经完成时,它会发送所有更新

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

def回调(arg):
全局变量
全局过程标记
变量=非变量
#更改按钮样式
如果变量为:
switchButton.update(标签='Anticrossing ON',
按钮(类型='success')
其他:
switchButton.update(标签='Anticrossing OFF',
按钮类型='默认')
#显示“计算…”
process_markup.update(可见=真)
def calc():
#长时间计算
x、 y=计算_数据(变量)
source.data={“x”:x,“y”:y}
#隐藏“计算…”
process_markup.update(可见=假)
curdoc().添加下一个勾选回调(计算)

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

Perfect,这解决了我的问题。非常感谢@EugenePakhomov!很好,这解决了我的问题。非常感谢@EugenePakhomov!