API reference¶
Auto-generated from the public qtviz namespace (everything in qtviz.__all__).
Describe a plot once as immutable data (an Element), compose with *
(overlay) and + (layout), then render through any backend — pyqtgraph,
matplotlib, or webengine — swappable at runtime. qv.show(...) is the script
one-liner; qv.View is the plain QWidget for applications.
qtviz.__version__ reports the installed version.
Elements¶
qtviz.Scatter ¶
Bases: NormedRaster, Element
A point cloud — x/y positions with optional color/size encoding.
norm/clim engage the shared colormap-normalization surface on the
color_by mapping — the same vocabulary Image/Heatmap/Mesh use.
legend_entry ¶
legend_entry(theme, index: int = 0)
A color_by Scatter already emits its own categorical/continuous
Legend from the color mapping — contributing a swatch entry too would
double-legend ([D60] risk #3), so it opts out of the contract.
select_xy ¶
select_xy()
Brush/pick registration coordinates — replaces the isinstance tuples in backend event wiring.
channels ¶
channels() -> dict
x/y always; color/size roles when bound to a data column, so the
resolve pipeline materializes them for the native renderers.
qtviz.Curve ¶
Bases: Element
A connected line through ordered x/y points; optionally stepped
(step=) and/or with point markers (marker=); axis="y2"
puts it on the twin right-hand axis.
qtviz.Bars ¶
Bases: Element
Bars — x categories (or numeric positions) with y heights. With
by= each distinct group value becomes its own palette-colored series,
laid out side-by-side (mode="grouped") or cumulatively ("stacked");
mode is meaningful only with by.
annotate= is the [D131] union: True labels each bar with its value
("auto" → %g), a str is a [D86] format spec for that value, and a
non-str accessor (col() expression, callable, or raw array) labels
each bar from the data instead ([D136] accessor arm) — the one place the
accessor union's plain-string form is taken by the format spec, so a
column label is spelled annotate=col("name").
annotate_by
property
¶
annotate_by: Accessor | None
The [D136] accessor arm of annotate= — None when annotate is
off or a format spec (the fmt arm stays on .annotate as a str).
channels ¶
channels() -> dict
x/y always; the by role when set, so the resolve pipeline
materializes the category column for the renderers (same pattern as
Scatter's color_by).
legend_entry ¶
legend_entry(theme, index: int = 0)
A color_by Bars emits its own key ([D60] risk #3 rule).
qtviz.Histogram ¶
Bases: Element
Binned frequency of a single raw value column. bins is a count or one of
numpy's rule names ("auto", "fd", "sturges", …); the binning is
computed once in core so every backend draws the same bars.
qtviz.Image ¶
Bases: NormedRaster, Element
A 2-D array drawn as an image over explicit extent (also hosts RGBA
rasters). norm/vmin/vmax/gamma engage the color surface —
normalized once in core, colorbar/limits appear only when used.
resolved_grid ¶
resolved_grid()
The one gridded accessor: the resolved GridData — replaces
scattered element.data.grid() reach-through in the backends.
qtviz.Heatmap ¶
Bases: NormedRaster, Element
A grid of tidy x/y cells shaded by a z value. Duplicate rows landing on
one cell reduce through aggregator (the pre-0.4 implicit behavior
was "last", kept in the vocabulary).
annotate= writes each aggregated value at its cell center —
"auto" for %g, or any format spec (".1f", "{:.0%}", …). The
text color is computed in core per cell (WCAG luminance of the cell's ramp
color → theme foreground or background), and grids above ~400 cells warn
and skip labels rather than smear unreadable text.
resolved_cell_labels ¶
resolved_cell_labels(xs, ys, grid, theme)
The core-computed labels for an already-pivoted grid, or
[] when the option is off — one call site per backend renderer.
qtviz.ErrorBars ¶
Bases: Element
Error bars around y — err is symmetric, or (lo, hi) for asymmetric.
lo_limit= / hi_limit= name optional boolean columns; where
true, that side's cap is drawn as an outward arrowhead — "the true value
lies beyond" (mpl's lolims/uplims semantic). Heads reuse the shared
quiver construction and refer to the direction axis, so limits are
per-axis (direction="both" rejects them — use two elements).
resolved_limits ¶
resolved_limits()
(err_lo, err_hi, arrows) from the resolved channels:
limited sides are zeroed (the arrow shaft replaces the bar) and
arrows is the core (shaft, head) polyline pair — None when no
limit columns are set, so plain error bars render exactly as before.
qtviz.Spread ¶
Bases: Element
A filled band between lo and hi. Exactly one of x/y positions
it: x= runs the band in y over x positions (the confidence-interval
case); y= runs it in x over y positions. lo/hi always name
the band edges.
qtviz.BoxPlot ¶
Bases: _Distribution
A five-number-summary box (median, quartiles, 1.5·IQR whiskers clipped to
the data, outlier points) of value — one box, or one per by category.
qtviz.Violin ¶
Bases: _Distribution
A kernel-density silhouette of value (Gaussian KDE, Scott's rule) —
one violin, or one per by category.
qtviz.Area ¶
Bases: Element
A series filled to the zero baseline. With by= each distinct group
value becomes its own palette-colored band — layered translucently
(mode="overlay") or cumulatively stacked ("stacked") — the shared
grouping pattern, so stacking stays inside one element. Grouped data pivots
on unique x (duplicate rows in a group sum, like Bars).
qtviz.Ecdf ¶
Bases: Element
The empirical cumulative distribution of a raw value column — a step curve
rising 0→1. The statistic is computed in core (_stats.ecdf, the house
rule: qtviz decides the numbers) and drawn through each backend's
post-step curve path.
qtviz.Pie ¶
Bases: Element
Proportional wedges of a non-negative value column, optionally
labeled by a by category column; hole (0 ≤ hole < 1) makes a donut. Slice
colors cycle the theme palette in row order.
Supported on matplotlib and webengine; pyqtgraph has no pie
primitive, so negotiation routes around it (the RawFigure precedent —
an element need not render everywhere).
qtviz.Contour ¶
Bases: Element
Iso-value contours of a 2-D array over explicit extent (the Image
data contract). levels is a count (uniform interior levels, computed once
in core so every backend draws the same lines — ) or an explicit
sequence of values. filled=True shades between levels; pyqtgraph draws
lines only and warns on filled (capability-honest).
annotate= writes each level's value inline on its longest
iso-line — True for %g, or any format spec. Placement (marching
squares → arc-length midpoint, tangent angle normalized upright, and a
background mask segment that breaks the line) is computed once in core,
so every backend places identical labels — deliberately not mpl's
native clabel (over engine fidelity).
qtviz.Mesh ¶
Bases: NormedRaster, Element
A 2-D value grid over explicit cell edges: values[j, i] fills the
cell x[i]..x[i+1] × y[j]..y[j+1] — edges are the
canonical contract (Heatmap owns the centers convention; Image the
uniform-bounds one). Non-uniform spacing is the point: log-spaced
frequency rows, irregular time bins. Shares the norm surface.
qtviz.Quiver ¶
Bases: Element
arrows at (x, y) with components (u, v).
arrow_scale converts (u, v) units to data-space arrow length
("auto" sizes the largest arrow to ~90% of the field's typical cell);
head_scale scales the barbs. Geometry is computed once in core
so every backend draws the identical field.
key= adds a reference key — a legend entry whose sample glyph
is an arrow built by the same core construction as the field, labeled
with the stated magnitude (key_label, e.g. key=10,
key_label="10 m/s", or the bare number). Legend-based deliberately:
qtviz does not model axes-fraction chrome, and the legend is where
readers look for what a mark means.
legend_entry ¶
legend_entry(theme, index: int = 0)
With key= set, the entry is the reference key: an arrow
sample glyph plus a label stating the magnitude (key_label or the
number). An element label folds in as "label (key)". Without a
key this behaves like any labeled element.
lower ¶
lower(ctx)
The whole cross-backend implementation: two NaN-separated
polylines from the geometry, style resolved into one Stroke,
legend routed through legend_entry() — every backend draws these
marks through its _marks adapter.
qtviz.Stem ¶
Bases: Element
A stem (lollipop) series: a vertical line from baseline to each
(x, y), capped by a marker head. The segment geometry is computed once
in core (_geometry.stem_segments, ) and drawn as ONE
pair-connected polyline plus a marker layer per backend — never an item
per stem. Heads pick/hover like Scatter points; the element takes a
palette slot and contributes a legend entry like any series.
lower ¶
lower(ctx)
ONE pair-connected polyline for every stalk (never an item per stem) + a pickable marker layer for the heads.
qtviz.Streamlines ¶
Bases: Element
Streamlines of a vector field: u/v are accessors resolving to 2-D
arrays on the Image/Contour grid contract, placed in data space by extent —
deliberately grids, not per-point columns, because field topology needs
the grid. The integrator runs once in core (_streamlines): seeds on a
coarse mask grid (30×30 · density), RK4 both directions with bilinear
interpolation, termination on domain exit / stagnation / an occupied
mask cell — the mask enforces line spacing. Every backend draws the
resulting polylines + one mid-line arrowhead each as two cheap
NaN-separated curves.
Recorded v1 scope cuts: no color_by=speed gradient lines (pg cannot
draw gradient polylines — the same honesty tier as Curve(color_by=);
revisit together), no varying line width, no start-point control.
qtviz.Inset ¶
Bases: Element
indicator_window ¶
indicator_window()
The child's declared x/y window ((x0, x1), (y0, y1)), or
None when either lim is unset. [D154] I4b: an undeclared window is
no longer a warn-skip — the backend seeds the rectangle from the
inset's rendered (autoranged) window instead, and the live
InsetIndicator controller tracks it from there.
indicator_rect
staticmethod
¶
indicator_rect(window)
The parent-side Rect marking window ([D154]) — the wave-1
annotation, so it lowers everywhere with zero new drawing code.
qtviz.RawFigure ¶
Bases: Element
Host an existing Plotly / Bokeh / HoloViews figure unchanged (webengine only).
Sizing follows the figure's own configuration — a passthrough never
mutates your figure. Plotly figures track the widget automatically
(responsive config + a Qt-side resize nudge); a Bokeh figure keeps its
declared size, so pass sizing_mode="stretch_both" when you want it to
fill the widget.
Polar ([D119])¶
qtviz.PolarGrid ¶
Bases: Element
Circular grid chrome ([D70]-class): rings concentric circles out to
r_max, spokes radial lines, degree labels (or custom theta_labels —
the radar case) and radius labels. Chrome, not data: it binds nothing,
draws in the theme foreground, and contributes no legend entry.
lower ¶
lower(ctx)
Rings as ONE NaN-separated PolygonMark, spokes as ONE
pair-connected Polyline, labels as TextMarks.
qtviz.polar ¶
Polar plotting ([D119] Option B — design/spikes/polar-spike-report.md).
Polar is a transform, not a projection: polar() rebinds a tabular
element's x/y through (θ, r) → (r·cosθ, r·sinθ) before the data seam,
PolarGrid draws the circular chrome (rings/spokes/labels) from marks —
one lower(), zero backend edits — and wedge() builds annulus-sector
points for Polygon polar bars. The surface stays rectilinear (pair with
.opts(aspect=1, grid=False) and AxisSpec(ticks=())), so R1, events,
brushes, ViewState, and backend switching are untouched by design.
The recorded costs of that choice (hover reads x/y, no r-zoom semantics)
live in the spike report.
PolarGrid ¶
Bases: Element
Circular grid chrome ([D70]-class): rings concentric circles out to
r_max, spokes radial lines, degree labels (or custom theta_labels —
the radar case) and radius labels. Chrome, not data: it binds nothing,
draws in the theme foreground, and contributes no legend entry.
lower ¶
lower(ctx)
Rings as ONE NaN-separated PolygonMark, spokes as ONE
pair-connected Polyline, labels as TextMarks.
polar ¶
polar(element, *, theta: Accessor | None = None, r: Accessor | None = None)
Reinterpret a tabular element's position channels as polar
([D119] Option B): x becomes θ (radians, CCW from +x) and y becomes
r unless theta=/r= name other bindings; the returned copy plots
(r·cosθ, r·sinθ). Column-name / col() bindings compose into a
serializable Expression (lazy-capable, value-equal); a callable or
raw-array binding falls back to a callable pair ([D14] escape-hatch
semantics). Pair with PolarGrid and .opts(aspect=1).
wedge ¶
wedge(theta0: float, theta1: float, r0: float = 0.0, r1: float = 1.0, *, steps: int = 16) -> tuple[tuple[float, float], ...]
Annulus-sector outline points — the polar bar, ready for
Polygon(wedge(...), fill=True): outer arc θ0→θ1 at r1, inner arc
back at r0 (a point when r0 == 0).
qtviz.wedge ¶
wedge(theta0: float, theta1: float, r0: float = 0.0, r1: float = 1.0, *, steps: int = 16) -> tuple[tuple[float, float], ...]
Annulus-sector outline points — the polar bar, ready for
Polygon(wedge(...), fill=True): outer arc θ0→θ1 at r1, inner arc
back at r0 (a point when r0 == 0).
Annotation & reference elements¶
qtviz.HLine ¶
Bases: _Reference
A horizontal reference line at y, spanning the full x extent.
qtviz.VLine ¶
Bases: _Reference
A vertical reference line at x, spanning the full y extent.
qtviz.Span ¶
Bases: _Reference
A filled reference band from lo to hi — horizontal
(orient="horizontal", a y-range across the full width) or vertical
(orient="vertical", an x-range).
qtviz.Text ¶
Bases: _Reference
A text note anchored at data coordinates (x, y); rotation is
counter-clockwise degrees, halign/valign place the box relative to
the point, and frame=True draws a theme-styled box behind it.
qtviz.Arrow ¶
Bases: _Reference
An arrow between two data points, head at the end point (head="end",
or "both"/"none") — the pointing half of annotate; pair with
a Text for a callout.
qtviz.Rect ¶
Bases: _Shape
An axis-aligned rectangle from (x0, y0) to (x1, y1).
qtviz.Ellipse ¶
Bases: _Shape
An ellipse centered at (cx, cy) with radii rx/ry, rotated by
angle degrees (counter-clockwise, about the center).
qtviz.Polygon ¶
Bases: _Shape
A closed polygon through literal points (≥ 3 (x, y) pairs).
qtviz.RefLine ¶
Bases: _Reference
An infinite reference line y = slope·x + intercept (the
axline analog; HLine/VLine cover the axis-parallel cases). A
straight data-space line isn't straight under log scales, so it
warns-and-drops there.
Composition & View¶
Element is the base class of every element above — the type to use in your
own annotations (def render(el: qv.Element) -> None). Node is the
Element | Overlay | Layout union that View and show accept.
qtviz.Element ¶
Bases: Immutable
channels ¶
channels() -> dict
{role: accessor} — what the resolve pipeline materializes into
role-keyed arrays. Override for non-uniform shapes (e.g. ErrorBars).
legend_entry ¶
legend_entry(theme, index: int = 0)
This element's contribution to a multi-series legend ([D60]): its
label + swatch, or None when it shouldn't contribute (no label, or —
per override — it already emits its own Legend, like a color_by
Scatter). index is the element's position in its Overlay, which decides
the default palette slot exactly as the renderers do.
lower ¶
lower(ctx)
This element's Mark lowering ([D122]) — Lowered | None. None
(the default) means the element does not lower: every backend must
register a native renderer for it, and type(el).lower is not
Element.lower is the dispatch predicate backends use. Overrides run
on resolved data and must be pure: marks in linear data space
([D121]), style resolved through ctx. A registered native renderer
wins over lowering (the fast-path override).
select_xy ¶
select_xy()
Brush/pick registration coordinates (x, y) | None for elements a
backend wires natively ([D124] — the declared replacement for
isinstance tuples in backend event code). Lowered elements carry this
on Lowered.select_xy instead.
opts ¶
opts(**kw)
[D133] surface configuration without abandoning the algebra:
el.opts(title=…, x="t [s]", y=AxisSpec(scale="log")) wraps this
element in a one-child Overlay carrying the options — the exact
Overlay([el], options=…) construction, as sugar. Accepts the
OverlayOptions keywords (title, x, y, y2, aspect,
legend, background, grid); x/y/y2 take a label string or
an AxisSpec. Chain on the result to refine.
qtviz.Overlay ¶
Bases: Immutable
Same axes, layered. Built by *. Single-surface → single backend.
opts ¶
opts(*, title: str | None | _Unset = UNSET, x: AxisSpec | str | None | _Unset = UNSET, y: AxisSpec | str | None | _Unset = UNSET, y2: AxisSpec | str | None | _Unset = UNSET, aspect: float | None | _Unset = UNSET, legend: bool | str | _Unset = UNSET, background: ColorSpec | None | _Unset = UNSET, grid: bool | _Unset = UNSET) -> Overlay
Field-wise options merge: only the fields you pass change
(UNSET keeps; None clears where meaningful). For x/y/y2 a
bare string merges into the existing spec's .label; a full
AxisSpec replaces it. Chains — later calls win per field.
qtviz.Layout ¶
Bases: Immutable
Side-by-side / grid / splitter / tabs / dock. Built by +. Children
may use different backends. A grid built by Layout.mosaic additionally
carries per-child cells — (row, col, rowspan, colspan) — so panes can
span.
Children may be named ([D145]): pass a mapping (Layout.grid({"price":
p, "volume": v})), a mosaic (labels retained), or explicit labels=.
Labels name the direct children — layout["price"] looks one up,
layout.with_pane("price", node) swaps one immutably — and become the
pane labels downstream (state capture/restore keys, view.pane(...),
event scoping). Unlabeled panes get their flat index as a string.
__getitem__ ¶
__getitem__(key: str | int) -> Node
A child by explicit label (searching nested Layouts too) or by
direct index. Only given labels resolve — default index labels are
positional, so address those with the int form.
with_pane ¶
with_pane(label: str, node: Node) -> Layout
Copy-with: the layout with the pane named label replaced by
node ([D145]) — the declarative way to update one pane
(view.set_root(root.with_pane("price", new_price))). Searches nested
Layouts; raises KeyError if the label is absent.
opts ¶
opts(*, title: str | None | _Unset = UNSET, rows: int | None | _Unset = UNSET, cols: int | None | _Unset = UNSET, spacing: int | _Unset = UNSET, link_x: bool | str | _Unset = UNSET, link_y: bool | str | _Unset = UNSET, tab_labels: Sequence[str] | None | _Unset = UNSET, dock_areas: Mapping[int, str] | Sequence[tuple] | None | _Unset = UNSET, width_ratios: Sequence[float] | None | _Unset = UNSET, height_ratios: Sequence[float] | None | _Unset = UNSET) -> Layout
Field-wise merge of the layout options (title here is the
container suptitle). Only passed fields change; chains.
grid
classmethod
¶
grid(children: Sequence[Node] | Mapping[str, Node], *, cells: Mapping[str, Cell] | Sequence[Cell] | None = None, **kw) -> Layout
A grid — from a sequence, or a mapping whose keys become the pane
labels ([D145]). cells= places panes explicitly ([D148]) — the
programmatic answer to spans, symmetric with the mosaic's output:
Layout.grid({"ch0": a, "ch1": b, "summary": s},
cells={"ch0": (0, 0, 1, 1), "ch1": (1, 0, 1, 1),
"summary": (0, 1, 2, 1)})
A cells mapping is keyed by label (mapping children required) and
may reorder freely; a sequence aligns with the children. Overlap and
span validity are checked like the mosaic parser's.
mosaic
classmethod
¶
mosaic(spec: MosaicSpec, mapping: Mapping[str, Node] | None = None, *, options: LayoutOptions | None = None, backend_hint: str | None = None, **panes: Node) -> Layout
A grid from an ASCII plan (the subplot_mosaic precedent):
Layout.mosaic("AAB\nCCB", A=curve, B=sidebar, C=table)
Layout.mosaic([["price", "book"],
["volume", "book"]], price=p, volume=v, book=ob)
String form: each distinct character is one pane (spanning its
rectangle); . is a hole. List form ([D145]): arbitrary string
labels, None (or ".") a hole. Panes come as keywords or as a
mapping (for labels that aren't identifiers); every label in the
spec must be given, and vice versa. Labels are retained — they key
state capture/restore, view.pane(...), and layout[label].
qtviz.View ¶
Bases: QWidget
The widget that renders a node tree — the bridge from declarative elements to a live Qt widget.
View(root) renders an Element, Overlay, or Layout (or a reactive
Signal[Node], re-rendering on change) through the chosen backend and IS
a plain QWidget: embed it in any PySide6 layout. Pan/zoom/selection
state survives set_backend() switches; on() subscribes to the typed
interaction events; lazy data resolves off the GUI thread with the last
render kept visible. Constructing a View before a QApplication exists
is safe — it creates one on demand.
handle
property
¶
handle: Any
The live backend RenderHandle for the current render (or None
while resolving) — the [D53] escape hatch to backend-native objects.
root
property
¶
root: Any
The rendered node tree — pair with Layout.with_pane for the
declarative per-pane update:
view.set_root(view.root.with_pane("price", new_node)).
panes
property
¶
panes: tuple
Every pane of the current render, flattened in layout order (empty while a lazy render is resolving).
set_backend ¶
set_backend(name_or_backend: str | Backend) -> None
Re-render through a different backend — by registered name
("pyqtgraph", "matplotlib", "webengine", "auto") or a
Backend instance. The current pan/zoom/selection state carries
over; event subscriptions survive the switch.
set_root ¶
set_root(root: Any) -> None
Replace the rendered node tree (an Element/Overlay/Layout)
and re-render. For continuously-updating data prefer a qv.stream
source or a reactive Signal[Node] root over repeated set_root.
on ¶
on(event_type: type, cb: Callable, *, throttle_ms: int | None = None, source=None, pane=None) -> Disposable
Subscribe to a typed event. source= ([D134]) filters by the
emitting element — pass an Element (or its id), or a sequence of
either; it replaces the e.source_id == el.id lambda idiom.
pane= ([D149]) filters by the emitting surface — a pane label
([D145]; "0", "1", … when unlabeled) or a sequence of labels:
view.on(qv.RangeEvent, on_zoom, pane="price"). Both filters
compose.
pane ¶
pane(key: str | int | None = None)
The current render's PaneHandle for one surface ([D147]) — by
label ([D145]), by flat index, or (key=None) the only pane. The
"Axes of qtviz": interaction-side verbs only —
view.pane("price").set_range(x=(0, 10)) # programmatic pan/zoom
view.pane("price").autorange()
view.pane("price").select(x0, y0, x1, y1) # programmatic brush
view.pane("price").capture() # ViewState, data space
view.pane("price").native # PlotItem / Axes / host
view.pane("price").elements # ids on this surface
Facades wrap the current render: fetch fresh rather than caching —
a pane kept across a rebuild goes dead (pane.alive) and raises
DisposedError. Describe-side config (title, scale, …) stays on the
node (.opts() / set_root). Raises while a lazy render is still
resolving (View.loading).
native ¶
native(element_id: str) -> Any
The live backend primitive for an element (handle.native, [D53]) — the
escape valve for backend-native work (ROIs, crosshairs, native signals) the
typed events don't expose. None if not rendered. Non-portable by design.
qtviz.show ¶
show(root, *, title: str | None = None, size: tuple[int, int] = (960, 640), backend: str | Backend = 'auto', theme: Theme | None = None, toolbar: bool = False, block: bool = True) -> View
The one-liner for scripts: wrap root in a View (an existing
View passes through), size/title/show it, and — with block=True — run
the Qt event loop. Returns the View either way, so block=False hands
back a live widget for embedding or tests. View itself stays a plain
QWidget for real applications.
Constructing widgets before calling show is safe: View ensures a
QApplication exists, so qv.show(qv.View(...)) and
qv.show(qv.Scatter(...)) both just work. root may also be a
zero-argument callable returning the node or a ready View — a
convenience for keeping build()-style examples importable, no longer a
requirement. toolbar/backend/theme apply when show constructs the
View; a passed-in View keeps its own settings.
Panes — downstream use of each surface¶
After render, each surface (grid cell, tab, splitter pane — or the whole plot
of a single-surface render) is addressable as a pane ([D145]/[D147]):
view.pane("price") returns a live PaneHandle — the "Axes of qtviz" —
scoped to interaction-side verbs (set_range, autorange, select,
capture/restore, native, elements). Describe-side configuration stays
on the node (.opts(), Layout.with_pane + set_root). Whole-render state
is a LayoutState — ordered (label, ViewState) pairs, matched by label
across rebuilds and backend switches. These are returned types, importable
from qtviz.core.backend ([D135] return-type convention).
qtviz.core.backend.PaneHandle ¶
One surface of a live render — the "Axes of qtviz" ([D147]). A thin
facade over the current render, scoped strictly to interaction-side
concerns: view ranges, programmatic brush, the native escape hatch.
Describe-side config (title, scale, …) never flows through here — that is
.opts() on the node; one-way data flow keeps rebuilds reasoned about.
Facades are built fresh by RenderHandle.panes() on every call and go
stale with the render they wrap — fetch fresh, never cache across a
rebuild. All widget-touching methods are GUI-thread-only. The base class
is an inert single pane, so any single-surface backend that predates the
protocol is compliant with zero changes ([D125]).
alive
property
¶
alive: bool
Whether the render this pane wraps is still the live one. A pane
kept across a rebuild/backend switch goes dead — its widgets are
Qt-disposed — and every state-touching call raises DisposedError.
native
property
¶
native: Any
The live backend surface primitive — a pg PlotItem, an mpl Axes,
the webengine host ([D53]). Non-portable by design; None if unknown.
elements
property
¶
elements: tuple[str, ...]
Ids of the elements rendered on this surface (feed View.on(source=…)).
restore ¶
restore(state: ViewState) -> None
Apply state — None fields leave the current range untouched.
set_range ¶
set_range(*, x: tuple[float, float] | None = None, y: tuple[float, float] | None = None, y2: tuple[float, float] | None = None) -> None
Programmatic pan/zoom sugar — data-space (lo, hi) per axis; omitted
axes keep their current range. The same interaction-state class of
change as a user drag, so events/rasters react identically.
select ¶
select(x0: float, y0: float, x1: float, y1: float) -> None
Programmatic brush: emits the same per-element SelectEvents a
Shift-drag over (x0, y0)–(x1, y1) (data space) would.
export ¶
export(fmt: str, path, *, dpi: float | None = None, transparent: bool = False) -> Path
Write just this pane to path ([D150] — the per-pane answer to
[D72]'s whole-container raster). Formats follow the backend's own
export capabilities.
qtviz.core.backend.LayoutState
dataclass
¶
Portable interaction state for a whole render ([D150]): ordered
(pane label, ViewState) pairs, one per surface. Restore matches by
label — same label = same role, so state survives backend switches and
root swaps; labels the new render doesn't have drop silently (a changed
dashboard shape is not an error). Default pane labels are index strings
("0", "1", …), so unlabeled layouts degrade to positional matching.
For the single-surface case (x_range & co.) the first pane's fields pass
through, so handle.capture_state().x_range keeps reading naturally.
Data binding¶
qtviz.col ¶
col(name: str) -> Col
Reference a data column by name in an Expression (e.g. col("a") - col("b")).
qtviz.lit ¶
lit(value) -> Lit
A literal scalar inside an Expression (broadcast against the columns).
qtviz.tabular ¶
tabular(data: Any) -> DataRef
Force data to a tabular ref — e.g. a 1-D xarray DataArray as columns.
qtviz.gridded ¶
gridded(data: Any) -> DataRef
Force data to a gridded ref — e.g. a plain 2-D array as an image grid.
qtviz.set_raster_threshold ¶
set_raster_threshold(n: int) -> None
raster='auto' rasterizes a Scatter once its point count exceeds n.
qtviz.set_raster_size ¶
set_raster_size(width: int, height: int) -> None
Default datashader canvas resolution for static rasterization.
qtviz.stream ¶
The streaming data source ([D76], milestone-0.6-live §1).
StreamRef is a mutable, append-able tabular DataRef with a ring-buffer
rolling window. It notifies through the base contract's subscribe seam —
designed in Phase 1, stubbed NOOP everywhere until now. Pure Python + numpy,
no Qt: append is thread-safe under a lock; whoever subscribes owns the
GUI-thread marshaling (the View's StreamBinding, increment 2).
Purity (R1/[D38]): the Element holding a StreamRef stays immutable — it holds a handle to changing data, exactly like a pandas frame the user mutates. The only new power is that this handle tells its subscribers.
StreamRef ¶
Bases: TabularRef
Append-able named columns with an optional rolling window (max rows —
old rows drop as new ones arrive, the spec §12 "stream-time auto-rolling"
deferral lifted). is_lazy stays False: reads are cheap in-memory slices;
nothing here needs the async resolve path.
append ¶
append(**columns: Any) -> None
Append rows (scalars or equal-length 1-D arrays for every column). Thread-safe; fires each subscriber once per append (after the write).
resolve_channels ¶
resolve_channels(channels: dict[str, Any], *, who: str | None = None) -> dict[str, np.ndarray]
Snapshot the buffer under the lock, then resolve accessors against the copy — a render never sees a torn append, and later appends never mutate an already-resolved frame.
stream ¶
stream(columns: dict[str, Any], *, window: int | None = None) -> StreamRef
A live, append-able data source: stream({"t": float, "v": float},
window=100_000). Bind it to any element like a dict/DataFrame; views on it
update as you append (from any thread). window keeps the last N rows.
Encoding & styling¶
qtviz.Color ¶
Immutable canonical color. str / tuple inputs auto-convert.
qtviz.Palette ¶
Bases: Immutable
An ordered, cycling sequence of colors used for categorical encoding.
qtviz.Theme ¶
Bases: Immutable
Backend-agnostic styling (background, axes, palette) applied to any View.
Construct directly or via Theme.light() / dark() / from_qt_app().
qtviz.set_default_theme ¶
set_default_theme(theme: Theme | None) -> None
The app-level default a View(theme=None) consults — symmetry
with set_default_backend. None restores the built-in light theme.
qtviz.Norm ¶
The one colormap-normalization spec, shared by every element that maps
values to color (Image, Heatmap, Mesh, Scatter.color_by). The
string shorthand (norm="log") covers the 90% case; Norm carries only
the transform's own parameters (gamma for power, linthresh for
symlog, levels for boundary) — the value-range clamp is the
separate clim=. A parameter set for a kind that ignores it raises:
accept-then-ignore is the one sin this library refuses.
qtviz.OverlayOptions ¶
Bases: Immutable
Shared-surface options for an Overlay: title, per-axis AxisSpec (x/y,
plus the twin y2, ), aspect, legend toggle + position, background,
grid toggle.
`x`/`y`/`y2` take an `AxisSpec` or — the shorthand — a bare string
meaning the axis label; `AxisSpec.label` is the one canonical home. `y2`
configures the right-hand axis that appears when any series element sets
`axis="y2"` — it is ignored when none does. `legend` is one union field
: True/"auto" places automatically, "right"/"top" place
explicitly, False/"none" hides everything.
qtviz.LayoutOptions ¶
Bases: Immutable
Arrangement options for a Layout: rows/cols, spacing, axis linking
(link_x/link_y — True links all panes, "col"/"row" link within
each grid column/row, [D146]), tab/dock labels, relative column/row sizes
(width_ratios/height_ratios, ), and a container title
(the figure suptitle).
qtviz.AxisSpec ¶
Bases: Immutable
Per-axis surface configuration — label, scale, limits, ticks.
scale (linear|log|symlog|time), declarative lim, invert;
tick_format is "auto", "eng", a Python format-spec
(".2f", ",d", ".0%"), a strftime pattern, or a one-field template
("${:,.0f}", "{:.0f} ms"); explicit ticks/tick_labels pin the
positions/labels; minor=True requests minor ticks and
tick_rotation rotates the labels. All positions are data space
(R1). A backend that can't render the requested scale warns and falls
back to linear.
Events¶
qtviz.Event
dataclass
¶
Base of every typed interaction event. source_id names the emitter —
the element for element events (pick/select/hover), the pane label for
surface events (range/tap). pane ([D149]) always carries the pane label
of the surface the event came from ([D145]; "0", "1", … when unlabeled)
— subscribe with view.on(EventType, cb), filtered by element via
source= or by pane via pane=.
qtviz.RangeEvent
dataclass
¶
Bases: Event
The visible axis ranges changed (pan/zoom): x/y are the new
(lo, hi) data-space bounds.
qtviz.PickEvent
dataclass
¶
Bases: Event
A single data point was clicked: its point_index in the element's
data plus the data-space x/y of the point.
qtviz.SelectEvent
dataclass
¶
Bases: Event
A brush/box selection completed: the selected indices into the
element's data and the data-space bounds (x0, y0, x1, y1).
qtviz.HoverEvent
dataclass
¶
Bases: Event
The pointer moved over the plot: nearest point_index (or None off
the data) and the data-space cursor position. On a datashaded raster
value carries the aggregated count/mean under the cursor.
qtviz.TapEvent
dataclass
¶
Reactive¶
qtviz.signal ¶
S-style reactivity — Signal / derived / effect / batch (spec §9; D38–D40).
Auto-tracking: while a derived/effect body runs, it sits on the _observers
stack and every Signal.get() registers it as a subscriber — so dependencies are
discovered automatically. Synchronous, GUI-thread-only (a cross-thread set
marshals via run_on_gui); simple propagation + batch() to coalesce, not
topological/glitch-free (D39). The whole graph is tiny and runs on one thread, so
no locks.
Signal ¶
Bases: Generic[T]
A reactive cell: read with get() (auto-tracks), write with set().
derived ¶
derived(fn: Callable[[], T]) -> Signal[T]
A read-only signal that recomputes fn when any signal it reads changes.
effect ¶
effect(fn: Callable[[], None], *, owner=None) -> Disposable
Run fn now and re-run it on any tracked-signal change; dispose to stop
(auto-disposed when owner QObject is destroyed).
batch ¶
batch(fn: Callable[[], None]) -> None
Run fn, coalescing all sets into a single notification pass.
qtviz.derived ¶
derived(fn: Callable[[], T]) -> Signal[T]
A read-only signal that recomputes fn when any signal it reads changes.
qtviz.effect ¶
effect(fn: Callable[[], None], *, owner=None) -> Disposable
Run fn now and re-run it on any tracked-signal change; dispose to stop
(auto-disposed when owner QObject is destroyed).
qtviz.batch ¶
batch(fn: Callable[[], None]) -> None
Run fn, coalescing all sets into a single notification pass.
qtviz.Signal ¶
Bases: Generic[T]
A reactive cell: read with get() (auto-tracks), write with set().
HoloViews / hvplot adapter¶
qtviz.from_holoviews ¶
from_holoviews(obj: Any)
Translate a HoloViews element/container into a qtviz Node.
Returns a native Element/Overlay/Layout where qtviz models the type, else
a RawFigure hosted on the webengine backend. A DynamicMap with kdims
returns a Signal[Node] (seeded at default kdim values — use
from_holoviews_dmap to drive the kdims); a stream-only DynamicMap renders
its current frame statically with a warning (L1). Raises
UnsupportedHoloViewsElement only if even the RawFigure fallback cannot apply.
qtviz.from_holoviews_dmap ¶
from_holoviews_dmap(dm: Any) -> DMapBinding
Build a DMapBinding from a HoloViews DynamicMap (one-way, L1).
One writable Signal per kdim (seeded by _kdim_default) feeds a derived
Signal[Node] that resolves dm[values] and runs the static translation on
each frame. No qtviz→hv write-back (that is Level 2, deferred).
qtviz.from_hvplot ¶
from_hvplot(data: Any, kind: str, **kwargs: Any)
Translate an hvplot call into a qtviz Node (Path A).
data.hvplot(kind=kind, **kwargs) returns a HoloViews object (Element /
Overlay / often a DynamicMap), which from_holoviews already consumes — so
this is a thin convenience. hvplot is an optional extra (qtviz[hvplot]),
imported lazily here.
kind and **kwargs are forwarded verbatim to hvplot; they are hvplot's
contract, not qtviz's stable surface, and are not validated here.
Errors¶
QtvizError is the base of every error qtviz raises on purpose —
except qv.QtvizError catches every deliberate rejection. The full taxonomy
(validation, negotiation, adapters, missing dependencies) lives in
qtviz.errors.
qtviz.QtvizError ¶
Bases: Exception
Base for every error qtviz raises on purpose.
Backend selection¶
qtviz.set_default_backend ¶
set_default_backend(name: str) -> None
Set the backend used when a View is created with backend="auto" and no hint.
Validated eagerly: an unregistered name raises here rather than surfacing later, deep inside negotiation, far from this call.
Backend authors (qtviz.backends)¶
The extension namespace ([D125]): third-party backends register through the
qtviz.backends entry-point group, and the author-facing contracts live here —
qtviz.backends.Capabilities (the honesty declaration) and
qtviz.backends.set_backend_priority (the auto-negotiation preference order).
See Backends for the full extension guide.