HTML export#

quantem.widget has three sharing paths:

  1. Widget-level HTML: widget.export_html(...) writes one standalone widget viewer. Use this when a single Show1D / Show2D / Show3D / Show3DSlices / Show4DSTEM / ShowEDS view is the artifact.

  2. Notebook-level HTML: quantem html notebook.ipynb --no-execute exports a whole notebook with its saved widget state. Use this for reports and tutorials that combine text, figures, and multiple widgets.

  3. GitHub preview notebook: quantem github notebook.ipynb --no-execute keeps a notebook readable on GitHub by replacing live widgets with compressed images of the widget UI.

This page defines the widget-level convention. It is intentionally a structural protocol, not a base class. Each widget keeps its own packing and performance logic, but the public shape is shared and easy for users, tests, and LLM agents to find.

Opening an exported widget on a phone or tablet: interactive widgets recompute with WebGPU, and browsers expose WebGPU only in a secure context (HTTPS or localhost). An exported HTML served over plain http://<ip>:<port> to a phone will render the first frame but ignore taps, because navigator.gpu is withheld over insecure origins. Serve it over HTTPS (for example tailscale serve --bg --https=443 http://127.0.0.1:<port>). Full explanation, browser flags, and a debugging page: see Viewing exported HTML on mobile.

Python contract#

Every export-capable widget should expose:

from pathlib import Path

path: Path = widget.export_html(
    path=None,          # str | pathlib.Path | None
    title=None,         # optional browser page title when supported
    mode="single",      # "single" or "folder"
    encoding="full",    # "full", "uint8", or widget-specific
    downsample=None,    # None, 2, 4, or widget-specific
)

The method returns the written pathlib.Path, creates parent directories, and updates widget.export_status with the filename, size, and selected export mode. The exported page must hydrate with the ipywidgets HTML manager and run without a live Python kernel. Browser-side changes in the HTML are local; they do not write back to the .ipynb or .html file.

For type hints or feature detection, use the structural protocol:

from quantem.widget import SupportsHtmlExport, supports_html_export

def maybe_export(widget: object) -> None:
    if supports_html_export(widget):
        widget.export_html("viewer.html")
class quantem.widget.export.SupportsHtmlExport(*args, **kwargs)#

Widget object with a Python API for standalone HTML export.

Implementations should write an HTML file that can hydrate the widget with the ipywidgets HTML manager and run without a live Python kernel. The preferred public options are mode for file layout, encoding for data storage, and downsample for shape reduction. Existing widget-specific names such as quantized, dtype, det_bin, and binning remain compatibility aliases.

export_html(path: str | Path | None = None, *, title: str | None = None, **options: Any) Path#

Write a standalone HTML artifact and return the written path.

class quantem.widget.export.SupportsFrontendHtmlExport(*args, **kwargs)#

Widget object with the standard in-widget HTML export bridge.

HTML export button#

Widgets that expose an in-widget Export button should use the same synced traits:

Trait

Direction

Purpose

export_enabled

Python -> JS

Show or disable the export UI

export_request

JS -> Python

JSON request: mode, request id, filename, download flag

export_status

Python -> JS

Human-readable progress, size, or error

export_payload

Python -> JS

HTML bytes when the browser initiated a download

export_payload_id

Python -> JS

Echoes the request id so JS downloads the right payload once

export_filename

Python -> JS

Suggested download filename

The standard request shape is:

{
  "mode": "single",
  "encoding": "full",
  "downsample": null,
  "id": "unique-request-id",
  "filename": "viewer.html",
  "download": true
}

For older widgets, legacy request modes such as exact, quantized, or uint8-bin2 may still be accepted. New code should use mode, encoding, and downsample. download=true means Python should build HTML bytes into export_payload; otherwise Python may write directly to disk by calling export_html(...).

Standard options#

Use the same three option names across widgets:

Option

Meaning

Preferred values

mode

where the data lives

single, folder

encoding

how the data is stored

full, uint8, widget-specific

downsample

whether dimensions are reduced before export

None, 2, 4, widget-specific

mode is packaging. It should not imply lower precision or a smaller shape. encoding is storage representation. It replaces vague API names like quantized. downsample is shape reduction. Each widget must document whether the reducer is mean, sum, min/max, or another operation, and the export UI must label the choice clearly enough that users know whether the file is browse-quality or count-preserving.

Widget capability table#

Widget

HTML export

Mode

Encoding

Downsample

Folder export

Reducer / notes

Show1D

yes

single

full

1, 2, 4, 8

no

preserves every trace/x sample; linked 2D snapshot and profile panels use a NaN-aware area mean, with pixel size and panel/profile coordinates rescaled

Show2D

yes

single

full, uint8

planned

no

uint8 stores display-scaled image data

Show3D

yes

single; large reviews use export_sidecar(...) folder output

full, uint8

planned

yes, via export_sidecar(...)

uint8 stores display-scaled volume data; folder output keeps the viewer HTML small and loads the stack from a nearby data file. See the advanced tutorial for the full-resolution folder workflow.

Show3DSlices

yes

single

full, uint8

planned

no

uint8 stores display-scaled volume data

Show4DSTEM

yes

single, folder when data already uses a companion folder

uint8, full

1, 2, 4, 8

sometimes

uint8 detector downsample uses mean for compact browse export; full/uint16 export should document whether downsample is count-preserving sum or display-stable mean

ShowEDS

yes

single, folder

full

2, 4

yes

count-preserving sum downsample across spatial and energy axes

The public Python calls are:

Widget

Python API

Show1D

export_html(path=None, title=None, mode="single", encoding="full", downsample=None)

Show2D

export_html(path=None, title=None, mode="single", encoding="full", downsample=None)

Show3D

export_html(path=None, title=None, mode="single", encoding="full", downsample=None); multi-GB folder reviews use export_sidecar(out_dir)

Show3DSlices

export_html(path=None, title=None, mode="single", encoding="full", downsample=None)

Show4DSTEM

export_html(path=None, title=None, mode="single", encoding="uint8", downsample=1)

ShowEDS

export_html(path=None, title=None, mode="single", encoding="full", downsample=None)

ShowFolder

export_html(path=None, title=None)

Existing compatibility aliases remain supported:

Old option

Preferred option

quantized=True

encoding="uint8"

dtype="uint8"

encoding="uint8"

dtype="uint16"

encoding="full"

det_bin=2

downsample=2

binning=4

downsample=4

mode="sidecar"

mode="folder"

Single and folder exports#

Use mode="single" when you want one HTML file. This is the default because it is easiest to email, upload, and move around.

Use mode="folder" when the HTML file should read exact data from a nearby data folder or URL. The HTML contains the viewer and startup state; the large dataset stays outside the HTML file.

Use mode="folder" when:

  • the exact dataset is too large to put inside one HTML file,

  • the audience is internal and can keep a folder next to the HTML,

  • preserving full data matters more than having one portable file.

Use mode="single" when:

  • you are sending one file by email or Slack,

  • the file will be posted as a simple web download,

  • the reader may move the HTML without its data folder.

Use downsample=2 or downsample=4 when you still want mode="single" but the exact dataset is too large. Downsampling makes a smaller one-file HTML export by combining nearby pixels, voxels, detector pixels, or energy channels. For lab sharing, mode="folder" is useful because it keeps exact data without making the HTML enormous.

Reducer choice is part of the scientific contract. Compact uint8 4D-STEM exports should avoid immediate clipping, so detector downsample may use a mean/average reducer and should be labeled as browse-quality. Count-preserving exports such as full/uint16 should preserve detector counts; if they downsample, sum is usually the scientifically expected reducer when the stored dtype can hold the result. If a widget chooses mean for a full export, the UI and docs must say so.

Notebook sharing#

HTML export and GitHub preview solve different problems:

Command

Output

Interactive

Use it for

normal .ipynb saved from Jupyter

notebook with widget state

yes, in Jupyter

continuing work

quantem html notebook.ipynb --no-execute

standalone HTML page

yes, in a browser

sharing an interactive report

quantem github notebook.ipynb --no-execute

optional notebook copy with compressed widget pictures

no

GitHub notebook preview

GitHub does not run widget JavaScript. Use the hosted documentation, Colab, Jupyter, or quantem html for real interaction. The quantem github command is only for a separate non-interactive notebook copy for GitHub’s native renderer; never run it in place on the canonical tutorial notebooks.

Implementation checklist#

For a new widget, copy the pattern from the closest existing widget:

  • Public export_html(...) -> pathlib.Path.

  • Private _default_html_export_path(...) with a readable slug, shape, and mode.

  • Private _write_html_export(...) using ipywidgets.embed.embed_minimal_html with dependency_state(..., drop_defaults=False).

  • Optional _html_export_bytes(...) for the browser download path.

  • Optional _clone_for_html_export(...) when the standalone artifact needs a packed/export-only widget state.

  • Standard HTML export button traits listed above.

  • Export status strings that include both file size and mode.

Do not force all widgets through one base class. The shared part is the public shape; the data packing must remain widget-specific so full, uint8, downsampled, and folder exports can be honest about precision, size, and performance.