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.

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/phases.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/Å, not as a 2πg scattering-vector axis.

Viewer UI#

ShowDiffraction has the shared show_title, show_controls, controls_collapsed, and show_stats traits (set them after construction). See Viewer UI controls.

Reference#

class quantem.widget.showdiffraction.ShowDiffraction(*args: t.Any, **kwargs: t.Any)#

Bases: StateFileMixin, HtmlExportMixin, 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 sub-pixel Gaussian refinement. Works with a single 2D pattern (SAED) or a 3D stack of patterns, and accepts NumPy arrays, PyTorch tensors, or Dataset2d / Dataset3d. 4D input is not supported.

Parameters:
  • data (np.ndarray, torch.Tensor, Dataset2d or Dataset3d) – 2D (det_rows, det_cols) single pattern or 3D (n_frames, det_rows, det_cols) stack of patterns. A dataset supplies the title and, when its detector axes are a reciprocal length (1/angstrom, 1/Å, 1/nm), the k calibration.

  • detector_sampling_inv_A (float, optional) – k-space sampling in 1/Å per pixel. Marks the pattern calibrated. A dataset is the source of its own calibration: a value that contradicts it raises.

  • bright_field_center_px (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.

  • bright_field_radius_px (float, optional) – Bright-field disk radius in pixels. Defaults to 1/8 of the detector size.

  • title (str, default "") – Title displayed above the widget.

  • panel_width_px (int, optional) – Initial diffraction canvas width in CSS pixels.

  • offline (bool, default False) – Pack every frame into the page so an exported HTML scrubs without a kernel.

  • device (str, default "auto") – Where the frames are reduced: "auto" (CUDA, then MPS, then CPU; printed once), "cuda", "cuda:N", "mps" or "cpu". A tensor stays on its device unless this names another.

  • remove_hot_pixels (bool, default False) – Zero integer counts above three times the 99.9th percentile when the frame maximum exceeds five times it (hot pixels on counting detectors). Off by default so the frames hold the recorded counts; when such pixels are present a one-line notice says how many.

  • verbose (bool, default True) – Print the loaded shape and device.

  • **kwargs – Any synced trait, for example dp_scale_mode="linear" or show_controls=False.

Examples

>>> import numpy as np
>>> from quantem.widget import ShowDiffraction
>>> ShowDiffraction(np.random.rand(256, 256))
>>> ShowDiffraction(np.random.rand(20, 128, 128), detector_sampling_inv_A=0.012)
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) → Self#

Replace the spots with detected Bragg peaks, strongest first.

Candidates come from the detect_denoise view; each is then picked on the raw frame like a click (Gaussian-refined when spot_refine). min_relative is the contrast floor relative to the strongest peak, noise_sigma the shot-noise floor in robust sigma units; lower it on frames whose background structure inflates the estimate.

index_spots(phase: Phase, tol: float = 0.03, angle_tol: float = 3.0) → Self#

Index the spots against phase and solve the zone axis.

Needs a calibrated pattern and a lattice-based phase (Phase.from_cubic or the full constructor): the zone axis comes from the inter-spot angles, which a d-spacing card does not have. See lattice.index_spot_vectors().

run_auto(phase: Phase | None = None, *, max_rings: int = 8, exclude_radius: float | None = None) → Self#

Center finding, ring detection, ring fitting, k calibration from phase (default: the selected phase_name), recovery of predicted rings and indexing.

max_rings keeps the most significant ring peaks (standard errors above the profile envelope, lattice.detect_ring_radii()). The calibration is verified scale-free, ring-radius ratios against the phase’s d-spacing ratios (lattice.calibration_scale_from_phase()), and is not applied when the rings do not decide it. analysis_status reports every failed step and the rings the phase does not explain; it is empty on a clean result.

identify_phase(database, tol: float = 0.03) → list[dict]#

Rank an explicit list of candidate phases against the 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, custom_only: bool | None = None, top_n: int = 10) → list[dict]#

Rank the built-in library plus the custom phases against the measured d-spacings.

elements (default: the identify_elements trait, for example "Fe, O") keeps only phases whose formula uses those elements; with custom_only (default: the identify_custom_only trait) the library is skipped.

classmethod measurements_from_state(state, path: str | Path | None = None)#

Measurement rows (MEASUREMENT_COLUMNS) from a saved state file or dict; with path they are written as CSV (or JSON with the calibration metadata).

export_html(path: str | Path | None = None, *, title: str | None = None) → Path#

Write a standalone HTML viewer with exact float32 frames that opens with no kernel and no network.

state_dict() → dict#

The persistable widget state (calibration, picks, display) as a plain dict.

load_state_dict(state: dict | str | Path) → None#

Restore a state_dict, its envelope or a save file; a file of another schema or an unknown key raises before anything is applied.

summary() → None#

Print calibration, center, spots, rings, zone axis and phase match.

free() → None#

Release the frame stack. del widget alone does not free it because the traitlets observers pin the widget.

Interactive controls#

Each control mutates the listed synced trait. Analysis buttons send one _request message ({"action": ..., "args": [...], "seq": n}); Python runs the action, reports in analysis_status, and clears _request. 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)

bright_field_center_row_px, bright_field_center_col_px

Crosshair moves; spot d-spacings recompute

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)

_request, spots

Marker placed/removed; d-spacing updates

Move spot (Move + drag)

_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

_request, rings

Auto-finds every Debye–Scherrer ring that stands at least 5 standard errors of the azimuthal mean above the profile’s lower envelope; peaks are located on the detect_denoise view, significance and ring fits use the raw counts; no count cap

Add / remove ring

_request, rings

Ring overlay; ring d-spacing updates

Calibrate from spot / ring

_request, detector_sampling_inv_A

Sets k-space pixel size from a known d

Auto button

_request, analysis_status

Runs center, rings, calibration, fit, and indexing in one pass; the calibration is applied only when the ring-radius ratios verify it; status reports failed steps and the rings the phase does not explain

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

_request, calibration_rms_px

Fits k-space sampling from the ring-to-reflection assignment whose radius ratios match the phase’s d-spacing ratios within 1%; refuses (status says why) when two scales explain the rings about equally or most rings stay unexplained

Index rings / spots

_request, zone_axis

Fills hkl labels at the current calibration. A ring label needs the ring-radius ratios to agree with the phase and with the calibration (within 3 %); a ring whose d only falls within 3 % of a reflection shows that candidate with ? and is named in the status. 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

_request

Refines ring radius and width; fwhm column appears

Fit ellipse / use correction

_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

_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

_request, center_method

Refines the center; records the method used

Merge frames (3D)

_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

_request, _identify_results

Ranked candidate phases with per-line match tables

Quality panel

_quality

Analysis-quality snapshot: center, calibration, ellipse, ring fits, rings the selected phase does not explain, 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.