ShowDiffraction#
Interactive d-spacing analysis for a single 2D diffraction pattern or a 3D
stack (tilt/time series). Find the beam center, pick Bragg spots and rings,
read calibrated d-spacings, and calibrate k-space from a known reflection. See the
ShowDiffraction tutorial for a worked example,
or run quantem showdiffraction <pattern> from the command line for a
one-command analyzed HTML.
The primary phase workflow is candidate verification: you usually know which
phases to expect, so build them (library_phase, Phase.from_cubic,
Phase.from_dspacings, or custom phases in the Phase menu) and rank only
those with identify_phase(database) or the candidates only switch.
search_phases() against the built-in library is the fallback for when you
have no candidates in mind; narrow it with an element filter.
Reference data sources: every lattice parameter in the built-in phase library
(PHASE_LIBRARY in showdiffraction.py) is a room-temperature value taken from a
license-clean source cited next to the entry — NIST SRM certificates and NBS
circulars/monographs (US public domain), the Crystallography Open Database
(CC0), or the primary literature. No values come from proprietary compilations
such as the ICDD PDF or Pearson’s Handbook.
The lattice-based phase model enumerates d-spacings and geometric systematic
absences. It does not calculate structure-factor intensities, thermal effects,
or dynamical diffraction; use Phase.from_dspacings when matching against a
measured or literature line table with intensities.
Calibrated radial axes are reported as g = 1/d in 1/Å; the legacy
radial_profile(units="q") spelling is an alias for units="g", not a
2πg scattering-vector axis.
Viewer UI#
ShowDiffraction supports the shared ui_mode, show_title,
show_controls, controls_collapsed, and show_stats names. See
Viewer UI controls.
Reference#
- class quantem.widget.showdiffraction.ShowDiffraction(*args: t.Any, **kwargs: t.Any)#
Bases:
AnyWidgetInteractive d-spacing analysis for 2D/3D diffraction patterns.
Pick Bragg spots and rings on the diffraction pattern to measure d-spacings, g-vectors, and inter-spot angles, with optional sub-pixel Gaussian refinement. Works with a single 2D pattern (SAED) or a 3D stack of patterns, and accepts NumPy arrays, PyTorch tensors, or quantem datasets. 4D input is not supported.
- Parameters:
data (np.ndarray or torch.Tensor) – 2D
(det_rows, det_cols)single pattern or 3D(n_frames, det_rows, det_cols)stack of patterns. A quantem dataset or ioLoadResultis also accepted and unwrapped. 4D input raises.k_pixel_size (float, optional) – k-space sampling in 1/Å per pixel. Marks the pattern calibrated.
pixel_size (float, optional) – Real-space pixel size in Å.
center (tuple[float, float], optional) – (row, col) of the diffraction center in pixels. Defaults to the detector center, then auto-detected from the bright-field disk if also no radius.
bf_radius (float, optional) – Bright-field disk radius in pixels. Defaults to 1/8 of the detector size.
title (str, default "") – Title displayed above the widget.
snap_enabled (bool, default False) – Snap clicked spots to the local intensity maximum.
snap_radius (int, default 5) – Search radius in pixels for snapping / Gaussian refinement.
spot_refine (bool, default True) – Sub-pixel refine spots with a 2D Gaussian fit on add.
detect_denoise ({"auto", "none", "gaussian", "anscombe"}, default "auto") – Denoise applied to the frame before center refinement and spot/ring detection. “auto” estimates the noise level and picks a mode; fits and measurements always run on the raw data, so positions are not biased by the smoothing. Set the
show_detection_viewtrait to display the denoised view instead of the raw frame, or thedenoisetrait for a display-only filter ("nlm"keeps spots sharp) that touches neither detection nor measurements.dp_scale_mode (str, default "log") – Diffraction display scaling (“linear”, “log”, “sqrt”).
ui_mode ({"interactive", "presentation", "report", "minimal"}, default "interactive") – Shared viewer UI preset. Explicit
show_*keyword arguments override preset values.show_title (bool, default True) – Show the top title row.
show_stats (bool, default True) – Show statistics (mean, min, max, std).
show_controls (bool, default True) – Show the control panel.
controls_collapsed (bool, default False) – Start with controls hidden while keeping a recoverable
Controlsbutton in the frontend.panel_width_px (int, optional) – Initial diffraction canvas width in CSS pixels. The frontend still lets users resize the panel interactively.
verbose (bool, default True) – Print load timing on construction.
state (str, pathlib.Path, or dict, optional) – Saved state to restore after construction.
Examples
>>> import numpy as np >>> from quantem.widget.showdiffraction import ShowDiffraction
Single 2D diffraction pattern:
>>> ShowDiffraction(np.random.rand(256, 256))
Calibrated stack of diffraction patterns:
>>> ShowDiffraction(np.random.rand(20, 128, 128), k_pixel_size=0.012)
Public constructor
- property detector_shape: tuple[int, int]#
Detector shape as
(rows, cols).
- property n_source_frames: int | None#
Source-frame count before merge_frames appended a merged frame.
- auto_detect_center(*, refine: bool = False) Self#
Find the BF disk center/radius from the summed stack.
- refine_center(*, method: str = 'symmetry', search_radius: float = 8.0) Self#
Refine the center with symmetry, phase correlation, or auto.
- set_center(row: float, col: float) Self#
Set the diffraction center to (row, col) and mark the mode manual.
- detect_spots(max_spots: int | None = None, min_distance: int = 6, min_relative: float = 0.1, exclude_radius: float | None = None, noise_sigma: float = 5.0, replace: bool = True) Self#
Detect Bragg spots with contrast at least
min_relativeof the strongest peak.noise_sigmasets the shot-noise contrast floor in robust sigma units; lower it on frames whose background structure inflates the estimate (diffuse scattering, detector shadows).
- detect_rings(max_rings: int | None = None, prominence_rel: float = 0.05, min_separation: int = 5, exclude_radius: float | None = None, replace: bool = True) Self#
Detect Debye-Scherrer rings from radial profile peaks (max_rings=None keeps all).
- add_spot(row: float, col: float) Self#
Add a spot, optionally refining or snapping it.
- move_spot(spot_id: int, row: float, col: float) Self#
Move the spot with id
spot_id, re-picking it at the new position.
- clear_spots() Self#
Remove all spots.
- undo_spot() Self#
Remove the most recently added spot.
- remove_spot(spot_id: int) Self#
Remove the spot with id
spot_id(no-op if not present).
- add_ring(radius_px: float) Self#
Add a ring at radius_px from the center (polycrystalline d-spacing pick).
- clear_rings() Self#
Remove all rings.
- undo_ring() Self#
Remove the most recently added ring.
- remove_ring(ring_id: int) Self#
Remove the ring with id
ring_id(no-op if not present).
- fit_ring_profile(*, window: float | None = None, model: str = 'gaussian', subtract_background: bool = True) Self#
Fit each ring peak and store refined radius, width, area, and quality.
- recover_predicted_rings(phase: Phase, *, tol_px: float = 4.0, snr: float = 3.0) list[float]#
Add rings the detector missed at radii the calibrated phase predicts.
For each allowed reflection with no ring within
tol_px, the raw radial profile is tested near the predicted radius; a local maximum at leastsnrrobust sigmas above the detrended profile noise becomes a ring. Returns the added radii in pixels.
- run_auto(phase: Phase | None = None, *, max_rings: int = 8, exclude_radius: float | None = None) Self#
Run center finding, ring detection, fitting, calibration, and indexing.
Silent on success;
analysis_statusonly reports steps that failed.
- merge_frames(*, statistic: str = 'mean', align: bool = True, max_shift: float = 8.0) dict#
Align the stack and append the combined pattern as a new frame.
- quality_report() dict#
QC snapshot: center method, calibration, ellipse, ring fits, unexplained rings, mask coverage, and outermost-ring SNR.
- radial_profile(*, n_bins: int | None = None, max_radius: float | None = None, center: tuple[float, float] | None = None, units: str = 'auto', angular_range: tuple[float, float] | None = None, subtract_background: bool = False) tuple[ndarray, ndarray]#
Azimuthally averaged profile in px, g, or d units.
units="q"is kept as a legacy alias for"g".
- azimuthal_profile(*, ring_id: int | None = None, radius_px: float | None = None, width: float | None = None, n_theta: int = 180) tuple[ndarray, ndarray]#
Intensity vs azimuth around a ring.
- texture(*, ring_id: int | None = None, radius_px: float | None = None, width: float | None = None, n_theta: int = 180, return_profile: bool = False) dict#
Order-2 ring texture: strength in [0, 1] and 180-degree angle.
- fit_ellipse(ring_id: int | None = None, *, n_theta: int = 180) dict#
Fit ellipse distortion from ring radius vs azimuth.
- apply_ellipse_correction(*, enable: bool = True) Self#
Enable or disable radius circularization by the fitted ellipse.
- radial_background(*, n_bins: int | None = None, max_radius: float | None = None, center: tuple[float, float] | None = None, method: str = 'power', poly_order: int = 3, peak_windows: list[tuple[float, float]] | None = None, exclude_radius: float | None = None) tuple[ndarray, ndarray]#
Fit a smooth radial background while excluding peaks.
- index_rings(phase: Phase, tol: float = 0.03, replace: bool = True) Self#
Label rings by d-spacing match against a calibrated phase.
- identify_phase(database, tol: float = 0.03) list[dict]#
Rank an explicit list of candidate phases against measured d-spacings.
This is the primary verification workflow: build the candidates you expect (
library_phase(),Phase.from_cubic(),Phase.from_dspacings(), …) and rank only those. Usesearch_phases()when you have no candidates in mind.
- search_phases(*, tol: float = 0.03, elements=None, exclude_elements=None, extra=None, custom_only: bool | None = None, top_n: int = 10) list[dict]#
Rank library, custom, and extra phases against measured d-spacings.
With
custom_only(default: theidentify_custom_onlytrait) the library is skipped and only user candidates (custom phases plusextra) are ranked.
- index_spots(phase: Phase, tol: float = 0.03, angle_tol: float = 3.0) Self#
Index spots and solve the zone axis from an angle-consistent anchor pair.
- calibrate_from_spot(row: float, col: float, d_known: float) Self#
Calibrate
k_pixel_sizefrom a spot of known d-spacing.
- calibrate_from_ring(radius_px: float, d_known: float) Self#
Calibrate
k_pixel_sizefrom a ring of known d-spacing.
- calibrate_from_phase(phase: Phase, *, tol: float = 0.03, d_min: float = 0.5) Self#
Fit
k_pixel_sizeby assigning ring-radius ratios to a known phase.
- export_measurements(path: str) Path#
Export spot and ring measurements as CSV or JSON.
- classmethod measurements_from_state(state, path=None)#
Rebuild the measurement table from a saved state.
- export_html(path: str | Path | None = None, *, title: str | None = None, **options) Path#
Write a standalone HTML viewer with exact float32 frames.
- set_image(data) Self#
Replace data. Preserves display settings, clears spots and rings.
- state_dict()#
Return the persistable widget state as a plain dict.
- save(path: str)#
Write the widget state to a JSON file.
- 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.
- load_state_dict(state)#
Restore widget state from a dict; unknown keys are ignored.
- summary()#
Print a text summary of calibration, spots, rings, and indexing.
- free()#
Free GPU memory held by this widget.
Interactive controls#
Each control mutates the listed synced trait. A UI-test agent acts on the control, then asserts the trait changed and the canvas repainted (non-zero, no console error, no NaN frame).
Control |
Trait |
Expected effect |
|---|---|---|
Colormap dropdown |
|
Pattern recolors to the chosen map |
Scale mode dropdown |
|
Intensity mapped linear / log / sqrt |
Invert toggle |
|
Colormap reversed |
Contrast histogram (dual-thumb slider) |
|
Drag either thumb (mouse or touch) for a live preview; traits update once on release |
Center mode dropdown |
|
|
Click to set center (manual) |
|
Crosshair moves; spot d-spacings recompute |
Detect spots |
|
Auto-finds every isolated peak with contrast at least 10% of the strongest ( |
Add / remove spot (click) |
|
Marker placed/removed; d-spacing updates |
Move spot (Move + drag) |
|
Re-picks the spot at the drop position; stale hkl clears |
Spot pick dropdown |
|
Clicked spots are Gaussian-fitted, snapped to the local maximum, or kept exactly as clicked |
Detect rings |
|
Auto-finds all Debye–Scherrer rings above the profile prominence threshold, on the |
Add / remove ring |
|
Ring overlay; ring d-spacing updates |
Calibrate from spot / ring |
|
Sets k-space pixel size from a known d |
Auto button |
|
Runs center, rings, calibration, fit, and indexing in one pass; status reports failed steps only |
Phase menu |
|
Selects a library or custom phase for calibration and indexing; custom entries take a full lattice (a, b, c, α, β, γ) and absence rule |
Identify candidates only |
|
Identify ranks only custom phases, skipping the library |
Calibrate from phase |
|
Fits k-space sampling from ring-to-reflection assignment |
Index rings / spots |
|
Fills hkl labels; spot indexing also solves the zone axis |
Exclude menu |
|
Edits wedge/disk regions excluded from analysis |
Draw excluded disk / wedge (drag) |
|
Drag on the pattern to add an excluded region with live preview |
Mask view toggle |
|
Shows or hides excluded-region overlays |
Fit rings |
|
Refines ring radius and width; fwhm column appears |
Fit ellipse / use correction |
|
Measures distortion; the switch circularizes radii |
Profile panel |
|
Radial profile with ring markers; click adds a ring |
Azimuthal panel |
|
Intensity vs azimuth around the outermost ring |
hkl toggle |
|
Shows or hides hkl labels on spots and rings |
Stats toggle |
|
Shows or hides the pattern-statistics readout |
Undo / clear spots and rings |
|
Removes the last or all markers (Ctrl+Z also undoes) |
Center view |
view transform |
Recenters and zooms the view to the diffraction center |
Spot / ring CSV and JSON |
measurement tables |
Downloads the visible measurement table rows |
Refine method dropdown |
|
Picks the center-refinement algorithm (auto / symmetry / phase_corr) |
Refine center |
|
Refines the center; records the method used |
Merge frames (3D) |
|
Align + merge frames; appends the combined pattern |
Element filter box |
|
Restricts the phase search to these elements (e.g. |
Identify phases |
|
Ranked candidate phases with per-line match tables |
Quality panel |
|
Analysis-quality snapshot: center, calibration, ellipse, ring fits, mask coverage |
Ring click in profile |
|
Highlights the picked ring marker (0 clears) |
Frame slider (3D) |
|
Scrubs to a different pattern in the stack |
Pan (drag) / zoom (wheel) |
view transform |
Pattern translates / zooms about the cursor |
Touch: two-finger pinch / drag, double-tap |
view transform |
Pinch zooms about the fingers, two-finger drag pans, double-tap resets the view |
Export → PNG / HTML |
|
Saves the current view as a PNG image or a standalone HTML viewer |
See also
The shared HTML-export contract is documented in html-export.