Can I update a bokeh plot without callbacks from the server?

时光总嘲笑我的痴心妄想 提交于 2020-02-02 12:23:46

问题


I want Bokeh to update periodically and arbitrarily when the results from a separate algorithm running in python returns results, not based on any input from the Bokeh interface.

I've tried various solutions but they all depend on a callback to a some UI event or a periodic callback as in the code below.

import numpy as np
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Plot, LinearAxis, Grid
from bokeh.models.glyphs import MultiLine
from time import sleep
from random import randint


def getData():  # simulate data acquisition
    # run slow algorith
    sleep(randint(2,7)) #simulate slowness of algorithm
    return dict(xs=np.random.rand(50, 2).tolist(), ys=np.random.rand(50, 2).tolist())


# init plot
source = ColumnDataSource(data=getData())

plot = Plot(
    title=None, plot_width=600, plot_height=600,
    min_border=0, toolbar_location=None)

glyph = MultiLine(xs="xs", ys="ys", line_color="#8073ac", line_width=0.1)
plot.add_glyph(source, glyph)

xaxis = LinearAxis()
plot.add_layout(xaxis, 'below')

yaxis = LinearAxis()
plot.add_layout(yaxis, 'left')

plot.add_layout(Grid(dimension=0, ticker=xaxis.ticker))
plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))
curdoc().add_root(plot)


# update plot
def update():
    bokeh_source = getData()
    source.stream(bokeh_source, rollover=50)

curdoc().add_periodic_callback(update, 100)

This does seem to work, but is this the best way to go about things? Rather than having Bokeh try to update every 100 milliseconds can I just push new data to it when it becomes available?

Thanks


回答1:


You can use zmq and asyncio to do it. Here is the code for the bokeh server, it wait data in an async coroutine:

from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, curdoc
from functools import partial
from tornado.ioloop import IOLoop
import zmq.asyncio

doc = curdoc()

context = zmq.asyncio.Context.instance()
socket = context.socket(zmq.SUB)
socket.connect("tcp://127.0.0.1:1234")
socket.setsockopt(zmq.SUBSCRIBE, b"")

def update(new_data):
    source.stream(new_data, rollover=50)

async def loop():
    while True:
        new_data = await socket.recv_pyobj()
        doc.add_next_tick_callback(partial(update, new_data))

source = ColumnDataSource(data=dict(x=[0], y=[0]))

plot = figure(height=300)
plot.line(x='x', y='y', source=source)

doc.add_root(plot)
IOLoop.current().spawn_callback(loop)

to send the data just run following code in another python process:

import time
import random
import zmq

context = zmq.Context.instance()
pub_socket = context.socket(zmq.PUB)
pub_socket.bind("tcp://127.0.0.1:1234")

t = 0
y = 0

while True:
    time.sleep(1.0)
    t += 1
    y += random.normalvariate(0, 1)
    pub_socket.send_pyobj(dict(x=[t], y=[y]))


来源:https://stackoverflow.com/questions/56742575/can-i-update-a-bokeh-plot-without-callbacks-from-the-server

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!