How Bokeh Maintains Bidirectional Communication

The Bokeh visualization library achieves real-time, bidirectional synchronization between a Python environment and a client web browser primarily through the Bokeh Server architecture. By pairing a client-side JavaScript rendering engine (BokehJS) with a persistent Python backend over WebSockets, Bokeh continuously reflects Python data changes in the browser and transmits user-driven browser events back to Python callbacks.

The Client-Server Architecture

Bokeh splits the visualization workload between two environments:

  1. BokehJS (Client): A JavaScript library that runs inside the user's browser, responsible for rendering interactive canvas elements, handling UI events, and maintaining a local copy of visualization data.
  2. Bokeh Server (Backend): A Python process built on the Tornado web framework that executes application logic, computes data transformations, and processes interactions.

The Shared Document Model

At the heart of Bokeh's synchronization mechanism is the Document object. A Document acts as a central data structure containing all the components of a plot—such as axes, glyphs, layouts, and data sources—represented as declarative models.

Every model in Python has a precise counterpart in BokehJS. For example, a Python ColumnDataSource has an identical JavaScript ColumnDataSource model in BokehJS. When an application initializes, the server serializes the entire Document into a JSON representation and sends it to BokehJS, establishing identical state on both sides.

The WebSocket Protocol

Once the initial render occurs, Bokeh abandons standard stateless HTTP polling and establishes a persistent, full-duplex WebSocket connection between the browser and the Tornado server.

Bokeh employs a specialized protocol over this WebSocket connection that transmits lightweight differential updates (patches) rather than resending entire plots. This protocol supports both text (JSON) and binary formats, enabling low-overhead transfer of large numeric arrays (such as NumPy buffers) directly into JavaScript typed arrays.

Two-Way Event Synchronization

The WebSocket connection powers bidirectional data flow in two distinct directions:

1. Python to Browser Updates

When Python code modifies a property of a plot element—such as updating the coordinates in a ColumnDataSource or altering a title—the Python Document automatically captures the change.

2. Browser to Python Updates

When a user interacts with a visualization (e.g., dragging a slider, selecting points with a lasso tool, or clicking a button), BokehJS captures the UI event.

Through this persistent loop of synchronized Document models and minimal patch messaging over WebSockets, Bokeh maintains a responsive, low-latency bridge between Python computational power and interactive browser interfaces.