【问题标题】:Bokeh: Failed to trigger js_on_change on ColumnDataSource from doc.add_periodic_callback()散景:无法从 doc.add_periodic_callback() 触发 ColumnDataSource 上的 js_on_change
【发布时间】:2022-02-22 15:38:40
【问题描述】:

我正在尝试从散景服务器中的另一个线程更新 Slope 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()

【问题讨论】:

  • 如果您希望update 在固定的时间间隔内继续发生,那么 Bokeh 的内置 add_periodic_callback 似乎是一个更好的选择。否则,您将需要执行docs.bokeh.org/en/latest/docs/user_guide/… 中描述的进程,其中线程调用add_next_tick_callback
  • @bigreddot,我更新了代码,问题是一样的
  • 您已将plot 添加为文档根目录,但您在哪里告诉它source 是文档的一部分?它怎么知道看它?是我不明白的散景魔法吗?
  • @TimRoberts,我也对这部分感到困惑,我怎么能告诉散景这个数据源应该在文档中使用而不在 python 代码中使用它? (但只能在 javascript 中使用)
  • 使用这个方法:stackoverflow.com/questions/68683190/…,我触发了回调

标签: python bokeh


【解决方案1】:

纯粹基于问题,正如上面介绍的那样,根本不需要 CDS 来更新斜率,并且添加一个过于复杂。这是我要写的代码:

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()

顺便说一句,请注意,如果您希望一次拥有多个用户/会话,则不能有任何“全局”散景模型(例如,在您的情况下,就像全局 CDS)。 bkapp 函数必须为每个会话返回一个完全独特的新对象集

【讨论】:

  • 啊,没意识到python对象和javascript对象是自动同步的!
【解决方案2】:

这是工作代码。正如蒂姆罗伯茨指出的那样,问题在于散景文档不了解数据源。一个 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()

【讨论】:

  • 您应该能够在 args 中传递 DataModel 子类,但即使这样也不是必需的(见上文),除非问题缺少重要要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多