散景:无法从 doc.add_periodic_callback() 触发 ColumnDataSource 上的 js_on_change

Bokeh: Failed to trigger js_on_change on ColumnDataSource from doc.add_periodic_callback()

我正在尝试从散景服务器中的另一个线程更新坡度 y_intercept。但是我无法触发js_on_change,似乎连javascript代码都没有生成。有人可以告诉我这里出了什么问题吗?这是整个代码(更新为使用 add_periodic_callback()):

#!/usr/bin/env python3
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slope, CustomJS
from bokeh.plotting import figure
from bokeh.server.server import Server
import pandas as pd

source = ColumnDataSource()
n = 0

def update():
    global n
    source.data = pd.DataFrame({"y": [n]})
    print(f"{source.data=}")
    n += 1

def bkapp(doc):
    plot = figure(y_range=(-10, 10))
    plot.line([-10, 10], [-10, 10])
    slope = Slope(gradient=0, y_intercept=0, line_color='black')
    plot.add_layout(slope)

    source.js_on_change('data', CustomJS(
        args=dict(ds=source, slopes=slope), code="""
        console.log("whereismycode");
        slope.y_intercept = ds.data["y"][0];
        """
        ))

    doc.add_root(plot)
    doc.add_periodic_callback(update, 5000)

server = Server({'/': bkapp}, port=5103, num_procs=1)
server.start()

if __name__ == '__main__':
    print(f'address = {server.address}, port = {server.port}')

    server.io_loop.add_callback(server.show, "/")
    server.io_loop.start()

这是工作代码。正如 Tim Roberts 指出的那样,问题在于 bokeh doc 不知道数据源。一个 hacky 解决方案是将它附加到隐藏的字形。 @bigreddot,也许有专门用于此目的的特殊方法?

#!/usr/bin/env python3
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slope, CustomJS, DataTable
from bokeh.plotting import figure
from bokeh.server.server import Server
from bokeh.layouts import column
import pandas as pd

source = ColumnDataSource()
n = 0

def update():
    global n
    source.data = pd.DataFrame({"y": [n]})
    print(f"{source.data=}")
    n += 1

def bkapp(doc):
    plot = figure(y_range=(-10, 10))
    plot.line([-10, 10], [-10, 10])
    slope = Slope(gradient=0, y_intercept=0, line_color='black')
    plot.add_layout(slope)

    table = DataTable(source=source, visible=False)

    source.js_on_change('data', CustomJS(
        args=dict(ds=source, slope=slope), code="""
        console.log("whereismycode");
        slope.y_intercept = ds.data["y"][0];
        """
        ))

    doc.add_root(column([plot, table]))
    doc.add_periodic_callback(update, 5000)

server = Server({'/': bkapp}, port=5103, num_procs=1)
server.start()

if __name__ == '__main__':
    print(f'address = {server.address}, port = {server.port}')

    server.io_loop.add_callback(server.show, "/")
    server.io_loop.start()

纯粹基于问题,完全如上文所述,根本不需要CDS来更新斜率,加一个就是over-complication。这是我要写的代码:

import pandas as pd
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS, Slope
from bokeh.plotting import figure
from bokeh.server.server import Server

n = 0

def bkapp(doc):
    plot = figure(y_range=(-10, 10))
    plot.line([-10, 10], [-10, 10])
    slope = Slope(gradient=0, y_intercept=0, line_color='black')
    plot.add_layout(slope)

    def update():
        global n
        slope.y_intercept = n
        n += 1

    doc.add_root(plot)
    doc.add_periodic_callback(update, 5000)

server = Server({'/': bkapp}, port=5103, num_procs=1)
server.start()

if __name__ == '__main__':
    print(f'address = {server.address}, port = {server.port}')

    server.io_loop.add_callback(server.show, "/")
    server.io_loop.start()

顺便说一句,请注意,如果您希望一次拥有多个 user/session,那么就不会有任何“全局”Bokeh 模型(例如,您的情况下的全局 CDS) . bkapp 函数必须 return 每个会话 完全唯一的新对象集