Show3DSlices#
Linked top and arbitrary-angle side cuts through a 3D volume. See the Show3DSlices tutorial.
Viewer UI#
Show3DSlices supports the shared ui_mode, show_title, show_controls,
controls_collapsed, show_stats, show_crosshair, and show_scale_bar
names. The saved-state scale-bar trait remains scale_bar_visible for
compatibility. See Viewer UI controls.
Reference#
- class quantem.widget.show3dslices.Show3DSlices(*args: Any, **kwargs: Any)#
Bases:
AnyWidgetLinked top-slice and oblique vertical slice viewer for 3D volumes.
Renders an XY slice plus one arbitrary-angle vertical plane through a
(nz, ny, nx)volume in linked canvases with synchronized context, optional FFT, and playback over depth or plane position. Pass a 4D array of shape(panel, nz, ny, nx)to compare several volumes with one panel selector while preserving the same slice, side-plane, contrast, and camera controls. Designed for multislice ptychography reconstructions and other small-to-medium 3D volumes where the operator wants to scrub through depth while marching an angled plane through lateral regions. The raw volume data is sent once over the Jupyter Comm channel and re-sliced in JS for each scrubber update.Features#
Linked XY plus arbitrary-angle vertical slice canvases
Comparable volume pages with shared slice geometry and page playback
Playback over Z slice, oblique plane position, or both
Adjustable oblique endpoints, angle, and perpendicular position bounds
Log scale, percentile auto-contrast, manual
vmin/vmaxPer-plane statistics (opt-in via
show_stats)Anisotropic scale bars via
pixel_size_axes(e.g. nz << nxy multislice)Depth-axis
z_stretchfor non-cubic volumes (CSS scaling, zero memory)panel_width_pxconstructor sizing for compact or wide panel layoutsDisplay-only global slice post-alignment with Auto/manual row/col slopes
FFT panel with optional Hann window for the active plane
PNG / PDF / TIFF single-slice export with plane and index selection
JSON state save/load via
state_dict/load_state_dict/saveExplicit
freeto release RAM held by traitlets observers
Config Contract#
The
configargument is an explicit QuantEM reconstruction convenience, not a general-purpose transform registry. It accepts either a parsedconfig.jsonmapping or a path to that JSON file. Show3DSlices reads only the following keys:reconstruction.slice_thickness_Aandreconstruction.obj_sampling_A_per_pxforpixel_sizewhenpixel_sizeis not provided.data.rotation_degforrotation_degwhenrotation_degis not provided andapply_config_transformsis True.object.cropped_shapefor a centered post-rotation crop whenpost_cropis not provided andapply_config_transformsis True. If that key is absent, it falls back toreconstruction.obj_padding_pxand theninput.padding.
Explicit constructor arguments always win over config-derived values. To use only config sampling metadata, pass
apply_config_transforms=False. To force no config rotation or post-crop while still leaving transforms enabled, passrotation_deg=0and/orpost_crop=0explicitly.The spatial transform order is fixed and intentionally visible:
crop->padding->rotation_deg->post_crop. The resulting float32 volume is then sent to the browser. No hidden JS-side rotation, crop, or precision-changing transform is applied fromconfig.- param data:
3D array of shape
(nz, ny, nx)or 4D array of shape(panel, nz, ny, nx). Also accepts a quantemDataset3d(uses.arrayand.samplingautomatically). A 5D array uses shape(page, panel, nz, ny, nx). A 4D stack becomes one-volume pages whenpage_labelsis provided; withoutpage_labelsit retains the legacy multi-panel meaning.- type data:
array_like
- param data_b:
Back-compatible two-panel shortcut. When provided,
dataanddata_bmust be matching 3D volumes and the frontend exposes a panel selector.- type data_b:
array_like, optional
- param title:
Title displayed above the viewer.
- type title:
str, optional
- param panel_titles:
Per-panel labels for 4D input or
data_bcomparison. Length must match the number of panels. For 5D pages, pass one title per panel slot or one title per flattened panel.- type panel_titles:
sequence of str, optional
- param page_labels:
Labels for comparable volumes/pages. Page switching keeps the same top/side slice geometry, zoom, and display controls for direct depth comparison.
- type page_labels:
sequence of str, optional
- param ui_mode:
Shared viewer UI preset. Explicit
show_*keyword arguments override preset values.- type ui_mode:
{“interactive”, “presentation”, “report”, “minimal”}, default “interactive”
- param show_title:
Show the top title row.
- type show_title:
bool, default True
- param cmap:
Colormap name. One of the project’s valid colormaps (
"inferno","viridis","magma","gray","plasma", …).- type cmap:
str, default “plasma”
- param sampling:
Voxel sampling for the scale bars. Pass a scalar for isotropic data, or a 3-tuple (pz, py, px) for anisotropic data (e.g. multislice ptycho with z-thickness >> xy-sampling). Pairs with
units;nmis converted to Å. Matches the quantemDataset/Show2D/Show4DSTEMconvention.- type sampling:
float or sequence of 3 floats, optional
- param units:
Unit(s) for
sampling(e.g."A","nm"). One value applies to all axes; a sequence sets each axis.- type units:
str or sequence of str, optional
- param pixel_size:
Back-compatible scale-bar sampling in Å/pixel. Prefer
samplingandunitsfor new code. A 3-tuple is interpreted as(pz, py, px).- type pixel_size:
float or sequence of 3 floats, optional
- param config:
Parsed QuantEM reconstruction
config.jsondata, or a path to it. This is only used for the keys listed in “Config Contract” above. It can infer sampling metadata, scan-alignment rotation, and post-rotation FOV crop, but explicit constructor arguments override every inferred value.- type config:
mapping or path-like, optional
- param apply_config_transforms:
If True, use config-derived
rotation_degandpost_croponly when those arguments are omitted. If False,configmay still fillpixel_sizebut will not rotate or crop the volume.- type apply_config_transforms:
bool, default True
- param crop:
Spatial crop applied before padding and rotation. Use an int to crop all sides,
(rows, cols)for symmetric row/column cropping, or(top, bottom, left, right)for side-specific cropping.- type crop:
int or tuple[int, int] or tuple[int, int, int, int], default 0
- param padding:
Spatial padding applied after crop and before rotation. This mirrors Show3D and is useful when rotating a scan-aligned view without clipping real signal at the canvas edge.
- type padding:
int or tuple[int, int], default 0
- param pad_mode:
Padding fill mode.
"median"uses a single stack median so borders are contrast-neutral;"constant"fills with 0.- type pad_mode:
{“median”, “constant”}, default “median”
- param rotation_deg:
In-plane row/column rotation in degrees, applied after crop/padding. If omitted and
configis provided, usesdata.rotation_degfrom the config; otherwise defaults to 0. Uses built-in float32 bilinear interpolation with nearest-edge fill, no SciPy dependency, and keeps the output shape fixed.- type rotation_deg:
float, optional
- param post_crop:
Spatial crop applied after rotation. If omitted and
configis provided, usesobject.cropped_shapeor reconstruction padding from the config; otherwise defaults to 0.- type post_crop:
int or tuple[int, int] or tuple[int, int, int, int], optional
- param show_stats:
Compute per-slice statistics traits on each slice change (widget.stats_mean, stats_min, stats_max, stats_std, each a legacy list of 3 floats). Python-side only; the JS widget does not render a stats bar. Set False to skip 12 reductions per slice scrub on multi-MB volumes when you don’t need the values.
- type show_stats:
bool, default False
- param show_controls:
Show secondary controls for color, colorbar, smoothing, crosshair, z-stretch, contrast, and playback. The slice toolbar keeps only FFT and Reset Zoom visible.
- type show_controls:
bool, default True
- param controls_collapsed:
Start with controls hidden while keeping a recoverable
Controlsbutton in the frontend.- type controls_collapsed:
bool, default False
- param show_crosshair:
Show slice intersection guides across orthogonal panels.
- type show_crosshair:
bool, default True
- param show_fft:
Toggle FFT panel for the active plane.
- type show_fft:
bool, default False
- param fft_window:
Apply a 2D Hann window to each displayed slice before FFT. Useful for suppressing edge leakage/streaking in reciprocal-space panels.
- type fft_window:
bool, default False
- param log_scale:
Use signed log1p for intensity mapping.
- type log_scale:
bool, default False
- param auto_contrast:
Use percentile-based contrast (2nd-98th). On for ptycho phase data (long-tailed histogram - manual contrast usually crushes the signal).
- type auto_contrast:
bool, default True
- param vmin:
Manual contrast limits.
- type vmin:
float, optional
- param vmax:
Manual contrast limits.
- type vmax:
float, optional
- param slice_alignment:
Display-only global post-alignment mode.
"auto"estimates one row/col shift-per-slice slope from adjacent slice registration when no slopes are provided;"manual"applies the provided slopes directly. The raw volume is not modified.- type slice_alignment:
{“off”, “auto”, “manual”}, default “off”
- param row_shift_px_per_slice:
Global display shift applied per slice relative to the middle slice, using the project-wide row/col convention. Positive row shifts move deeper slices down; positive col shifts move them right.
- type row_shift_px_per_slice:
float, default 0.0
- param col_shift_px_per_slice:
Global display shift applied per slice relative to the middle slice, using the project-wide row/col convention. Positive row shifts move deeper slices down; positive col shifts move them right.
- type col_shift_px_per_slice:
float, default 0.0
- param fps:
Playback speed when scrubbing one axis, capped at 30.
- type fps:
float, default 30.0
- param play_axis:
Which control to animate (0=slice/Z, 1=oblique plane position, 3=both). Legacy saved states with 2 are mapped to 1.
- type play_axis:
int, default 0
- param dim_labels:
Labels for data axes 0, 1, 2 in that order. Default [“slice”, “row”, “col”] matches the project-wide detector-plane convention (axis 0 = multislice depth, axis 1 = row, axis 2 = col). Pass any 3-string list to override.
- type dim_labels:
list of str, optional
- param offline:
Pack
volume_bytesas uint8 plus global min/max metadata for static nbconvert HTML reports. Leave False for live notebooks that need exact float32 values in the browser.- type offline:
bool, default False
Example
Instantiate Show3DSlices on a multislice ptycho object, scrub through depth, and export a slice to PNG:
>>> import numpy as np >>> from quantem.widget import Show3DSlices >>> volume = np.random.rand(14, 256, 256).astype(np.float32) >>> w = Show3DSlices(volume, title="multislice object", cmap="viridis", ... sampling=(2.0, 0.2, 0.2), units="A", z_stretch=8) >>> w.play() >>> w.save_image("xy_slice7.png", plane="xy", slice_idx=7)
Notes
The raw volume data is sent once over the Comm channel; subsequent slice moves, page changes, and panel switches only ship trait updates, not the data.
One volume is active at a time so every page reuses the same top/side cut, camera, and display state. For simultaneous side-by-side 3D volume rendering, use
Show3DVolume.Saved states that include
dual_mode/show_diffkeys are still rejected because those imply a different rendering contract.Call
free()before discarding the widget to release RAM pinned by traitlets observers.
- state_dict() dict#
Return a JSON-serializable snapshot of every user-tunable trait.
Captures display config (cmap, log scale, contrast, FFT, orthographic, smooth, flip, crosshair), scale-bar settings (
pixel_size,pixel_size_axes,z_stretch), playback config (fps, loop, reverse, boomerang, play axis), the three slice positions, and the dimension labels. The raw volume data is NOT included; pair the snapshot with the originaldataargument on restore.- Returns:
Mapping of trait name -> serializable value. Suitable for
json.dumpor use withsave/load_state_dict.- Return type:
dict
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume, cmap="viridis") >>> state = w.state_dict() >>> w2 = Show3DSlices(volume) >>> w2.load_state_dict(state)
Notes
Schema versioning is handled inside
save; the dict returned here is the unversioned inner payload.
- collapse_controls() Self#
Collapse controls behind the frontend
Controlsbutton.
- expand_controls() Self#
Expand frontend controls when
show_controlsis enabled.
- toggle_controls() Self#
Toggle whether frontend controls start collapsed.
- set_page(page: int) Self#
Show a zero-based page while preserving the active panel slot.
- next_page() Self#
Advance to the next page, clamped at the final page.
- previous_page() Self#
Move to the previous page, clamped at page zero.
- estimate_slice_alignment(*, panel: int | None = None, apply: bool = True, force: bool = False) dict#
Estimate one global row/col post-alignment slope through the stack.
Adjacent slices are registered after median subtraction, Gaussian high-pass filtering, and Hann windowing. The adjacent shifts are accumulated, then a straight line is fit versus slice index. The fitted slope is the display shift to apply per deeper slice, centered around the middle slice when rendered.
- Parameters:
panel (int or None, optional) – Panel index to estimate for 4D panel stacks. Defaults to the active panel.
apply (bool, default True) – If True, store the fitted slopes in
row_shift_px_per_sliceandcol_shift_px_per_sliceand switchslice_alignmentto"auto".force (bool, default False) – Recompute even when this panel already has a cached estimate.
- Returns:
JSON-serializable diagnostics with fitted shifts, cumulative trajectory, adjacent shifts, fit R² values, and correlation quality.
- Return type:
dict
- reset_slice_alignment() Self#
Turn off post-alignment and discard cached alignment results.
- save(path: str) None#
Write the current widget state to a versioned JSON file.
Wraps
state_dictin a small envelope that records the widget type ("Show3DSlices") and a schema version soload_state_dictcan refuse states that belong to a different widget. The raw volume data is NOT written; only the display / playback / slice configuration.- Parameters:
path (str) – Destination JSON file path. Parent directories must already exist.
- Return type:
None
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume, cmap="viridis", sampling=(2.0, 0.2, 0.2), units="A") >>> w.save("slices_state.json")
Notes
To restore, instantiate
Show3DSliceswith the (possibly different) volume and callw.load_state_dict(json.loads(open(path).read())).
- export_html(path: str | Path | None = None, *, title: str | None = None, mode: str = 'single', encoding: str = 'full', downsample: int | None = None, quantized: bool | None = None) Path#
Write a standalone HTML viewer for sharing.
The exact export embeds the current float32 volume bytes and preserves numerical precision. The quantized export writes the existing offline uint8 representation plus global min/max metadata, which makes a much smaller single-file report for visual sharing. Preferred export options are
mode="single",encoding="full"orencoding="uint8", anddownsample=None.quantizedis kept as a compatibility alias forencoding="uint8".- Parameters:
path (str or pathlib.Path, optional) – Destination HTML path. Defaults to the current working directory with the widget title, volume shape, and export mode in the name.
quantized (bool, default False) – If True, write the uint8 offline pack. If False, write exact float32 bytes.
title (str, optional) – Browser page title. Defaults to the widget title or class name.
- Returns:
The written HTML file.
- Return type:
pathlib.Path
- load_state_dict(state: dict) None#
Apply a saved
state_dictsnapshot to this widget.Restores display, playback, slice, and labeling configuration from a dict produced by
state_dict. States that include the deprecateddual_mode/show_diffkeys are rejected with a hint to useShow3DVolumefor two-volume comparisons. Unknown keys (typically from a newer widget version or a typo) emit aUserWarningand are dropped. Deprecated keys (title_b,linked_contrast,compact) are silently ignored.vmin/vmaxare cleared first so either bound can be set regardless of the current contrast limits. Forward-compat: a saved state with only the scalarpixel_size(nopixel_size_axes) mirrors the scalar across all three axes so depth scale bars stay in sync with the lateral one.- Parameters:
state (dict) – Mapping previously returned by
state_dict(or its on-disk equivalent).- Returns:
Mutates the widget in place.
- Return type:
None
Example
>>> import json >>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume) >>> w.load_state_dict(json.load(open("slices_state.json")))
Notes
Saved files from a different widget type are caught earlier in the
saveenvelope check, not here.
- free() None#
Release RAM held by this widget.
Drops the numpy volume and clears the
volume_bytessync trait, then triggers agc.collect().del widgetalone does NOT free memory: traitlets installs strong observer references that pin the widget’s refcount untilfreeis called.- Returns:
Mutates the widget in place. After this call, the volume is gone and rendering will be blank; rebuild a new widget for further use.
- Return type:
None
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume) >>> w.free()
Notes
Idempotent: calling
freetwice is a no-op.
- summary() None#
Print a one-screen status report for the current widget.
Sections include: title and volume shape (with pixel-size readout when set), current slice positions per axis with the user’s
dim_labels, raw data min/max/mean, and display config (cmap, contrast, log/linear, FFT, Hann window). Useful for notebook reproducibility and bug reports.- Returns:
Prints to stdout.
- Return type:
None
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume, title="multislice") >>> w.summary()
- play() Self#
Start slice playback along the current
play_axis.Sets the
playingtrait toTrue. The JS animation loop scrubs the control selected byplay_axis(0=slice/Z,1=oblique plane position,3=both) atfpsframes per second.- Returns:
The widget, for chaining (
w.play()).- Return type:
Self
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume, fps=10, play_axis=0) >>> w.play()
- pause() Self#
Pause playback at the current slice indices.
Sets
playingtoFalsewithout resettingslice_z/slice_y/slice_x. Per-slice statistics (ifshow_statsis on) are refreshed for the current slice on pause.- Returns:
The widget, for chaining.
- Return type:
Self
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume) >>> w.play().pause()
- stop() Self#
Stop playback and recenter all three slice indices.
Sets
playingtoFalseand resetsslice_z/slice_y/slice_xto the geometric center of the volume (nz // 2etc.). Usepauseto keep the current slice indices.- Returns:
The widget, for chaining.
- Return type:
Self
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume) >>> w.play().stop()
- save_image(path: str | Path, *, plane: str | None = None, slice_idx: int | None = None, format: str | None = None, dpi: int = 150) Path#
Save a single 2D slice of the volume as PNG, PDF, or TIFF.
Extracts the requested axis-aligned slice, colorizes it with the current
cmapand contrast (vmin/vmaxor 2-98 percentile auto-contrast), and writes it topath.log_scaleandflipare honored so the saved file matches what the browser shows for that plane.Plane / index mapping for this legacy export helper:
"xy": slice along Z,slice_idxindexes intonz; defaults to currentslice_z."xz": slice along Y,slice_idxindexes intony; defaults to currentslice_y."yz": slice along X,slice_idxindexes intonx; defaults to currentslice_x.
- Parameters:
path (str or pathlib.Path) – Output file path. Parent directories are created if needed.
plane (str | None, optional) – One of
"xy","xz","yz". Defaults to"xy". The interactive browser UI now exposes Top plus an arbitrary Side plane; this helper keeps the older axis-aligned export names for backwards compatibility.slice_idx (int | None, optional) – Slice index along the chosen axis. Defaults to the current position for that plane.
format (str | None, optional) – One of
"png","pdf","tiff". If omitted, inferred from the file extension; defaults to"png"if no extension. Mismatched extension and explicitformatis allowed: the container written followsformat.dpi (int, default 150) – DPI metadata written into the file.
- Returns:
The written file path.
- Return type:
pathlib.Path
Example
>>> from quantem.widget import Show3DSlices >>> w = Show3DSlices(volume, cmap="viridis") >>> w.save_image("xy_top.png", plane="xy", slice_idx=0) >>> w.save_image("xz_mid.pdf", plane="xz")
Notes
PDF output is converted to RGB internally (no alpha channel).
Slice indices outside the valid range for the chosen plane raise
IndexError; unsupported planes or extensions raiseValueError.
Interactive controls#
Control |
Trait |
Expected effect |
|---|---|---|
Page slider / play |
|
Switches or plays comparable volumes while preserving the same slice geometry and view state |
Panel menu |
|
Selects one panel slot within the active page |
Crosshair drag |
|
Moves the cut position; all panels update together |
Oblique line drag |
|
Drag either endpoint to rotate/resize the side cut, or drag the line body to translate the whole cut freely in row/col while staying inside the top slice |
Oblique angle |
|
Rotates the oblique cut plane |
Colormap dropdown |
|
Recolors all panels |
Contrast min / max |
|
Display clamp changes |
Auto-contrast toggle |
|
Re-fits the percentile range |
Log-scale toggle |
|
Log intensity mapping |
Slice alignment |
|
Open Advanced and enable Slice alignment. The first enable estimates one global row/col shift per slice automatically; later raw/aligned toggles reuse the cached estimate and aligned display volume. The sliders refine the cached result without modifying the raw volume. |
FFT toggle |
|
Panels show power spectra |
Z-stretch |
|
Depth axis scaled for anisotropic voxels |
Scale bar toggle |
|
Calibrated bar shows/hides |
Export button |
|
Writes a standalone HTML viewer (exact / quantized) |
Automatic slice alignment high-pass filters adjacent reconstructed slices with a Gaussian sigma capped at 12 pixels, then refines each translation on a 20x local matrix-DFT grid. The 12-pixel scale is an empirical preprocessing setting, not a physical microscope parameter. The subpixel method follows Guizar-Sicairos, Thurman, and Fienup (2008), DOI 10.1364/OL.33.000156. The resulting row/col trajectory is reduced to one global linear shift per slice. This is reversible display post-processing; it does not add sample tilt to the ptychographic forward model or modify the reconstructed volume.
Compare volumes with pages#
Pass a 4D stack plus page_labels when every page contains one volume. The
same top slice, side cut, oblique angle, zoom, contrast, and playback settings
remain active as the page changes:
# Shape: page, depth, rows, cols
w = Show3DSlices(
np.stack([raw_volume, aligned_volume]),
page_labels=["raw", "aligned"],
panel_titles=["object phase"],
)
Use a 5D array when each page has the same small panel set:
# Shape: page, panel, depth, rows, cols
w = Show3DSlices(
comparison_5d,
page_labels=["single-slice", "multislice"],
panel_titles=["object", "absolute error"],
)
Explicit page dictionaries are also accepted:
w = Show3DSlices([
{"title": "before", "volume": before},
{"title": "after", "volume": after},
])
set_page(), next_page(), and previous_page() provide the same workflow
from Python. Existing 4D calls without page_labels keep their legacy
multi-panel meaning, so saved notebooks do not silently change interpretation.