ShowDiffraction

Contents

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: AnyWidget

Interactive 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 io LoadResult is 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_view trait to display the denoised view instead of the raw frame, or the denoise trait 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 Controls button 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_relative of the strongest peak.

noise_sigma sets 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 least snr robust 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_status only 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. Use search_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: the identify_custom_only trait) the library is skipped and only user candidates (custom phases plus extra) 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_size from a spot of known d-spacing.

calibrate_from_ring(radius_px: float, d_known: float) → Self#

Calibrate k_pixel_size from a ring of known d-spacing.

calibrate_from_phase(phase: Phase, *, tol: float = 0.03, d_min: float = 0.5) → Self#

Fit k_pixel_size by 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 Controls button.

expand_controls() → Self#

Expand frontend controls when show_controls is 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

dp_colormap

Pattern recolors to the chosen map

Scale mode dropdown

dp_scale_mode

Intensity mapped linear / log / sqrt

Invert toggle

dp_invert

Colormap reversed

Contrast histogram (dual-thumb slider)

dp_vmin_pct, dp_vmax_pct

Drag either thumb (mouse or touch) for a live preview; traits update once on release

Center mode dropdown

center_mode

auto re-detects the BF disk; manual enables click-to-set

Click to set center (manual)

center_row, center_col

Crosshair moves; spot d-spacings recompute

Detect spots

_detect_spots_request, spots

Auto-finds every isolated peak with contrast at least 10% of the strongest (min_relative); candidates come from the detect_denoise view, positions are refined on raw data; no count cap

Add / remove spot (click)

_spot_add_request, _spot_remove_request, spots

Marker placed/removed; d-spacing updates

Move spot (Move + drag)

_spot_move_request, spots

Re-picks the spot at the drop position; stale hkl clears

Spot pick dropdown

spot_refine, snap_enabled, snap_radius

Clicked spots are Gaussian-fitted, snapped to the local maximum, or kept exactly as clicked

Detect rings

_detect_rings_request, rings

Auto-finds all Debye–Scherrer rings above the profile prominence threshold, on the detect_denoise view; ring fits stay on the raw profile; no count cap

Add / remove ring

_ring_add_request, _ring_remove_request, rings

Ring overlay; ring d-spacing updates

Calibrate from spot / ring

_calibrate_from_spot_request, _calibrate_from_ring_request, k_pixel_size

Sets k-space pixel size from a known d

Auto button

_auto_request, analysis_status

Runs center, rings, calibration, fit, and indexing in one pass; status reports failed steps only

Phase menu

phase_name, custom_phases

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_custom_only

Identify ranks only custom phases, skipping the library

Calibrate from phase

_calibrate_phase_request, calibration_rms_px

Fits k-space sampling from ring-to-reflection assignment

Index rings / spots

_index_rings_request, _index_spots_request, zone_axis

Fills hkl labels; spot indexing also solves the zone axis

Exclude menu

mask_regions

Edits wedge/disk regions excluded from analysis

Draw excluded disk / wedge (drag)

mask_regions

Drag on the pattern to add an excluded region with live preview

Mask view toggle

show_mask

Shows or hides excluded-region overlays

Fit rings

_fit_rings_request

Refines ring radius and width; fwhm column appears

Fit ellipse / use correction

_fit_ellipse_request, ellipse_corrected

Measures distortion; the switch circularizes radii

Profile panel

show_profile, profile_log, profile_subtract_background, _profile_data

Radial profile with ring markers; click adds a ring

Azimuthal panel

show_azimuthal, _azimuthal_data

Intensity vs azimuth around the outermost ring

hkl toggle

show_hkl

Shows or hides hkl labels on spots and rings

Stats toggle

show_stats

Shows or hides the pattern-statistics readout

Undo / clear spots and rings

_spot_undo_request, _spot_clear_request, _ring_undo_request, _ring_clear_request

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

refine_method

Picks the center-refinement algorithm (auto / symmetry / phase_corr)

Refine center

_refine_center_request, center_method

Refines the center; records the method used

Merge frames (3D)

_merge_request

Align + merge frames; appends the combined pattern

Element filter box

identify_elements

Restricts the phase search to these elements (e.g. Fe,O)

Identify phases

_identify_request, _identify_results

Ranked candidate phases with per-line match tables

Quality panel

_quality

Analysis-quality snapshot: center, calibration, ellipse, ring fits, mask coverage

Ring click in profile

selected_ring_id

Highlights the picked ring marker (0 clears)

Frame slider (3D)

frame_idx

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

export_request, export_payload

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.