[Python] Bokeh server: plot shared data in several sessions

Discussão em 'Python' iniciado por Stack, Junho 20, 2025.

  1. Stack

    Stack Membro Participativo

    I am relatively new to bokeh, but very familiar with python.
    I want to use a Bokeh server to create a graphical live viewer for my data. I want to retrieve the data in a single thread and then pass them to all open documents / sessions.
    What would be a good solution to do so? Is there even a good solution?

    What I tried:


    My current approach was to start the thread as soon as the server is started, and inside that iterate over all sessions to update the plots, as soon as new data are available. It is working for one session, but as soon as I open another session, I start getting errors. Also, after loading the page there are only the initial data visible until new data arrive.

    # app_hooks.py
    import time
    import threading

    import bokeh.server.contexts
    from bokeh.plotting import Document
    from bokeh.models import ColumnDataSource

    keep_running = True
    data = { # some initial data
    'x': [1, 2, 3, 4, 5],
    'y': [6, 7, 2, 4, 7]
    }

    def callback(document: Document, new_data: dict):
    model = document.get_model_by_name("line")
    if model is None:
    print("Model not found in document")
    return
    assert isinstance(model, bokeh.models.renderers.glyph_renderer.GlyphRenderer)
    source: ColumnDataSource = model.data_source
    # source.stream(new_data, rollover=100)
    source.data = new_data

    def retrieve_data(i: int) -> dict[str, list[float]]:
    # idea: use a PUB/SUB pattern to retrieve data
    global data
    time.sleep(1) # it might take some time until new data is available. Can be seconds to hours.
    data['x'].append(i)
    data['y'].append(i * 0.5 % 5)
    return data

    def on_server_loaded(server_context: bokeh.server.contexts.BokehServerContext):
    # If present, this function executes when the server starts.
    def add_data_worker():
    global keep_running
    i=0
    while keep_running:
    print(f"Iteration {i + 1}")
    new_data = retrieve_data(i)
    for session in server_context.sessions:
    print(session.destroyed, session.expiration_requested)
    session.document.add_next_tick_callback(lambda: callback(session.document, new_data))
    i += 1

    thread = threading.Thread(target=add_data_worker, daemon=True)
    thread.start()

    def on_server_unloaded(server_context: bokeh.server.contexts.BokehServerContext):
    # If present, this function executes when the server shuts down.
    global keep_running
    keep_running = False


    # main.py
    from bokeh.plotting import figure, curdoc
    from bokeh.models import ColumnDataSource
    from .app_hooks import data

    source = ColumnDataSource(data=data)

    p = figure(title="Simple Line Example", x_axis_label='x', y_axis_label='y')
    p.line(x="x", y="y", legend_label="My Value", line_width=2, source=source, name="line")

    curdoc().add_root(p)

    Other ideas I had:

    • If I use a publish/subscribe pattern anyway I could create one subscriber and update-thread per session. But for me it feels better to have them centralized.
    • Let each session poll the data from another server. I would do so by using curdoc().add_periodic_callback(callback, 1000) and inside that callback sending a HTTP-request which gives me the current data. But I want to avoid polling and I want to minimize the delay when new data are available. So I would have to poll very often.

    Are there other ideas? Are there best practices for similar problems? Do I even choose a good library for that?

    Continue reading...

Compartilhe esta Página