Skip to main content

Observable JavaScript notebooks as reusable Python widgets

Project description

pyobservablejs

Observable JavaScript notebooks as Python widgets.

pyobservablejs renders Observable JavaScript cells from Python and runs them with Observable Notebook Kit in the browser. Python owns the notebook model, synced OJS variables, and cell widgets. TypeScript owns Notebook Kit evaluation, rendering, and runtime metadata.

import pyobservablejs as obs

rows = [
    {"letter": "A", "frequency": 0.0812},
    {"letter": "B", "frequency": 0.0149},
    {"letter": "C", "frequency": 0.0271},
    {"letter": "D", "frequency": 0.0432},
    {"letter": "E", "frequency": 0.1202},
]

obs.Notebook(
    obs.md("# Letter frequencies"),
    obs.ojs("""
    Plot.plot({
      height: 260,
      marginLeft: 48,
      y: {grid: true, label: "frequency"},
      marks: [
        Plot.ruleY([floor]),
        Plot.barY(rows, {x: "letter", y: "frequency", tip: true})
      ]
    })
    """),
    variables={"rows": rows, "floor": 0.04},
)

Install

pip install pyobservablejs

or:

uv add pyobservablejs

pyobservablejs supports Python 3.10 through 3.14.

Notebook Model

  • obs.Notebook(...) builds a Notebook Kit notebook from Python-authored cells.
  • variables={...} sets OJS variables. A matching notebook variable is overridden.
  • notebook.update_variables(...) pushes Python-side changes into the live OJS runtime.
  • name="..." gives Python a stable name for a cell.
  • notebook.values and notebook.cell("name").value read browser-synchronized outputs after rendering.
  • notebook.graph exposes Notebook Kit-derived cell definitions, references, and dependency edges.

Cell helpers keep the source mode explicit:

Helper Source mode
obs.ojs(...) Observable JavaScript
obs.js(...) ES module JavaScript
obs.md(...) Markdown
obs.html(...) HTML
notebook = obs.Notebook(
    obs.md("# Inputs"),
    obs.ojs('viewof gain = Inputs.range([0, 11], {value: 5})', name="gain"),
    obs.ojs("double = gain * 2", name="double"),
)

notebook.cell("gain")

After the notebook or cell widget has rendered in the browser, read the synced value from a later Python cell:

notebook.value("double")

Source Notebooks

Load Notebook Kit HTML from a string:

from pathlib import Path

path = Path("chart.html")
notebook = obs.Notebook.from_html(
    path.read_text(encoding="utf-8"),
    base_path=path.parent,
)

Local FileAttachment(...) references and relative JavaScript imports are embedded by default so the widget can move between notebook frontends.

Load a public ObservableHQ notebook by URL, slug, or id:

notebook = obs.Notebook.from_observablehq("https://observablehq.com/@mbostock/saving-svg")

Remote FileAttachment(...) entries are registered as URL-backed attachments, so Plot notebooks and examples with uploaded files can render in the widget. Pass variables={...} to override variables in a loaded notebook with Python values.

Documentation

Built On

Contributing

See CONTRIBUTING.md for local setup, workbench notebooks, and the check commands used before sending changes for review.

Acknowledgements

pyobservablejs builds on Observable Notebook Kit and @observablehq/runtime. pyobsplot informed the Python-to-OJS variable API.

Thanks to @manzt (Trevor Manz) for the composable anywidgets demo that helped shape the widget design.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyobservablejs-0.0.0rc1.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyobservablejs-0.0.0rc1-py3-none-any.whl (1.4 MB view details)

Uploaded Python 3

File details

Details for the file pyobservablejs-0.0.0rc1.tar.gz.

File metadata

  • Download URL: pyobservablejs-0.0.0rc1.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for pyobservablejs-0.0.0rc1.tar.gz
Algorithm Hash digest
SHA256 155b792a161ba62d12d313d160da7b172186b83a05787e01c7c3b020d70e31a2
MD5 6eaf4ad35f43fca866336108430ba537
BLAKE2b-256 ee7f11ddbdd46c020e0dfd8fcfd89ebae90c681a746c42135ec22f422918e0ad

See more details on using hashes here.

File details

Details for the file pyobservablejs-0.0.0rc1-py3-none-any.whl.

File metadata

File hashes

Hashes for pyobservablejs-0.0.0rc1-py3-none-any.whl
Algorithm Hash digest
SHA256 64ffa5bf88129abbf35a51d7e4a2b30eebad15c46138cf10d55428ab645bb5f6
MD5 f63c550c2bde60cd431a6d0629367973
BLAKE2b-256 8b776de82fa856823e75cdd499f2eec18e2abb8d3ec1c19b43c7aa04bc78082b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page