API — nefi.viz¶
Generated by scripts/gen_api_docs.py — do not edit by hand. Index
nefi.viz¶
nefi.viz — figures, animations, dashboards and shareable reports for neural-field inversion.
nefi.viz.fields¶
Field viewers: 1-D lines, 2-D images, 3-D slices / mosaics / projections / voxels, and the standard reconstruction figure :func:compare_fields (GT | measurement | reconstruction(s) | signed error, metrics in the panel titles).
class Comparison(name: str | None, label: str, tag: str, g: np.ndarray | None, items: list[tuple[str, np.ndarray]], mets: dict[str, dict[str, float]], spec: CmapSpec, domain...¶
Everything a comparison layout needs (resolved by :func:compare_fields).
gt_title(self) -> strlims(self) -> tuple[float, float]recon_title(self, lab: str, n_metrics: int = 2) -> str
def add_colorbar(fig: Any, mappable: Any, axes: Any, label: str | None = None, nticks: int = 4, shrink: float = 0.85, location: str | None = None, pad: float = 0.015) -> Any¶
Thin colorbar attached to one axes or a list of axes (constrained-layout friendly); location="bottom" puts it below (e.g. next to 3-D axes, whose tick labels constrained layout does not see).
def anomaly_background(a: Any) -> float¶
Background level of a field: its median (the bulk value for localized anomalies).
def anomaly_centroid(vol: Any, *, mask: Any = None, background: float | None = None, level: float = 0.5) -> tuple[int, ...]¶
Grid index of the centroid of the dominant anomaly of a 2-D / 3-D field.
def anomaly_levels(gt: Any, *, background: float | None = None, fraction: float = 0.5, min_share: float = 0.2) -> list[float]¶
Contour levels outlining the anomalies of a ground truth: background ± fraction × the largest deviation on each side (a side whose deviation is below min_share of the other is skipped, so a positive-only source map gets one level and a signed map two).
def as_complex(a: np.ndarray, stacked: str | None = None) -> np.ndarray¶
Combine a stacked real/imag pair (stacked="first": shape (2, ...); "last": (..., 2)) into a complex array; other arrays are returned unchanged.
def axis_coords(n: int, domain: Any = None, dim: int = 0) -> np.ndarray¶
Cell-center coordinates of axis dim (physical if domain is given).
def compare_fields(gt: Any, recons: Any, measurement: Any = None, *, kind: str = 'auto', field: str | None = None, quantity: str | None = None, metrics: Any = 'auto', error: b...¶
The standard reconstruction figure: measurement | GT | reconstruction(s) | extra panels.
def default_metrics(kind: str) -> dict[str, Callable]¶
PSNR + relative error (1-D), PSNR + SSIM (2-D / 3-D) from :mod:nefi.metrics.basic.
def depth_mosaic(vol: Any, *, field: str | None = None, axis: int = -1, slices: Sequence[int] | None = None, n_slices: int = 8, ncols: int | None = None, domain: Any = None,...¶
Depth-slice mosaic of a 3-D field with one shared color scale (NeFTY Fig. 4 style).
def detect_kind(x: Any, kind: str = 'auto') -> str¶
"1d" | "2d" | "3d" | "complex" from the dimensionality / dtype of x.
def draw_contour(ax: Axes, mask: Any, extent: tuple[float, float, float, float], color: str | None = None, level: float = 0.5)¶
Outline of a 2-D mask (e.g. a defect / support) on an image panel.
def draw_levels(ax: Axes, arr: Any, levels: Sequence[float], extent: tuple[float, float, float, float], *, style: str = 'gt', origin: str = 'lower', color: str | None = Non...¶
Iso-lines of a 2-D array (field convention a[x, y]) on an image panel.
def draw_peaks(ax: Axes, idx: np.ndarray, shape: Sequence[int], extent: tuple[float, float, float, float], style: str = 'gt')¶
Overlay peak markers: "gt" hollow white circles, "recon" aqua crosses.
def field_metrics(pred: Any, gt: Any, metrics: Mapping[str, Callable] | str | None = 'auto') -> dict[str, float]¶
Metrics of pred against gt (failures become nan, never exceptions).
def image_extent(shape: Sequence[int], domain: Any = None, dims: tuple[int, int] = (0, 1)) -> tuple[float, float, float, float]¶
imshow extent (x0, x1, y0, y1) of a 2-D slice: physical when domain (a :class:~nefi.domain.Domain or an extent list) is given, pixel indices otherwise.
def image_panels(images: Mapping[str, Any], *, field: str | None = None, spec: CmapSpec | str | None = None, shared: bool = True, ncols: int | None = None, peaks: bool = Fal...¶
Grid of 2-D panels {label: image} with one shared color scale (default).
def line_profile(a: np.ndarray, center: Sequence[int], axis: int) -> np.ndarray¶
Values of a along axis through the grid point center.
def match_shape(a: np.ndarray, shape: Sequence[int]) -> np.ndarray¶
Resample a to shape (area / linear, cell-centered) when the shapes differ.
def metrics_label(metrics: Mapping[str, Any] | None, max_items: int = 2) -> str¶
"PSNR 24.1 dB · SSIM 0.912" from a metrics dict (first max_items entries).
def orthoslices(vol: Any, *, field: str | None = None, index: Sequence[int] | None = None, domain: Any = None, spec: CmapSpec | str | None = None, title: str | None = None,...¶
Three orthogonal slices through index (default: the most anomalous voxel, i.e. the largest difference from the median — typically inside a defect).
def panel_set(panels: Any = None, error: bool = True) -> tuple[str, ...]¶
Normalize compare_fields(panels=...): None → measurement, GT, reconstruction and the signed error; a string names the extra panel ("overlay" → measurement, GT, reconstruction, overlay); a sequence lists the panels (any of :data:PANELS).
def peak_indices(img: Any, threshold: float = 0.05) -> np.ndarray¶
(k, 2) integer (i, j) indices of 3×3 local maxima above threshold · max.
def plot_complex(x: Any, *, field: str | None = None, domain: Any = None, title: str | None = None, complex_stack: str | None = None, dark: bool | None = None) -> Figure¶
Magnitude (magma) and phase (twilight on [-π, π]) of a complex 1-D / 2-D field (3-D: representative slice).
def plot_field(x: Any, *, field: str | None = None, kind: str = 'auto', ax: Axes | None = None, domain: Any = None, title: str | None = None, colorbar: bool = True, peaks:...¶
Draw one field: line (1-D), image (2-D), depth mosaic (3-D; the representative slice when ax is given) or magnitude + phase (complex).
def plot_line(ax: Axes, y: Any, *, x: Any = None, domain: Any = None, label: str | None = None, color: str | None = None, style: str = 'recon', **kw: Any)¶
One 1-D field on an axes. style: "gt" (ink, dashed), "recon" (series color, solid), "data" (muted dots).
def projections(vol: Any, *, field: str | None = None, mode: str = 'auto', domain: Any = None, spec: CmapSpec | str | None = None, title: str | None = None, colorbar: bool ...¶
Max / min / mean projections of a 3-D field along each axis.
def representative_slice(vol: np.ndarray, axis: int = -1) -> int¶
Index of the slice with the largest in-slice variance (ties → the middle slice).
def resolve_field(obj: Any, field: str | None = None) -> tuple[np.ndarray, str | None]¶
Array of one field from a tensor, a :class:~nefi.solve.Result, a fields dict or a :class:~nefi.measurement.Measurement.
def select_slices(n: int, n_slices: int) -> list[int]¶
n_slices evenly spaced indices in [0, n) (all of them if n <= n_slices).
def show_image(ax: Axes, img: Any, *, spec: CmapSpec | str | None = None, name: str | None = None, vmin: float | None = None, vmax: float | None = None, extent: tuple[floa...¶
Draw a 2-D array as an image panel.
def squeeze_field(a: np.ndarray) -> np.ndarray¶
Drop singleton dims ((1, 64, 64) → (64, 64)) but keep at least 1-D.
def take_slice(vol: np.ndarray, index: int, axis: int = -1) -> np.ndarray¶
2-D slice vol[..., index] along axis (remaining dims keep their order).
def to_numpy(x: Any) -> np.ndarray¶
Tensor / array / list → numpy (float64 for real data, complex128 for complex data).
def voxel_threshold(a: np.ndarray, mode: str = 'auto', background: float | None = None, fraction: float = 0.5) -> tuple[str, float]¶
(mode, threshold) of a voxel view: the anomaly side ("below" / "above" the background, the side of the larger deviation for mode="auto") and the level fraction of the way from the background (default: the median) to that extreme.
def voxel_view(vol: Any, *, field: str | None = None, threshold: float | None = None, mode: str = 'auto', max_points: int = 4000, domain: Any = None, ax: Axes | None = Non...¶
Isosurface-free 3-D view: scatter of thresholded voxels, colored by value.
nefi.viz.hints¶
Display hints: how an instance wants its measurement and its fields drawn.
def apply_transform(a: np.ndarray, transform: Any, *, domain: Any = None, instance: Any = None) -> np.ndarray¶
Apply a display transform to one array (returns a new array; the input is unchanged).
def compare_extras(hints: Mapping[str, Any] | None, ndim: int) -> tuple[str, ...]¶
Extra panels of the gallery's compare figure: the compare_panel hint, else ("overlay",) for 3-D fields and ("error",) otherwise.
def field_hint(hints: Mapping[str, Any] | None, key: str, field: str | None) -> Any¶
Value of a field-level hint for field: a plain value applies to every field, a mapping {field: value} only to the fields it names ("*" = default).
def instance_hints(instance: Any = None, hints: Mapping[str, Any] | None = None) -> dict¶
Display hints for instance (:data:INSTANCE_HINTS < instance.viz_hints < explicit hints).
def transform_is_magnitude(transform: Any) -> bool¶
True for transforms whose result is a non-negative magnitude (abs, gradients).
def transform_name(transform: Any) -> str | None¶
Canonical name of a transform spec (None for the identity).
def transform_note(transform: Any) -> str¶
Short text for panel titles ("mean removed", "log₁₀", ...); "" = identity.
def volume_axis(hints: Mapping[str, Any] | None, default: int = -1) -> int¶
The volume_axis hint (slicing axis of 3-D fields), default when absent.
nefi.viz.interactive¶
Interactive 3-D viewer: drag-to-rotate isosurfaces, voxels and slices in the browser.
def asset_bytes() -> int¶
Size of :func:assets_html in bytes (shared by every viewer of a page).
def assets_html() -> str¶
The viewer's <style> and <script> — include once per page.
def auto_stretch(extent: Sequence[Sequence[float]], axis: int = -1) -> float¶
Depth stretch of thin slabs (as the static voxel views): physical (1) unless the volume axis is shorter than 35 % of the largest lateral side, then stretched to 35 %.
def decode_mesh(entry: Mapping[str, Any], shape: Sequence[int]) -> tuple[np.ndarray, np.ndarray]¶
(vertices (V, 3), faces (F, 3)) of a mesh entry (mirror of the JS decodeMesh).
def decode_volume(entry: Mapping[str, Any], shape: Sequence[int]) -> np.ndarray¶
The values the viewer decodes from a payload volume (mirror of the JS decode).
def downsample(a: np.ndarray, max_side: int = 64) -> np.ndarray¶
Area-average a so no side exceeds max_side (unchanged when it already fits).
def encode_mesh(verts: np.ndarray, faces: np.ndarray, shape: Sequence[int], **meta: Any) -> dict[str, Any]¶
A mesh entry: vertices (grid index coordinates in [-0.5, n - 0.5]) as uint16 over each axis, faces as uint16 (≤ 65535 vertices) or uint32; meta (level, side, rule) is kept.
def entry_viewer_inputs(entry: Any) -> tuple[dict[str, np.ndarray], dict[str, Any]]¶
(volumes, options) of a 3-D gallery entry: GT and reconstruction on the GT grid (the instance's display hints applied, :func:~nefi.viz.multiphysics.tile_data) — with an edge refinement GT | smooth | refined (or the refused candidate, labelled) —, the instance's IoU rule as the GT threshold, the anomaly centroid, the volume_transform hint.
def normalize_kind(kind: Any) -> str | None¶
"canvas" / "plotly" / None (off) from True, False, None or a name ("none", "off", "js", "vanilla", ...).
def normalize_mode(mode: str) -> str¶
One of :data:MODES (aliases: "isosurface", "points+slice", "both", ...).
def payload_levels(payload: Mapping[str, Any]) -> list[dict[str, Any]]¶
Levels, counts and IoU / Dice at the payload's defaults, recomputed from the decoded values like the browser does (tests and tools).
def plotly_cdn_tag() -> str¶
The <script src=…> tag of the plotly.js CDN build matching the installed plotly.
def plotly_volume_html(volumes: Any, *, extent: Any = None, threshold: Any = None, cmap: Any = None, title: str | None = None, height: int = 420, standalone: bool = False, field: ...¶
Isosurfaces with plotly.graph_objects.Isosurface (one scene per volume, cameras synchronized): the GT at its threshold rule, reconstructions at their level_rule level.
def quantize(a: np.ndarray, bits: int = 8, rules: Sequence[Mapping[str, Any]] = ()) -> tuple[dict[str, Any], np.ndarray]¶
Quantize a volume to bits-bit codes lo + q · step (the top code is NaN when the volume has NaNs); codes are nudged so each rule in rules selects exactly the voxels it selects in a (relative rules use a's own max / min, embedded as peak / trough). Returns (entry, decoded) — the JSON entry and the values the viewer sees.
def save_volume_viewer(path: str | Path, volumes: Any, *, kind: str = 'canvas', **kw: Any) -> Path¶
Write a standalone viewer page (kind="plotly": the CDN-backed plotly page).
def standalone_page(body: str, title: str, subtitle: str | None = None) -> str¶
A whole HTML document (report stylesheet, light / dark) around body.
def viewer_cmap(spec: CmapSpec) -> str¶
The viewer's colormap for a spec: the same name when implemented (_r variants included), else by kind (diverging → RdBu_r, cyclic → twilight, viridis).
def viewer_fragment(payload: Mapping[str, Any], *, height: int = 420, include_assets: bool = True, element_id: str | None = None) -> str¶
HTML fragment of one viewer: the (optional) assets, a <div> with a unique id, the JSON payload in a <script type="application/json"> and a one-line mount script.
def viewer_fragment_from_file(path: str | Path, *, height: int = 420, include_assets: bool = True, include_plotlyjs: bool = True) -> str¶
The report fragment of a viewer.json written by :func:write_entry_viewer (fresh element ids; the canvas assets / the plotly CDN tag only when asked — once per page).
def viewer_payload(volumes: Any, *, extent: Any = None, threshold: Any = None, mode: str = 'voxels', cmap: Any = None, title: str | None = None, field: str | None = None, labe...¶
The JSON payload of a viewer (see :func:volume_viewer_html for the arguments).
def viewer_size_bytes(volumes: Any, *, include_assets: bool = False, **kw: Any) -> int¶
Bytes a viewer adds to a page: the fragment of volumes (or of a ready payload), without the shared script / stylesheet unless include_assets.
def volume_viewer_html(volumes: Any, *, extent: Any = None, threshold: Any = None, mode: str = 'voxels', cmap: Any = None, title: str | None = None, height: int = 420, standalone:...¶
HTML of an interactive 3-D viewer of one or two volumes (same camera).
def write_entry_viewer(entry: Any, out_dir: str | Path, *, kind: str = 'canvas') -> dict[str, Any]¶
Write the viewer of a 3-D gallery entry: <name>/viewer.json (what reports embed) and <name>/viewer.html (a standalone page). Returns the manifest info (paths relative to out_dir, sizes in bytes, grid, rule, default levels and IoU / Dice).
nefi.viz.isosurface¶
Isosurfaces of 3-D fields: threshold rules, volume-matched iso-levels, display transforms, marching-cubes meshes and the shaded static renderings of gallery_3d.png / voxels.png.
def auto_rule(reference: Any) -> dict[str, Any]¶
Half-way from the reference's background (median) to its extreme on the anomaly side — the rule of the static voxel views (:func:~nefi.viz.fields.voxel_threshold).
def contour_levels(gt: Any, fractions: Sequence[float] = (0.25, 0.5, 0.75)) -> list[float]¶
Levels at fractions of the GT contrast, from its background (median) toward its extreme on the anomaly side.
def depth_exaggeration(shape: Sequence[int], domain: Any = None, factor: float = 0.6) -> float¶
Stretch of the depth axis of 3-D panels: max(1, factor · lateral / depth) (thin slabs stay readable; the axis label says ×k).
def draw_isosurfaces(axes: Sequence[Axes], entries: Sequence[tuple[str, np.ndarray, float, str]], *, domain: Any = None, colors: Sequence[str] | None = None, elev: float = 24.0,...¶
Shaded isosurfaces, one per projection="3d" axes, with one camera and one box.
def draw_level_contours(axes: Sequence[Axes], gt: np.ndarray, recon: np.ndarray, *, center: Sequence[int] | None = None, axis: int = -1, levels: Sequence[float] | None = None, frac...¶
Multi-level contours of GT (solid) and reconstruction (dashed) on the central slices.
def gaussian_smooth(a: Any, sigma: float) -> np.ndarray¶
Separable Gaussian smoothing (radius ⌈3σ⌉, replicated edges), σ in voxels.
def has_marching_cubes() -> bool¶
True when skimage.measure.marching_cubes is importable.
def hinted_transform(hints: Mapping[str, Any] | None, field: str | None = None) -> Any¶
The volume_transform display hint for field (a spec, or {field: spec} with "*" as default), normalized by :func:transform_spec.
def iou_dice(a: Any, b: Any) -> tuple[float, float]¶
(IoU, Dice) of two boolean masks (NaN when both are empty).
def iso_compare(gt: Any, recons: Any = None, *, field: str | None = None, rule: Any = None, how: str = 'matched', instance: Any = None, domain: Any = None, transform: Any =...¶
GT and reconstruction(s) as shaded isosurfaces with matched levels, plus contours.
def iso_levels(gt: Any, recon: Any, rule: Any = None, *, manual: float | None = None) -> dict[str, Any]¶
The GT level and the reconstruction's fixed / volume-matched / Otsu (/ manual) levels, with the voxel count, IoU and Dice of each reconstruction set against the GT set.
def iso_mesh(values: Any, level: float, side: str = 'above', *, max_faces: int = 20000, step_size: int | None = None) -> tuple[np.ndarray, np.ndarray] | None¶
Marching-cubes isosurface enclosing the voxels past level on side.
def iso_titles(label: str, levels: Mapping[str, Any], how: str = 'matched', name: str | None = None) -> tuple[str, str]¶
Two-line panel titles of a GT / reconstruction isosurface pair: level and rule, voxels or IoU / Dice (with the IoU at the GT threshold for comparison).
def level_rule(value: float, side: str, source: str = '') -> dict[str, Any]¶
An absolute rule v > value (side="above") or v < value.
def matched_level(values: Any, side: str, count: float) -> float¶
The volume-matched level: count voxels of values lie past it on side.
def normalize_rule(threshold: Any, reference: Any = None) -> dict[str, Any]¶
A threshold rule from None (automatic, :func:auto_rule), a number (side of the reference's larger deviation), (side, value) or a mapping.
def otsu_level(values: Any, bins: int = 256) -> float¶
Otsu's threshold: the histogram split (bins bins over [min, max]) maximizing the between-class variance — the middle of the maximizing splits when an empty gap between the classes makes several of them tie.
def recon_level(values: Any, rule: Mapping[str, Any], how: str, *, gt_count: int, manual: float | None = None) -> float¶
The level of a reconstruction under a level rule (:data:LEVEL_RULES).
def rule_level(rule: Mapping[str, Any], values: Any = None, *, peak: float | None = None, trough: float | None = None) -> float¶
The threshold of rule in data units for one volume (relative rules use the volume's own peak / trough: its max / min unless given).
def select_mask(values: Any, rule: Mapping[str, Any], *, peak: float | None = None, trough: float | None = None) -> np.ndarray¶
Voxels selected by a threshold rule (NaN never selected).
def surface_colors(n: int, dark: bool | None = None) -> list[str]¶
Isosurface colours: the ground truth neutral, reconstructions the categorical slots.
def transform_label(spec: Any) -> str¶
"display: smooth σ=1" (empty for no transform) — used in every title.
def transform_spec(spec: Any) -> dict[str, Any] | None¶
Normalize a volume display transform: None / "none" → None; a name of :data:VOLUME_TRANSFORMS (aliases: gaussian, unsharp, tv, bilateral, …); a mapping {"name": ..., <parameters>}; or (name, {parameters}).
def volume_transform(a: Any, spec: Any) -> np.ndarray¶
Apply a display transform (:func:transform_spec) to a volume; returns a new array.
def voxel_rule(instance: Any = None, reference: Any = None, *, hints: Mapping[str, Any] | None = None, field: str | None = None) -> dict[str, Any]¶
The GT threshold rule of voxel / isosurface views: the instance's IoU rule.
nefi.viz.measurement¶
Measurement viewers: spectra, time-series frames, sinograms, receiver traces, k-space masks, signals, sparse point observations — and :func:plot_fit (data vs prediction vs residual with the noise floor).
class MeasurementView(layout: str, kind: str, data: np.ndarray, label: str, spec: CmapSpec, mask: np.ndarray | None = None, points: tuple[np.ndarray, np.ndarray, np.ndarray] | No...¶
A single-panel representation of a measurement.
def detect_layout(data: Any, meta: Mapping | None = None, field_shape: Sequence[int] | None = None, mask: Any = None) -> str¶
Guess the measurement layout (see the module table) from shape, dtype and metadata.
def draw_measurement(ax: Axes, measurement: Any, *, field_shape: Sequence[int] | None = None, instance: Any = None, layout: str = 'auto', title: str | None = None, colorbar: boo...¶
Draw the compact view of a measurement into ax and return the view used (arguments as in :func:measurement_view; axes=True keeps ticks and axis labels).
def measurement_view(measurement: Any, *, field_shape: Sequence[int] | None = None, instance: Any = None, layout: str = 'auto', reduce: str | int | None = None, source: int | No...¶
Compact single-panel view of a measurement (used by tiles and :func:compare_fields).
def plot_fit(pred: Any, measurement: Any, *, noise_std: float | None = None, layout: str = 'auto', field_shape: Sequence[int] | None = None, instance: Any = None, domain...¶
Data vs prediction vs residual, with the noise floor.
def plot_frames(data: Any, *, times: Sequence[float] | None = None, n_frames: int = 5, pixels: Sequence[tuple[int, int]] | None = None, shared: bool = False, loglog: bool |...¶
Time-series frames (n_t, H, W) (NeFTY thermograms): a strip of frames (geometric time spacing) and per-pixel decay curves.
def plot_kspace(mask: Any, data: Any = None, *, shift: bool = True, title: str | None = None, dark: bool | None = None) -> Figure¶
k-space sampling mask (and the log-magnitude of the sampled data, if given).
def plot_measurement(measurement: Any, *, layout: str = 'auto', field_shape: Sequence[int] | None = None, instance: Any = None, domain: Any = None, hints: Mapping[str, Any] | No...¶
Full view of a measurement, dispatched on its layout (see the module table).
def plot_signal(data: Any, *, x: Any = None, mask: Any = None, noise_std: float | None = None, title: str | None = None, xlabel: str = 'sample', dark: bool | None = None) -...¶
A 1-D measurement (signal or sensor vector) with an optional ±σ band.
def plot_sinogram(data: Any, *, angles: Sequence[float] | None = None, detector: Sequence[float] | None = None, n_profiles: int = 3, mask: Any = None, title: str | None = Non...¶
Sinogram (n_views, n_detectors): image (angle vertical, detector horizontal) and a few projection profiles.
def plot_spectra(data: Any, *, freqs: Sequence[float] | None = None, n_slices: int = 3, n_pixels: int = 3, domain: Any = None, title: str | None = None, xlabel: str = 'frequ...¶
Spectral stacks (n_freq, H, W) (NeTMY): the noise map Σ_ω S(ω, r), a few frequency slices on a shared scale, and pixel spectra (mean ± std, brightest pixels).
def plot_traces(data: Any, *, source: int | None = None, dt: float | None = None, t0: float = 0.0, mode: str = 'both', max_traces: int = 48, clip: float = 99.0, title: str ...¶
Receiver traces (n_src, n_rec, n_t) of one source: image gather (time downwards, RdBu_r centred) and/or a wiggle plot with filled positive lobes.
def residual_stats(pred: Any, measurement: Any, noise_std: float | None = None) -> dict[str, float | None]¶
Data-fit summary: rmse (masked), noise_std, chi = RMSE/σ (≈ 1 when the fit reaches the noise floor, Morozov) and the relative residual ‖r‖ / ‖y‖.
def resolve_layout(data: Any, meta: Mapping | None, field_shape: Sequence[int] | None, mask: Any, hints: Mapping[str, Any] | None = None) -> str¶
Layout from meta["layout"], then instance hints, then :func:detect_layout.
def stack_axis(shape: Sequence[int], field_shape: Sequence[int] | None, hints: Mapping[str, Any] | None) -> int¶
Slice axis of a 3-D matrix / sinogram measurement (e.g. (n_views, n_det, n_z)).
def unpack(measurement: Any) -> tuple[np.ndarray, np.ndarray | None, dict, float | None]¶
(data, mask, meta, noise_std) from a :class:~nefi.measurement.Measurement, a tensor or an array.
nefi.viz.multiphysics¶
The multi-physics gallery: one smoke run per registered instance, one compact tile per physical system (GT | measurement | reconstruction, headline metric and wall-clock), a single overview figure, per-instance figures and a JSON manifest.
class GalleryEntry(name: str, status: str = 'pending', description: str = '', scene_class: str | None = None, smoke: str | None = None, config: dict[str, Any] = <factory>, bud...¶
Manifest entry of one physical system (JSON-serializable except run).
headline(self) -> tuple[str, float] | None—(metric, value)shown on the tile.ok(property)to_dict(self) -> dict[str, Any]
class GalleryManifest(...)¶
The JSON manifest (a dict) plus the in-memory :class:GalleryEntry list (.entries, with .run artifacts when keep_runs=True).
class GalleryRun(instance: Any, info: dict[str, Any], gt: dict[str, Any] | None, measurement: Any, problem: Any, result: Any, stage_snapshots: Any = None, field_snapshots: A...¶
In-memory artifacts of one gallery run (not serialized).
class TileData(name: str | None, label: str, note: str, g: np.ndarray | None, rec: np.ndarray, mask: np.ndarray | None, spec: Any, hints: dict[str, Any], domain: Any)¶
The arrays a tile shows (after the instance's display hints).
titles(self) -> tuple[str, str]volume(property)
def display_field(run: GalleryRun, result: Any, td: TileData) -> np.ndarray¶
result's primary field as the tile shows it: on the GT grid, complex → magnitude, the instance's field_transform applied (like :func:tile_data's reconstruction).
def draw_tile(container: Any, entry: GalleryEntry)¶
Draw one tile (GT | measurement | reconstruction) into a figure or sub-figure.
def draw_volume_block(container: Any, entry: GalleryEntry, *, n_slices: int = 8)¶
One system of gallery_3d.png: larger GT and reconstruction depth mosaics (GT outlined on the reconstruction), multi-level contours of GT (solid) and reconstruction (dashed) on the central slice and the depth cross-section, and shaded isosurfaces — the GT at its threshold rule (the instance's IoU rule), the reconstruction at the volume-matched level (as many voxels as the GT; same camera; levels, IoU and Dice in the titles, with the IoU at the GT's own threshold for comparison). A volume_transform display hint is applied to the reconstruction's contours and isosurface and named in the titles.
def draw_volume_tile(container: Any, entry: GalleryEntry, *, n_slices: int = 6)¶
The gallery row of a 3-D system (full overview width).
def entry_rule(run: GalleryRun, td: TileData | None = None) -> dict[str, Any]¶
The GT threshold rule of a 3-D gallery run: the instance's IoU rule (:func:~nefi.viz.isosurface.voxel_rule) — or, after a display transform of the field, half-way from the GT background to its extreme.
def gallery_sections(manifest: Mapping[str, Any], out_dir: str | Path, include: Sequence[str] | None = ('compare', 'measurement', 'fit', 'history', 'multiscale', 'mosaic', 'voxe...¶
Report sections of a gallery: overview + summary table, the 3-D systems (:func:volume_section), then one section per system.
def has_refined(entry: GalleryEntry) -> bool¶
True when the entry carries a refined (or refused-candidate) field to draw.
def instance_figures(entry: GalleryEntry, out_dir: str | Path, *, formats: Sequence[str] = ('png',), dpi: float = 130, max_kb: float | None = 300, animate: bool = False, dark: b...¶
Write the standard figures of one gallery entry into out_dir/<name>/.
def is_volume_entry(entry: GalleryEntry) -> bool¶
True for a successful entry whose primary field has three (non-singleton) dimensions.
def iso_rows(manifest: Mapping[str, Any]) -> list[dict[str, Any]]¶
One row per 3-D system: the reconstruction's level, IoU and Dice at the GT threshold and at the volume-matched level (and Otsu's IoU) — from the manifest's iso entries.
def iso_summary(entry: GalleryEntry) -> dict[str, Any]¶
Level-set comparison of a 3-D entry (raw fields, no display transform): the GT threshold rule and, for the reconstruction, the level, voxel count, IoU and Dice at the GT threshold (fixed), at the volume-matched level and at Otsu's level (:func:~nefi.viz.isosurface.iso_levels); refined: the same for the refined field. {} without a ground truth.
def meta_mask(measurement: Any, shape: Sequence[int]) -> np.ndarray | None¶
A field-shaped mask from measurement.meta (:data:MASK_KEYS), else None.
def physics_gallery(instances: Any = None, budget_scale: float = 0.15, device: str = 'auto', out_dir: str | Path = 'runs/gallery', *, seed: int = 0, smoke: bool = True, max_ste...¶
Run every available instance at a small budget and draw the multi-physics gallery.
def physics_overview(entries: Sequence[GalleryEntry], *, ncols: int = 3, title: str | None = None, dark: bool | None = None) -> Figure¶
One figure with a tile per physical system (failed systems show their error).
def physics_volumes(entries: Sequence[GalleryEntry], *, n_slices: int = 8, title: str | None = None, dark: bool | None = None) -> Figure | None¶
gallery_3d.png: one block per 3-D system (larger depth mosaics of GT and reconstruction, contrast contours and side-by-side isosurfaces at matched levels, :func:draw_volume_block); None when no entry is volumetric.
def refine_entry(entry: GalleryEntry) -> dict[str, Any]¶
Edge refinement of a 3-D gallery entry (nefi.solve.refine_run_output, see docs/refinement.md); never raises.
def refine_line(refine: Mapping[str, Any], width: int | None = None) -> str¶
"refined ✓ IoU 0.59 → 0.82 · Edge-F1 0.42 → 1 · χ 1.15 → 1.10" (tile titles).
def refine_rows(manifest: Mapping[str, Any]) -> list[dict[str, Any]]¶
One row per refined 3-D system: verdict, mode, data fit, IoU and Edge-F1 before → after, the refined field's volume-matched IoU and the cost — from the manifest's refine.
def refined_view(run: GalleryRun, td: TileData) -> tuple[np.ndarray, str] | None¶
(array, label) of the "refined" column of a 3-D run (None without refinement): "refined", or "refined — refused" for the refused candidate (the smooth result is kept).
def run_instance_smoke(spec: Any, *, budget_scale: float = 0.15, device: str = 'auto', seed: int = 0, smoke: bool = True, max_steps: int | None = 1500, min_steps: int = 20, time_b...¶
Generate → invert → evaluate one instance at a demo budget; never raises.
def summary_rows(entries: Sequence[GalleryEntry]) -> list[dict[str, Any]]¶
One table row per system: status, scene, grid, steps, timings, headline metrics.
def tile_data(run: GalleryRun) -> TileData¶
Primary field of a gallery run (GT and reconstruction on the GT grid), with the instance's field_transform / field_label / field_cmap hints applied; complex fields are shown by magnitude.
def tile_figure(entry: GalleryEntry, dark: bool | None = None) -> Figure¶
A stand-alone figure with one tile (a full-width row for 3-D systems).
def tile_title(entry: GalleryEntry) -> str¶
name + a second line with the headline metric (the smooth result's), wall-clock and steps + (3-D systems with refine) a third line: the refinement's verdict, IoU and Edge-F1 before → after and the data fit χ before → after (:func:refine_line).
def volume_block_figure(entry: GalleryEntry, *, n_slices: int = 8, dark: bool | None = None) -> Figure¶
One 3-D system's block of gallery_3d.png as its own figure (<name>/block3d.png: the static row shown above the system's interactive viewer in reports).
def volume_extras(entry: GalleryEntry, out_dir: str | Path, kind: str | None = 'canvas', *, formats: Sequence[str] = ('png',), dpi: float = 130, max_kb: float | None = 300)¶
3-D extras of a gallery entry: the level-set comparison (entry.iso) and, with an interactive kind, the static row <name>/block3d.png plus the viewer files (entry.viewer, :func:~nefi.viz.interactive.write_entry_viewer). Never raises.
def volume_section(manifest: Mapping[str, Any], out_dir: str | Path, *, interactive: bool = True, height: int = 420) -> Any¶
The "3-D systems" report section: with interactive and viewer files, one subsection per 3-D system — its static row (block3d.png) and right under it the interactive viewer (script and stylesheet included once) — else gallery_3d.png; the level table (:func:iso_rows) either way. None without 3-D systems.
nefi.viz.performance¶
Performance dashboards: per-step time, scaling with grid size, memory by gradient mode, wall-clock breakdowns and benchmark tables with confidence intervals.
def aggregate(rows: Any, metric: str, by: str = 'method', group: str | None = None, ci: float = 0.95) -> list[dict[str, Any]]¶
Mean ± CI of metric per by (and group) over rows without errors.
def collect_performance(instances: Any = None, device: Any = 'auto', steps: int = 20, *, warmup: int = 3, stage: int = -1, smoke: bool = True, overrides: Mapping[str, Mapping[str, ...¶
Profile the optimization step of several instances (rows for the plots above).
def collect_scaling(instance: Any, sizes: Sequence[Any], *, key: str | None = None, device: Any = 'auto', steps: int = 10, warmup: int = 2, stage: int = -1, smoke: bool = True,...¶
Profile one instance at several sizes (rows for :func:plot_scaling).
def load_profiles(source: Any = 'runs/_perf') -> list[dict[str, Any]]¶
Rows of tools/profile_instance.py --json files.
def load_rows(source: Any) -> list[dict[str, Any]]¶
Rows from a list of dicts, a BenchmarkResult / RuntimeTable (.rows), a dict with rows (benchmark.json) or entries (gallery manifest.json), or a path to a .json / .csv file or a directory containing one of them.
def loglog_slope(x: Sequence[float], y: Sequence[float]) -> float¶
Least-squares slope of log y vs log x (nan with < 2 positive points).
def normalize_row(r: Mapping[str, Any]) -> dict[str, Any]¶
Harmonize aliases and derive n / ms_per_step / fwd_ms where possible.
def plot_bench_table(rows: Any, metric: str, *, by: str = 'method', group: str | None = 'class', ci: float = 0.95, higher_is_better: bool | None = None, title: str | None = None...¶
Mean ± confidence interval of metric per method (dots with CI whiskers), one small multiple per scene class.
def plot_memory(rows: Any, *, by: str = 'shape', hue: str = 'mode', value: str = 'auto', title: str | None = None, dark: bool | None = None) -> Figure¶
Memory per gradient mode (e.g. adjoint vs autograd vs checkpoint) and grid size.
def plot_scaling(rows: Any, *, x: str = 'n', y: Sequence[str] = ('ms_per_step', 'memory'), by: str = 'instance', fit: bool = True, reference: bool = True, title: str | None ...¶
Step time and memory vs grid size, log-log, with fitted slopes (O(N^slope)).
def plot_speedup(rows: Any, *, title: str | None = None, dark: bool | None = None) -> Figure¶
Per-instance "speedup vs eager" bars (log axis, 1× = eager, value at every tip).
def plot_step_time(rows: Any, *, value: str = 'ms_per_step', by: str = 'instance', hue: str = 'device', split: bool = True, log: bool | str = 'auto', shapes: bool = True, titl...¶
Per-step time per instance (horizontal bars, value at every bar tip).
def plot_wallclock_breakdown(results: Any, *, labels: Sequence[str] | None = None, title: str | None = None, dark: bool | None = None) -> Figure¶
Stacked horizontal bars of where the wall-clock went, one bar per run.
def profile_problem(problem: Any, stage: Any, *, device: Any = 'auto', steps: int = 20, warmup: int = 3, saved_tensors: bool = True) -> dict[str, Any]¶
Time optimization steps of one curriculum stage (forward / backward / optimizer split).
def profile_speedups(rows: Any) -> list[dict[str, Any]]¶
Speedup of every accelerated profile over plain eager execution.
def profile_variant(row: Mapping[str, Any]) -> str¶
"eager" for a plain solver-loop profile, else a short label of its switches ("compile=step", "autocast=bf16", "solver=chebyshev · jacobi_iters=13", ...).
def shape_label(shape: Any) -> str¶
"64×64×16" from a shape list / string.
nefi.viz.qualitative¶
Qualitative comparison figures: the scenes × methods grid of a paper, failure-mode panels and a one-call baselines panel.
def axis_excess(err: np.ndarray) -> float¶
Cross / streak-artifact indicator of an error map.
def baselines_panel(instance: Any, measurement: Any = None, gt: Mapping[str, Any] | None = None, methods: Any = None, budget_scale: float = 0.1, *, device: str = 'cpu', seed: i...¶
Run the instance's method and its baselines() at a small budget and draw the grid.
def failure_modes(gt: Any, recons: Any, *, field: str | None = None, support_threshold: float = 0.05, dilate: int = 1, spectrum: bool = True, title: str | None = None, dark: ...¶
Residual maps that expose failure modes, one row per method.
def failure_stats(pred: Any, gt: Any, *, support_threshold: float = 0.05, dilate: int = 1) -> dict[str, float]¶
Failure-mode numbers of a reconstruction.
def method_grid(rows: Sequence[Mapping[str, Any]], row_labels: Sequence[str] | None = None, col_labels: Sequence[str] | None = None, *, field: str | None = None, gt_key: st...¶
The classic qualitative figure: scenes (rows) × methods (columns).
def run_methods(instance: Any, measurement: Any = None, gt: Mapping[str, Any] | None = None, methods: Any = None, budget_scale: float = 0.1, *, device: str = 'cpu', seed: i...¶
Run the instance's own method and baselines on one measurement at a small budget.
nefi.viz.report¶
Shareable reports: one self-contained HTML file (figures embedded as base64, metrics and timing tables, config hash, environment) or a Markdown page with relative image links.
class Section(title: str, text: str = '', images: list[Any] = <factory>, table: Sequence[Mapping[str, Any]] | None = None, columns: Sequence[str] | None = None, html: str...¶
One report section.
def environment_info(device: Any = None) -> dict[str, Any]¶
Versions, platform and accelerator info for reproducibility sections.
def fmt_value(v: Any, precision: int = 4) -> str¶
Compact cell text: numbers to precision significant digits, NaN/None → —.
def html_report(out_dir: str | Path, title: str, sections: Sequence[Section | Mapping[str, Any]], *, filename: str = 'index.html', subtitle: str | None = None, config_hash:...¶
Write a self-contained HTML report and return its path.
def html_table(rows: Sequence[Mapping[str, Any]], columns: Sequence[str] | None = None, precision: int = 4) -> str¶
HTML table (numbers right-aligned, tabular figures; status cells get a ✓ / ✗ glyph).
def markdown_report(out_dir: str | Path, title: str, sections: Sequence[Section | Mapping[str, Any]], *, filename: str = 'report.md', subtitle: str | None = None, config_hash: ...¶
Write a Markdown report (relative image links; figures objects are saved next to it).
def markdown_table(rows: Sequence[Mapping[str, Any]], columns: Sequence[str] | None = None, precision: int = 4) -> str¶
GitHub-flavoured markdown table.
def slug(text: str) -> str¶
URL-fragment slug of a heading.
def write_json(path: str | Path, obj: Any) -> Path¶
JSON writer tolerant of tensors, tuples, paths and non-finite floats.
nefi.viz.style¶
House style for nefi figures: palette, per-quantity colormaps, rc settings, sizes, saving.
class CmapSpec(cmap: str, kind: str = 'sequential', quantity: str = 'generic')¶
A colormap choice: matplotlib name, kind and the quantity it was chosen for.
centered(property)
class Theme(name: str, surface: str, page: str, ink: str, ink2: str, muted: str, grid: str, axis: str, bad: str, palette: tuple[str, ...])¶
Surface / ink tokens and the categorical palette of one color mode.
color(self, i: int) -> str— Categorical sloti(0-based).
def blank_axes(ax: Axes, frame: bool = True)¶
Hide ticks and tick labels of an image panel; keep a hairline frame (frame=True) so panels whose values sit at the surface color (diverging midpoint) keep visible edges.
def close_figure(fig: Figure)¶
Close a figure if it is managed by pyplot (never imports pyplot itself).
def cmap_for(name: str | None = None, data: Any = None, quantity: str | None = None) -> CmapSpec¶
Choose the colormap for a field.
def color_limits(arrays: Sequence[Any] | Any, spec: CmapSpec | None = None, robust: float | None = None) -> tuple[float, float]¶
Shared (vmin, vmax) of one or several arrays for a colormap spec.
def current_context() -> str¶
Active size context ("paper", "notebook" or "talk").
def figsize(ncols: int = 1, nrows: int = 1, *, panel: tuple[float, float] | None = None, cbar: bool | int = False, title: bool = False, context: str | None = None, max_...¶
Figure size (inches) for a grid of nrows × ncols panels.
def figure_to_png_bytes(fig: Figure, dpi: float = 110) -> bytes¶
Render a figure to PNG bytes (for embedding).
def format_metric(name: str, value: Any, precision: int = 3) -> str¶
Compact name value label for panel titles (PSNR 24.1 dB, SSIM 0.912).
def get_cmap(spec: CmapSpec | str, dark: bool | None = None)¶
matplotlib colormap for a spec, with the theme's color for masked (NaN) pixels.
def grid_on(ax: Axes, axis: str = 'y')¶
Hairline solid gridlines on axis ("x", "y" or "both"), below the data.
def is_signed(data: Any, min_fraction: float = 0.1) -> bool¶
True when data has a genuine negative and positive part (min < 0 < max beyond noise).
def message_axes(ax: Axes, text: str, title: str | None = None, error: bool = False)¶
Replace an axes by a centered text message (missing data, failed run).
def new_figure(nrows: int = 1, ncols: int = 1, *, figsize: tuple[float, float] | None = None, squeeze: bool = False, layout: str | None = 'constrained', **subplots_kw: Any...¶
A pyplot-free figure (safe on headless servers) and its axes grid.
def note(ax: Axes, text: str, loc: str = 'upper left', fontsize: float | None = None)¶
Small secondary-ink annotation inside an axes.
def palette(dark: bool | None = None) -> tuple[str, ...]¶
The eight categorical colors of the active (or requested) theme.
def panel_size(context: str | None = None) -> tuple[float, float]¶
Default (width, height) of one image panel in inches.
def paper_figsize(columns: int = 1, aspect: float = 0.75) -> tuple[float, float]¶
Journal figure size: one or two columns wide, height = aspect × width.
def plain_log_ticks(ax: Axes, axis: str = 'both')¶
Readable ticks on log axes spanning fewer than two decades: 1-2-5 steps printed as plain numbers (20, 50) instead of 2×10¹ or no label at all.
def primary_metric(metrics: Mapping[str, Any] | None) -> tuple[str, float] | None¶
The headline (name, value) of a metrics dict (PSNR > SSIM > HF1 > rel.err > ...).
def quantity_of(name: str | None) -> str | None¶
Physical quantity guessed from a field name ("rho" → "density") or None.
def savefig(fig: Figure, path: str | Path, formats: Sequence[str] = ('png',), dpi: float = 130, *, close: bool = True, max_kb: float | None = 300, min_dpi: float = 55) ...¶
Save a figure as PNG and optionally SVG / PDF (parent directories are created).
def series_colors(n: int, dark: bool | None = None) -> list[str]¶
Colors for n series in slot order. More than eight series must be folded first.
def set_default_style(dark: bool = False, context: str = 'notebook')¶
Process-wide default theme / context used when no :func:use_style block is active.
def spec_from_hint(value: Any, data: Any = None, quantity: str | None = None) -> CmapSpec | None¶
A colormap from a display hint (measurement_cmap / field_cmap).
def style_rc(dark: bool | None = None, context: str | None = None) -> dict[str, Any]¶
matplotlib rcParams of the house style for a theme and size context.
def styled(dark: bool | None = None) -> Iterator[Theme]¶
Apply the house style for one plotting call.
def theme(dark: bool | None = None) -> Theme¶
The active theme (dark=None) or the light / dark theme explicitly.
def use_style(dark: bool = False, context: str = 'notebook', **rc: Any) -> Iterator[Theme]¶
Context manager applying the house style (light or dark) and size context.
nefi.viz.training¶
Training-dynamics figures: loss history with stage boundaries and the annealing schedule, per-stage summaries, the coarse→fine multiscale view and snapshot animations.
class StageSnapshots(names: Sequence[str] | None = None)¶
Keep detached CPU copies of every field at the end of each curriculum stage.
on_stage_end(self, solver: Any, stage_idx: int, stage: Any, info: dict)on_step(self, solver: Any, state: Any)
def animate_snapshots(snapshots: Any, path: str | Path, *, gt: Any = None, result: Any = None, field: str | None = None, fps: float = 8.0, max_frames: int = 40, dpi: float = 72, ...¶
Animate field snapshots (GIF, or MP4 when ffmpeg is available).
def history_arrays(history: Any, stage_results: Sequence[Mapping] | None = None) -> dict[str, np.ndarray]¶
Per-step numpy columns of Result.history (or a history dict), all of equal length.
def loss_keys(arrays: Mapping[str, np.ndarray]) -> list[str]¶
Loss-valued columns (everything but bookkeeping), in history order.
def plot_history(result: Any, *, keys: Sequence[str] | None = None, noise_floor: float | None = None, noise_std: float | None = None, logy: bool | str = 'auto', show_progres...¶
Loss history with curriculum stage boundaries, annealing windows, β/K and LR panels.
def plot_multiscale(result: Any, snapshots: Any = None, *, gt: Any = None, field: str | None = None, history: bool = True, title: str | None = None, dark: bool | None = None) -...¶
Coarse→fine view of a multiscale curriculum.
def plot_stage_summary(result: Any, *, title: str | None = None, dark: bool | None = None) -> Figure¶
Per-stage bars: steps, wall-clock seconds (ms/step at the bar tip) and final data loss.
def snapshot_list(snapshots: Any, field: str | None = None) -> list[tuple[int, np.ndarray]]¶
[(global_step, array)] from a :class:~nefi.solve.callbacks.FieldSnapshots / :class:StageSnapshots callback, their .snapshots list, (step, tensor) pairs or bare tensors.
nefi.viz.volume¶
3-D field views: depth mosaics, cross-sections through the anomaly, projections and voxel comparisons — the building blocks of the 3-D layout of :func:~nefi.viz.compare_fields, the gallery's 3-D rows and gallery_3d.png.
class Outline(vol: np.ndarray, levels: list[float], mask: bool = False)¶
What is outlined on reconstruction panels: a GT mask (level 0.5) or the GT anomaly level set (:func:~nefi.viz.fields.anomaly_levels).
of(gt: Any = None, mask: Any = None) -> Outline | Noneprojection(self, axis: int, mode: str, max_fraction: float = 0.2) -> np.ndarray | None— The outlined quantity projected alongaxis—Nonefor mean projections and for extended anomalies (covering more thanmax_fractionof the projection, e.g. a skull or a filament network), whose projected outline would only add clutter.section(self, center: Sequence[int], which: int, axis: int) -> np.ndarrayslice(self, k: int, axis: int) -> np.ndarray
def anomaly_summary(vol: Any, mask: Any = None) -> dict[str, Any]¶
Centroid, background and projection side of a volume (for titles and reports).
def compare_volume(ctx: Comparison) -> Figure¶
The 3-D layout of :func:~nefi.viz.compare_fields.
def depth_label(k: int, n: int, axis: int, domain: Any = None, compact: bool = False) -> str¶
"z = 0.417" (physical, with a domain) or "z 3/6" (1-based slice number).
def draw_projection(ax: Axes, vol: np.ndarray, *, axis: int = -1, mode: str = 'auto', reference: Any = None, spec: CmapSpec, vmin: float | None = None, vmax: float | None = Non...¶
A min / max / mean projection along the volume axis (auto: the anomaly side of reference), outlined with the GT footprint when outline is given.
def draw_sections(axes: Sequence[Axes], vol: np.ndarray, center: Sequence[int], *, axis: int = -1, spec: CmapSpec, vmin: float, vmax: float, domain: Any = None, outline: Outl...¶
The two depth cross-sections through center (x–z and y–z for axis=-1), depth pointing down, a + at the centroid; outlines as in :func:draw_slices. square draws them in square boxes (the depth axis is stretched to the slice size, so thin slabs stay readable next to the mosaic).
def draw_slices(axes: Sequence[Axes], vol: np.ndarray, idx: Sequence[int], *, axis: int = -1, spec: CmapSpec, vmin: float, vmax: float, domain: Any = None, outline: Outline...¶
Depth slices idx of vol into axes (shared colour limits).
def draw_voxels(axes: Sequence[Axes], entries: Sequence[tuple[str, np.ndarray]], *, name: str | None = None, reference: np.ndarray | None = None, threshold: float | None = ...¶
Thresholded voxels of every entry into projection="3d" axes with one threshold (from reference, default the first entry), one colour scale and one camera; titles give the voxel count and the IoU with the reference voxel set. Returns the first scatter (for a shared colorbar) or None.
def label_inside(ax: Axes, text: str, loc: str = 'upper left')¶
A small white label with a dark halo inside an image panel (depth of a mosaic slice).
def mosaic_shape(k: int, max_cols: int | None = None) -> tuple[int, int]¶
(rows, cols) of a mosaic of k slices: one row up to 3, 2×2 for 4, two rows up to 8, then square-ish.
def mosaic_slices(n: int, max_slices: int = 6) -> list[int]¶
Up to max_slices evenly spaced slice indices along an axis of length n.
def project(vol: np.ndarray, axis: int = -1, mode: str = 'auto', reference: Any = None) -> tuple[np.ndarray, str]¶
Projection along axis: "max", "min", "mean" or "auto" (the anomaly side of reference — default vol — :func:projection_mode). Returns (array, mode).
def projection_mode(ref: Any, background: float | None = None) -> str¶
"min" when the anomalies of ref lie below the background (low-diffusivity defects), "max" otherwise (sources, absorbers, densities).
def section(vol: np.ndarray, center: Sequence[int], which: int, axis: int = -1) -> tuple[np.ndarray, int, int]¶
Cross-section containing the volume axis through center.
def section_extent(shape: Sequence[int], domain: Any, lateral: int, depth: int) -> tuple[float, float, float, float]¶
imshow extent of a cross-section drawn with origin="upper" (depth grows down).
def voxel_compare(gt: Any, recons: Any = None, *, field: str | None = None, threshold: float | None = None, mode: str = 'auto', domain: Any = None, elev: float = 24.0, azim: ...¶
Ground truth and reconstruction(s) as thresholded voxels, side by side.
def voxel_sets(g: np.ndarray, a: np.ndarray, mode: str, threshold: float) -> tuple[int, float]¶
(voxels of a past the threshold, IoU with the GT voxel set).