Skip to main content

Variables and serialization

variables sends named Python values to the Observable notebook.

import observablejs as obs

notebook = obs.Notebook(
obs.ojs("md`threshold is ${threshold}`", key="readout"),
variables={"threshold": 0.75},
)

Variable names

Names must match ^[A-Za-z_$][0-9A-Za-z_$]*$. Observable runtime builtins such as Inputs, Plot, FileAttachment, width, and invalidation are reserved. Sources using the classic library also reserve names such as require. Invalid or reserved names raise ValueError.

Write variables

notebook.update_variables({"threshold": 0.8})
notebook.replace_variables({"rows": rows})
notebook.reset_variables("threshold")

update_variables(values, /) merges exactly one mapping. replace_variables(values, /) replaces the complete mapping sent from Python. reset_variables(*names) removes selected Python values so the notebook can define them again. Keyword updates, pair iterables, and None are invalid for update and replacement.

Sending the same serialized value does not emit a controller state event. It is also a browser no-op unless the browser has changed a shared input with that name. In that case, the update clears the browser-owned value and reapplies the Python value. A real change reaches every active view.

Read controller variables

Notebook.variables is the variable mapping from the latest NotebookState. It is detached from construction inputs and recursively read-only. After serialization, sequences are tuples, nested mappings are read-only, byte-like values are bytes, and DataFrame-like inputs are row records.

def on_state(change):
print(change["new"].variables)

notebook.observe(on_state, names="state")

Mutating the snapshot cannot update the notebook. Use the mutation methods for writes.

Python to browser conversion

Python inputBrowser value
None, bool, strnull, boolean, string
Safe int, finite floatnumber
Large intBigInt
NaN and infinitiesmatching JavaScript number
date, datetimeDate
bytes, bytearray, memoryviewUint8Array
Mappingplain object
Range, sequence, iterablearray
pandas or Polars DataFramearray of row objects
pandas or Polars Series, NumPy arrayarray

One-shot iterators materialize once. Unsupported values raise TypeError before state changes. Use file attachments for data that should load through FileAttachment.

Shared viewof inputs

When a Python variable and named viewof input use the same name, the initial Python value sets the control. Browser changes then update sibling views. A later Python update sets the value again in every view. Use the same input shape for a shared name across views. Values that exceed the serialization limits remain local to their view. File selections and DOM objects also remain local. Python readback captures file metadata.

Browser result conversion

Cell values in NotebookView.state decode into detached read-only mappings. Readback refreshes a cell's values when that cell reevaluates.

Browser valuePython result value
undefined, nullNone
Number, boolean, stringJSON-compatible scalar
BigIntint
Valid Datedatetime.datetime
Array, plain objecttuple or read-only mapping
Map, Settuple-based records
Array buffer or typed arraybytes
Error returned as dataBrowserErrorValue
DOM element, function, regular expressionstable summary string
File, Blobread-only metadata mapping

Readback values share a budget of 50,000 visited values and fields and 1 MB of conservatively estimated JSON content per view snapshot. Values deeper than 100 levels or larger than the remaining budget become one summary such as Array(31000) or String(1000000). Browser evaluation and rendering retain the complete native value. Select the cells whose values Python needs, or use capture_state=False for a view whose output stays in the browser.

Evaluation, rendering, and serialization failures appear in structured CellError records. See View state and graph.