clerq.plot provides Plotly-based visualisation primitives for MBSolve and OBSolve results. Figures are interactive in the browser — hover to read values, drag to zoom, click the legend to toggle traces.
Installation
The plotting module requires the optional [plot] dependencies:
pip install clerq[plot]
or with uv:
uv pip install clerq[plot]
kaleido is included in [plot] and is required for static PNG export (fig.write_image()). If you only need interactive figures in a notebook you can install plotly alone.
Usage pattern
All plot functions take a solved MBSolve instance as their first argument and return a plotly.graph_objects.Figure. They never call .show() internally — that is always your call:
from clerq import plotfig = plot.field_spacetime(mbs) # returns a Figurefig.show(renderer='notebook_connected') # interactive in Jupyterfig.write_image('output.png') # static PNG via kaleido
Setup: solve a two-level absorber
We use a weak Gaussian probe propagating through a two-level absorber. This is enough to demonstrate every primitive.
Watch the pulse propagate through the medium. Each frame shows the field envelope \(|\Omega(z)|\) at a single instant. Use the slider to scrub to a specific time, or press ▶ Play to animate.
Computes the absorption spectrum via Fourier transform of the time-domain field at z_idx (default: exit face). This works in the linear (weak-field) regime; for strong fields the result is the nonlinear transmission, not the susceptibility.
Key options:
freq_range — clip the displayed frequency axis to |f| ≤ freq_range (γ), hiding the noisy high-frequency wings.
show_dispersion=True — add the dispersive component on a secondary axis.
freq_scale="arcsinh" — compress the frequency axis nonlinearly (linear near zero, log-like at large |f|) so narrow and broad features coexist. arcsinh_scale sets the width of the linear region in γ.
window — apply a SciPy window (e.g. "hann") to the time-domain field before the FFT to reduce spectral leakage from truncated free-induction decay.
# Narrow window around the resonance with dispersion on secondary axisfig = plot.spectrum(mbs, freq_range=3.0, show_dispersion=True)fig.show(renderer='notebook_connected')
# Arcsinh frequency scale (linear ±1 γ, log-like beyond) with Hann windowing# to reduce leakage from the free-induction decay tailfig = plot.spectrum(mbs, freq_scale="arcsinh", arcsinh_scale=1.0, window="hann")fig.show(renderer='notebook_connected')
population — state populations vs time
The diagonal elements \(\rho_{ii}(t)\) of the density matrix at a fixed z position. The probe drives population from |0⟩ to |1⟩ and back.
Plot \(|\rho_{01}(t)|\), \(\mathrm{Re}(\rho_{01})\), or \(\mathrm{Im}(\rho_{01})\) at a fixed z. The coherence is proportional to the macroscopic polarisation of the medium and drives the field evolution.