bokeh/bokeh
Interactive Data Visualization in the browser, from Python
10 hidden assumptions · 7-stage pipeline · 7 components
Like any codebase, this library makes assumptions it never checks — most are routine. The ones worth your attention are below.
Generates interactive browser visualizations from Python using dual-runtime architecture
Data starts in Python as pandas DataFrames or dicts, gets serialized to JSON with binary buffers for large arrays, transmitted to browser where it's reconstructed as typed arrays. GlyphViews read these arrays, apply coordinate transformations through Scale objects, and render visual marks to HTML5 canvas. User interactions trigger hit tests that update Selection objects, which propagate back through the system to highlight related data points.
Under the hood, the system uses 3 feedback loops, 3 data pools, 3 control points to manage its runtime behavior.
A 7-component library. 2212 files analyzed. Data flows through 7 distinct pipeline stages.
Hidden Assumptions
Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".
If a data source contains a column with incompatible data (like objects that Array.from() creates weird arrays from), get_array returns T[] but with wrong element types, causing type-unsafe operations downstream in GlyphView rendering
If hit testing occurs before rendering completes, accessing this.index throws 'index_data() wasn't called', breaking selection and interaction features silently until user clicks
If multiple bokeh plots try to use different WebGL contexts, they share the same ReglWrapper instance tied to the first context, causing rendering artifacts or crashes when switching between plots
Show everything (7 more)
WebGL extensions ['ANGLE_instanced_arrays', 'EXT_blend_minmax', 'OES_element_index_uint'] will be available in the browser context, but only checks if WebGL context creation succeeds
If this fails: If any required extension is missing, regl initialization may fail or glyphs render incorrectly without clear error messages, causing fallback to Canvas2D without user awareness
bokehjs/src/lib/models/glyphs/webgl/regl_wrap.ts:constructor
Factor arrays will contain reasonable numbers of unique string values (hundreds, not millions), but no bounds checking exists on the factors parameter length
If this fails: With millions of categorical factors, the mapping creation becomes O(n²) in memory and extremely slow, potentially causing browser tabs to hang or crash during coordinate transformation
bokehjs/src/lib/models/ranges/factor_range.ts:map_one_level
Source files on disk won't change between dependency resolution and compilation phases, but no file locking or timestamp validation occurs
If this fails: If files are modified during the build process (common in watch mode), the compiler may use stale dependency graphs with fresh file contents, producing inconsistent builds or missing imports
bokehjs/src/compiler/build.ts:compiler host and file system operations
The SelectionManager will coordinate with GlyphRenderer views that have been properly initialized and connected through signals, but no validation ensures the renderer-datasource binding
If this fails: If a GlyphRenderer is created but not properly connected to its data source's selection signals, selection highlighting breaks—users can select points but visual feedback disappears, making multi-plot dashboards unusable
bokehjs/src/lib/models/sources/columnar_data_source.ts:selection_manager
connect_signals() will be called after constructor but before any property changes or event callbacks are triggered, following a strict initialization order
If this fails: If properties are modified before connect_signals() runs, the _update_property_callbacks() won't be set up, causing js_property_callbacks to silently fail and custom JavaScript event handlers to never execute
bokehjs/src/lib/model.ts:connect_signals lifecycle
Factor tuples will consistently have the same nesting level throughout a single dataset (all L1Factor, all L2Factor, or all L3Factor), but no runtime validation enforces homogeneity
If this fails: Mixing factor levels like [['A'], ['B', 'C']] causes coordinate mapping to fail unpredictably—some categorical points render in wrong positions or disappear entirely from plots
bokehjs/src/lib/models/ranges/factor_range.ts:FactorSeq type system
Input JSON from stdin or argv.file will conform to the expected schema with 'code', 'lang', 'file', and 'bokehjs_dir' fields, but only validates file existence not content structure
If this fails: Malformed compilation requests cause JSON.parse() to throw or compile_and_resolve_deps() to fail with cryptic errors, breaking bokeh server's dynamic extension loading without clear error messages
bokehjs/src/compiler/main.ts:compile function
Open the standalone hidden-assumptions report for bokeh →
How Data Flows Through the System
Data starts in Python as pandas DataFrames or dicts, gets serialized to JSON with binary buffers for large arrays, transmitted to browser where it's reconstructed as typed arrays. GlyphViews read these arrays, apply coordinate transformations through Scale objects, and render visual marks to HTML5 canvas. User interactions trigger hit tests that update Selection objects, which propagate back through the system to highlight related data points.
- Python model creation — User creates plots in Python using bokeh.plotting API, defining data sources, glyphs, layouts, and styling that get registered as Model instances with property validation
- JSON serialization — Python models serialize to JSON using bokeh.core.serialization.Serialized, with large arrays extracted to binary buffers to avoid JSON parsing overhead [Python Model objects → Serialized]
- Browser transmission — JSON model definition gets embedded in HTML template or transmitted over WebSocket connection to Bokeh server, binary buffers sent as separate ArrayBuffer messages [Serialized → Raw JSON + buffers]
- JavaScript model reconstruction — Browser reconstructs JavaScript Model instances from JSON using HasProps property system, binary buffers become typed arrays (Float32Array, Int32Array) for efficient processing [Raw JSON + buffers → ColumnarDataSource]
- Coordinate transformation — GlyphView.compute_layout transforms data coordinates to screen pixels using Scale objects (LinearScale, LogScale, FactorRange), handling categorical and continuous axes [ColumnarDataSource → Screen coordinates]
- Canvas rendering — GlyphView.render draws visual marks to HTML5 Canvas2D context or WebGL through ReglWrapper, batching operations for performance with large datasets [Screen coordinates → Rendered pixels]
- Interaction handling — User clicks/hovers trigger GlyphView.hit_test which uses spatial indexing to find data points under cursor, updates Selection objects with indices of selected items [Mouse events → Selection]
Data Models
The data structures that flow between stages — the contracts that hold the system together.
bokehjs/src/lib/models/sources/columnar_data_source.tsDict with column names mapping to Arrayable<T> (typed arrays or regular arrays), plus selection state and default_values
Created from Python pandas DataFrame or dict, transmitted as JSON, reconstructed as JavaScript object with typed arrays for efficient rendering
bokehjs/src/lib/models/glyphs/glyph.tsDOM component with visuals properties, spatial index, data arrays, and optional WebGL renderer
Instantiated from JSON model, computes screen coordinates from data coordinates, renders to canvas on each frame, handles mouse/touch events
bokehjs/src/lib/models/selections/selection.tsObject with indices: OpaqueIndices, line_indices: OpaqueIndices, multiline_indices: MultiIndices, image_indices: ImageIndices arrays
Created empty, populated during hit testing, transmitted between client/server for linked selections, merged using set operations
src/bokeh/core/serialization.pyDataclass with content: T and buffers: list[Buffer] for binary data
Python models serialize to JSON with optional binary buffers for large arrays, transmitted over WebSocket or embedded in HTML, deserialized to reconstruct JavaScript models
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Column-oriented data storage using typed arrays (Float32Array, Int32Array) for efficient bulk operations and WebGL compatibility
R-tree spatial index built during rendering to accelerate hit testing and selection operations on large datasets
GPU memory buffers that cache vertex data and shader programs for high-performance rendering of scatter plots and lines
Feedback Loops
- Selection propagation (self-correction, balancing) — Trigger: User interaction with glyph. Action: Hit test updates Selection, triggers SelectionManager.update, notifies all connected GlyphViews to re-render with selection highlighting. Exit: Selection state stabilizes across all views.
- Property change cascade (self-correction, balancing) — Trigger: Model property modification. Action: HasProps.change signal triggers dependent property updates, view re-renders, and optional server synchronization. Exit: All dependent views reflect new property values.
- Build compilation loop (compilation, balancing) — Trigger: Source file change detection. Action: TypeScript compiler rebuilds changed modules, updates dependency graph, relinks affected bundles. Exit: All modules successfully compiled or build fails.
Delays
- TypeScript compilation (compilation, ~seconds to minutes) — Full system rebuild required when changing core interfaces, delays development feedback loop
- Initial render delay (warmup, ~milliseconds) — First draw requires spatial index construction and coordinate transformation, subsequent renders use cached computations
- WebGL context setup (warmup, ~milliseconds) — GPU rendering initialization compiles shaders and allocates buffers before first accelerated draw
Control Points
- WebGL availability check (runtime-toggle) — Controls: Whether to use GPU acceleration or fall back to Canvas2D rendering. Default: _compute_can_use_webgl()
- Build system verbosity (env-var) — Controls: Amount of compilation logging and progress reporting during development. Default: argv.verbose
- Selection policy strategy (architecture-switch) — Controls: How multiple selections combine (union, intersection, replace) across linked visualizations. Default: UnionRenderers
Technology Stack
Primary language for browser-side rendering engine and interaction handling
High-level API for plot construction and data binding, server runtime
2D graphics rendering target for all visualizations
GPU-accelerated rendering for large datasets through shader-based pipeline
WebSocket server for live data updates and bidirectional communication
Efficient array operations and data type handling in Python layer
TypeScript compilation, bundling, and development workflow automation
Key Components
- GlyphView (renderer) — Base class that renders data points as visual marks on canvas, handles coordinate transformations, selection, and optional WebGL acceleration
bokehjs/src/lib/models/glyphs/glyph.ts - ColumnarDataSource (store) — Holds tabular data as column arrays, manages selection state, and notifies views when data changes through signals
bokehjs/src/lib/models/sources/columnar_data_source.ts - SelectionManager (orchestrator) — Coordinates selection state across multiple renderers, applies selection policies (union/intersection), and manages cross-filtering
bokehjs/src/lib/models/sources/columnar_data_source.ts - ReglWrapper (adapter) — Wraps the Regl WebGL library to provide high-performance GPU rendering for large datasets, manages shaders and buffers
bokehjs/src/lib/models/glyphs/webgl/regl_wrap.ts - Compiler build system (processor) — Compiles TypeScript source code and CSS into JavaScript bundles, handles module linking and asset processing
bokehjs/src/compiler/build.ts - Factor range coordinate system (transformer) — Converts categorical data (strings, tuples) into numeric screen coordinates with automatic spacing and padding
bokehjs/src/lib/models/ranges/factor_range.ts - Model base class (registry) — Base class for all Bokeh objects, provides property system, change notifications, event handling, and JSON serialization
bokehjs/src/lib/model.ts
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated Library Repositories
Frequently Asked Questions
What is bokeh used for?
Generates interactive browser visualizations from Python using dual-runtime architecture bokeh/bokeh is a 7-component library written in TypeScript. Data flows through 7 distinct pipeline stages. The codebase contains 2212 files.
How is bokeh architected?
bokeh is organized into 4 architecture layers: Python API Layer, Serialization Bridge, TypeScript Compiler System, Browser Rendering Engine. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.
How does data flow through bokeh?
Data moves through 7 stages: Python model creation → JSON serialization → Browser transmission → JavaScript model reconstruction → Coordinate transformation → .... Data starts in Python as pandas DataFrames or dicts, gets serialized to JSON with binary buffers for large arrays, transmitted to browser where it's reconstructed as typed arrays. GlyphViews read these arrays, apply coordinate transformations through Scale objects, and render visual marks to HTML5 canvas. User interactions trigger hit tests that update Selection objects, which propagate back through the system to highlight related data points. This pipeline design reflects a complex multi-stage processing system.
What technologies does bokeh use?
The core stack includes TypeScript (Primary language for browser-side rendering engine and interaction handling), Python (High-level API for plot construction and data binding, server runtime), HTML5 Canvas (2D graphics rendering target for all visualizations), WebGL/Regl (GPU-accelerated rendering for large datasets through shader-based pipeline), Tornado (WebSocket server for live data updates and bidirectional communication), NumPy (Efficient array operations and data type handling in Python layer), and 1 more. A focused set of dependencies that keeps the build manageable.
What system dynamics does bokeh have?
bokeh exhibits 3 data pools (Data column arrays, Spatial index), 3 feedback loops, 3 control points, 3 delays. The feedback loops handle self-correction and self-correction. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does bokeh use?
4 design patterns detected: Dual-runtime architecture, Property-driven reactive system, Pluggable rendering backends, Spatial indexing for interactions.
Analyzed on April 20, 2026 by CodeSea. Written by Karolina Sarna.