.md →
ObservablePlot API#
Bases: AnyWidget
Run Observable Plot <https://observablehq.com/plot/>_ code in a notebook.
Observable Plot is a JavaScript charting library. This widget is a thin
runner: it loads Plot (and d3) from a CDN, then evaluates a blob of
JavaScript you supply (the code traitlet) exactly as you would write it
in an Observable notebook — a bare Plot.plot({...}) expression that
returns a DOM node. The returned node is mounted inline; Python's job is to
hand over the source, the data, and the sizing.
Python values are injected into the code's scope by name via variables:
each key becomes an in-scope JavaScript variable holding the (JSON-ified)
value. So variables={"vacancies": df} lets your code reference
vacancies directly::
Plot.plot({
marks: [
Plot.barY(vacancies, { x: "month", y: "vacancies" }),
Plot.ruleY([0]),
],
})
Plot and d3 are always in scope, along with container (the
target DOM element), the width / height ints, and the widget
model. Pandas / polars DataFrames and numpy arrays in variables are
converted to plain JSON structures (records / lists) before syncing.
The code is evaluated verbatim in the browser, so only pass JavaScript you trust (typically your own).
Reassigning code, variables, width, height, or version
re-runs the code and rebuilds the chart. Observable Plot has no incremental
redraw — each run produces a fresh SVG — but the new node is swapped in
atomically (the previous chart stays put until it is ready), so updates
driven by e.g. a slider do not flash a blank frame.
Examples:
import marimo as mo
import pandas as pd
from wigglystuff import ObservablePlot
df = pd.DataFrame({"month": ["Jan", "Feb", "Mar"], "vacancies": [3, 5, 2]})
code = '''
Plot.plot({
marks: [
Plot.barY(vacancies, { x: "month", y: "vacancies" }),
Plot.ruleY([0]),
],
})
'''
mo.ui.anywidget(ObservablePlot(code, variables={"vacancies": df}))
Point at a local file or a URL instead of an inline string — the first argument accepts any of the three forms:
ObservablePlot("charts/bars.js", variables={"vacancies": df})
ObservablePlot("https://example.com/chart.js")
Create an ObservablePlot widget.
The plot source is resolved in Python, so the browser always receives
plain JavaScript. code (or src) may be any of:
- an inline JavaScript string,
- a path to a local
.jsfile, or - an
http(s)://URL.
URLs and file paths are fetched/read here at construction time; the
detection is by value, so ObservablePlot("https://.../chart.js") and
ObservablePlot("Plot.plot({...})") both do the right thing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
Optional[str]
|
Inline JavaScript, a local file path, or an |
None
|
src
|
Optional[str]
|
An explicit alias for |
None
|
variables
|
Optional[Dict[str, Any]]
|
Mapping of name -> value injected into the code's scope as JavaScript variables. DataFrames and numpy arrays are converted to JSON-serializable structures. |
None
|
width
|
int
|
Container width in pixels. |
500
|
height
|
int
|
Container height in pixels. |
300
|
version
|
str
|
The |
'latest'
|
**kwargs
|
Any
|
Forwarded to |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If neither or both of |
Source code in wigglystuff/observable_plot.py
Synced traitlets#
| Traitlet | Type | Notes |
|---|---|---|
code |
str |
Resolved Observable Plot JavaScript (inline JS, or the contents of a file / URL, fetched in Python), evaluated as an expression that returns the DOM node to mount. |
variables |
dict |
Name → value mapping injected into the code's scope as JavaScript variables. DataFrames and numpy arrays are converted to JSON records/lists on assignment. |
width |
int |
Container width in pixels. |
height |
int |
Container height in pixels. |
version |
str |
@observablehq/plot version loaded from the CDN (defaults to "latest"). |
error |
str |
Read-back of the latest JS runtime / CDN-load error, or "". |