No history yet

Architectural Internals

Bokeh's MVC Heartbeat

Bokeh's architecture is a clean implementation of the (MVC) pattern. This separation of concerns is fundamental to how it synchronizes a Python backend with a JavaScript frontend. The components map directly:

  • Model: Python objects that inherit from bokeh.model.Model. These are not data models in the ORM sense, but stateful representations of plot components like axes, glyphs, and tools. They hold all the properties and data.

  • View: The JavaScript counterpart in BokehJS. Each Python model has a corresponding BokehJS view responsible for rendering it to the browser's canvas or DOM. The view listens for changes on its model and updates the visual representation accordingly.

  • Controller: This role is fulfilled by your Python code and the Bokeh server. When you modify a model's property (e.g., p.title.text = "New Title"), you are acting as the controller, altering the model's state. The Bokeh server then communicates this state change to the view.

Lesson image

The Document as Unit of State

The fundamental unit of synchronization in Bokeh is the Document. A Document is a container for the complete collection of Bokeh models that constitute a single scene or application. Every plot, widget, and layout you create lives within a Document.

When a Bokeh application is running, the lifecycle is straightforward. Any change to any model within the Document—whether it's changing a plot's background color or updating a ColumnDataSource—marks the Document as "dirty." The Bokeh server then knows that this document's state has diverged from its counterpart in the browser and needs to be synchronized.

Think of the Document as the single source of truth for your visualization's state on the Python side. All serialization and synchronization operations happen at the document level.

The Bokeh Protocol and JSON

Synchronization between the Python Document and the BokehJS Document happens over a WebSocket connection using the Bokeh Protocol. This protocol's payload is —a carefully structured format that describes the models and their properties.

When a connection is first established, the entire Python Document is serialized into a large JSON blob and sent to the client. This initial payload contains all the information BokehJS needs to construct a parallel object graph of models and render the initial view.

After this initial setup, communication becomes much more efficient. Instead of resending the entire document on every change, Bokeh generates a JSON patch. This patch describes only what has changed—for example, "the text property of the Title model with ID '1002' changed from 'Old Title' to 'New Title'." BokehJS applies these small patches to its local Document, ensuring the view stays in sync with minimal overhead.

The Property System

The magic behind Bokeh's automatic synchronization lies in its powerful property system. Every attribute of a Bokeh model is not a standard Python attribute but a typed Property descriptor (e.g., Int, String, Float, Instance(Axis)).

This system serves two critical purposes:

  1. Validation: When you assign a value to a model property, the property descriptor validates the input. Assigning a string to an Int property will immediately raise a ValueError. This enforces model integrity and prevents invalid states from being sent to the frontend.

  2. Change Notification: When a property's value is successfully changed, the descriptor triggers a notification event. This event is what informs the Document that the model is now dirty and a patch needs to be generated for synchronization. The property system is the core mechanism that connects a simple attribute assignment in Python to the complex machinery of JSON patching and WebSocket communication.

The BokehJS Runtime

Finally, all of this culminates in BokehJS, the JavaScript runtime environment. It's a sophisticated client-side library built on Backbone.js. When BokehJS receives the initial JSON payload, it iterates through the model definitions and instantiates a parallel object graph of Backbone Models.

For each model, it also creates a corresponding Backbone View. The view's job is to render the model's state. For a Circle glyph, the view draws circles on an HTML5 Canvas. For a Slider widget, the view creates and manages the appropriate HTML input elements.

When a JSON patch arrives over the WebSocket, BokehJS finds the target model by its ID, updates its attributes, and Backbone's event system notifies the corresponding view. The view then re-renders itself, updating the visualization. This architecture ensures that Python developers can manipulate high-level objects without ever touching the low-level rendering code that runs in the browser.

Quiz Questions 1/5

In Bokeh's architecture, which component is responsible for rendering the visual representation of a model in the browser?

Quiz Questions 2/5

After the initial connection is established, how does a Bokeh server efficiently communicate subsequent changes to a plot to the browser?