ShowEDS#
Public import:
from quantem.widget import ShowEDS, load_eds
ShowEDS explores EDS/EELS spectrum images with shape
(row, col, energy). The widget links a real-space map and a spectrum: dragging
the energy band updates the element map, and dragging the rectangular real-space
ROI updates the summed spectrum.
Viewer UI#
ShowEDS supports the shared ui_mode, show_title, show_controls,
controls_collapsed, and show_scale_bar names. The saved-state trait remains
scale_bar_visible for compatibility. See Viewer UI controls.
ShowEDS is still experimental. The merged baseline supports synthetic/small
cubes and the documented data-folder workflow. Direct native EMD sparse-stream
loading is under active real-data testing and should not be treated as finalized
release behavior yet.
Canonical forms:
# Native EDS/EELS file: parse metadata and keep exact no-bin EMD data lazy.
# The returned SpectrumImage uses (row, col, energy) and feeds ShowEDS directly.
eds = load_eds("0031-CaSIO3_...EDS_HAADF_Diffraction_Nano.emd")
w = ShowEDS(
eds,
energy=8.04,
width=0.24,
pixel_size=0.138,
pixel_unit="nm",
element_label="Cu K",
candidate_elements=["O", "Si", "Ca", "Cu", "Au"],
)
# Small or already-reduced cube: embeds the exact uint16/uint32/float32 cube in
# widget state, so notebook save/reopen and HTML export are self-contained.
w = ShowEDS(cube, energy_keV, base_image=haadf)
# Large EMD as a reusable data folder. The notebook stores startup state and a
# data-folder URL, not the multi-GB cube.
w = ShowEDS.from_emd(
"0031-CaSIO3_...EDS_HAADF_Diffraction_Nano.emd",
sidecar_dir="sidecars/eds_real_0031",
energy=8.04,
width=0.24,
pixel_size=0.138,
pixel_unit="nm",
element_label="Cu K",
candidate_elements=["O", "Si", "Ca", "Cu", "Au"],
selected_elements=["Cu", "Au"],
)
# Shareable HTML. Small cubes can use single HTML with exact data. Large folder-backed
# cubes can use exact folder HTML, or count-preserving downsampled single HTML.
w.export_html("showeds_exact.html")
w.export_html("showeds_exact_folder.html", mode="folder")
w.export_html("showeds_downsample4.html", downsample=4)
For the real EDS 0031 dataset, the folder path keeps the live notebook small
because the saved .ipynb contains widget state plus startup arrays, not the
entire raw cube. The exact folder HTML mode is similarly small but must be
served next to its companion data folder. downsample=2 or downsample=4
embeds sum-downsampled data into one HTML file, which is the better public
tutorial and Hugging Face demo path.
Reference#
- class quantem.widget.showeds.ShowEDS(*args: Any, **kwargs: Any)#
Bases:
StaticFallbackMixin,AnyWidgetExplore an EDS/EELS spectrum image
(row, col, energy).For browser-backed widgets, the frontend keeps the spectrum cube resident in WebGPU.
ShowEDS.from_emd(...)uses exact sparse browser-side streams by default for native Velox/RSCIIO EMD spectrum streams, keeping band/ROI interaction out of the notebook kernel. Passbackend="kernel"only when explicit lazy Python queries are required.- classmethod from_sidecar(sidecar_url: str, *, sidecar_dir: str | Path | None = None, initial_map: ndarray | None = None, initial_spectrum: ndarray | None = None, energy_keV: ndarray | list[float] | None = None, title: str = '', base_image: ndarray | None = None, energy: float | None = None, width: float | None = None, element_label: str = '', candidate_elements: list[str] | tuple[str, ...] | None = None, **kwargs: Any) ShowEDS#
Create a browser-only widget from a prepared data-folder URL.
- classmethod from_emd(path: str | Path, *, backend: str = 'auto', sidecar_dir: str | Path | None = None, sidecar_url: str | None = None, rebuild_sidecar: bool = False, energy_chunk: int = 256, spatial_bin: int = 1, energy_bin: int = 1, max_sidecar_bytes: int | None = 12884901888, title: str | None = None, energy: float = 8.04, width: float = 0.24, element_label: str = 'Cu K', candidate_elements: list[str] | tuple[str, ...] | None = None, **kwargs: Any) ShowEDS#
Open a Velox/RSCIIO EMD spectrum image.
backend="auto"uses an existing data folder if one is present. Otherwise, exact no-bin Velox/RSCIIO spectrum streams are indexed into browser-side sparse buffers so band/ROI interaction does not block the notebook kernel. Passbackend="kernel"to force the older lazy Python query path, orbackend="sidecar"/ explicit binning for a portable prefix-cache data folder.
- detect_elements(source: str = 'sum', *, elements: list[str] | tuple[str, ...] | None = None, energy_resolution_mnka: float = 130.0, min_significance: float = 4.0, max_candidates: int = 8, select: bool = False) list[dict[str, Any]]#
Detect candidate elements from spectrum peaks and rank them.
Estimates the continuum background, finds significant peaks, and ranks elements whose characteristic lines explain them (see
quantem.widget.showeds.match_elements()). Results are advisory and fill theelement_candidatestrait shown in the periodic-table menu.- Parameters:
source –
"sum"uses the full sum spectrum,"roi"the current ROI.elements – Restrict candidates to these symbols. Defaults to the constructor’s
candidate_elementswhen given, else the full line table.energy_resolution_mnka – Detector resolution at Mn Ka in eV.
min_significance – Minimum peak significance in sigma.
max_candidates – Maximum number of ranked candidates.
select – If
True, write the candidate symbols toselected_elements.
- Returns:
Ranked per-element reports, also stored in
element_candidates.- Return type:
list[dict]
- get_state(key=None, drop_defaults=False)#
Trait state for comm sync and notebook embedding.
ipywidgets calls this with
key=Noneto snapshot the FULL state that gets written into the saved notebook’smetadata.widgets. Whensave_stateis False we drop the heavy buffers from that snapshot so a plain ShowEDS does not bake the dense cube / sparse stream index into the .ipynb. Targeted syncs (keyis a name or set, used by hold_sync / send_state during live rendering) are untouched, so the frontend still receives every buffer normally.save_state=Trueembeds everything so a reopened notebook restores the interactive widget without a kernel.
- 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.
- export_html(path: str | Path | None = None, *, title: str | None = None, mode: str = 'single', encoding: str = 'full', downsample: int | None = None, binning: int | None = None) Path#
Write a standalone HTML explorer for this EDS/EELS widget.
mode="single"writes one HTML file.mode="folder"writes an HTML file that references an existing exact data folder. Usedownsample=2ordownsample=4for a smaller one-file export that sum-bins rows, columns, and energy channels.binningis kept as a compatibility alias for older notebooks.
- class quantem.widget.showeds.SpectrumImage(cube: ~typing.Any | None, energy_keV: ~numpy.ndarray | list[float], base_image: ~typing.Any | None = None, title: str = '', candidate_elements: list[str] = <factory>, path: ~pathlib.Path | None = None, source_shape: tuple[int, int, int] | None = None, spatial_bin: int = 1, energy_bin: int = 1, backend: str = 'browser', sidecar_dir: ~pathlib.Path | None = None, sidecar_url: str | None = None, initial_map: ~numpy.ndarray | None = None, initial_spectrum: ~numpy.ndarray | None = None, sampling: float | tuple[float, float] | list[float] | None = None, units: str | list[str] | None = None, metadata: dict[str, ~typing.Any] = <factory>, stream_index: dict[str, ~typing.Any] | None = None)#
Parsed EDS/EELS spectrum image with energy on the last axis.
This is the small public handoff object returned by
load_eds(). It is intentionally widget-local for now: users can pass it directly toShowEDS, while large native EMD files stay lazy and exact instead of forcing a dense cube into notebook state.- property array: Any | None#
Return the dense or lazy (row, col, energy) cube, when available.
- property shape: tuple[int, int, int] | None#
Return the spectrum-image shape (row, col, energy) when known.
- quantem.widget.showeds.load_eds(path: str | Path, *, backend: str = 'auto', sidecar_dir: str | Path | None = None, sidecar_url: str | None = None, rebuild_sidecar: bool = False, energy_chunk: int = 256, spatial_bin: int = 1, energy_bin: int = 1, max_sidecar_bytes: int | None = 12884901888, candidate_elements: list[str] | tuple[str, ...] | None = None) SpectrumImage#
Parse an EDS/EELS spectrum image into a
SpectrumImage.The returned object always uses the
(row, col, energy)convention and can be passed directly toShowEDS:from quantem.widget import ShowEDS, load_eds eds = load_eds("scan.emd") ShowEDS(eds)
For native Velox/RSCIIO
.emdfiles,backend="auto"uses an existing data folder when present. Otherwise exact no-bin spectrum streams are indexed into browser-side sparse buffers so interactive band/ROI updates stay out of the notebook kernel. Passbackend="kernel"only when explicit lazy Python queries are required. If a data folder is requested, or ifspatial_bin/energy_binare larger than one, the existing exact ShowEDS sidecar path is used.
- quantem.widget.showeds.bin_spectrum_image(cube: ndarray, energy_keV: ndarray | list[float] | None = None, *, base_image: ndarray | None = None, spatial_bin: int = 1, energy_bin: int = 1) tuple[ndarray, ndarray | None, ndarray | None]#
Sum-bin an EDS/EELS cube before sending it to the browser.
spatial_binbins rows and columns;energy_binbins adjacent energy channels. Summing preserves counts, which is usually the right behavior for spectrum-image exploration.
- quantem.widget.showeds.prepare_spectrum_image_sidecar(cube: ndarray, energy_keV: ndarray | list[float], out_dir: str | Path, *, base_image: ndarray | None = None, energy_chunk: int = 256, max_sidecar_bytes: int | None = 12884901888) Path#
Write an exact ShowEDS data folder for fast EDS/EELS interaction.
The data folder keeps the raw count precision but stores summaries that make browser interaction proportional to screen size or energy channels, not to the full
row * col * energycube on every drag. Files are written as little-endianuint32:energy_prefix_u32.bin: cumulative energy planes, shape(n_energy + 1, rows, cols). Band maps are exact plane differences.spatial_prefix_u32.bin: summed-area spectra, shape(rows + 1, cols + 1, n_energy). ROI spectra fetch four contiguous spectra and subtract them exactly.
This is intentionally a preprocessing step. Once the files exist, the live widget can fetch them from the frontend without Python round trips.
This prefix-cache format is meant for small or deliberately spatial-binned portable viewers. Native vendor EDS files should usually remain the query source for no-bin work: the widget only needs the current energy window, ROI spectrum, or visible preview, not a fully expanded browser artifact.
max_sidecar_bytesprotects against accidentally creating a portable cache that is not appropriate for the source.
- quantem.widget.showeds.load_emd_spectrum_image(path: str | Path, *, spatial_bin: int = 1, energy_bin: int = 1, candidate_elements: list[str] | tuple[str, ...] | None = None) dict[str, Any]#
Load a Velox/RSCIIO EDS spectrum image for
ShowEDS.Returns a dictionary containing
cube,energy_keV,base_image,title,candidate_elements, andsource_shape. The returned cube is always(row, col, energy). Optionalspatial_binandenergy_binperform count-preserving sum binning when explicitly requested.
- quantem.widget.showeds.eds_line_hints(energy_min: float, energy_max: float, *, elements: list[str] | tuple[str, ...] | None = None, max_lines: int = 600) list[dict[str, Any]]#
Return line hints inside an energy range for frontend display.
Interactive controls#
With a small cube in single mode with exact data, all interaction runs in the browser. With a folder-backed EMD widget, startup state is embedded and the browser fetches exact prefix arrays from the data-folder URL, so dragging the band or ROI does not need a Python round trip.
Control |
Trait |
Expected effect |
|---|---|---|
Energy band on spectrum |
|
Real-space element map recomputes from the selected energy window |
Band center drag |
|
The selected energy window translates without changing width |
Elements periodic table |
|
Select candidate elements, emphasize their line markers, and snap the band to characteristic X-ray lines |
Detect button |
|
Runs |
Real-space ROI |
|
Rectangular or circular ROI recomputes the summed spectrum from the selected real-space region |
Spectrum log toggle |
|
Spectrum switches between linear and log display |
Scroll zoom / pan |
|
Real-space and spectrum views zoom around the cursor and reopen at the saved view |
Real-space scale bar |
|
Shows/hides a Show2D-style scale bar and zoom indicator without changing count data |
Overlay slider |
|
Element-map overlay fades against the base image |
Auto / contrast range |
|
Element-map display range updates without changing counts |
Panel resize handles |
|
Real-space and spectrum panels resize independently |
Export menu |
|
Generates exact folder or downsampled single HTML |
Reset |
multiple state traits |
Restores default band, ROI, contrast, and panel sizing |
State and sharing#
Saving a notebook stores the interactive widget state: current band, ROI, scroll
zoom, scale-bar calibration, log toggle, overlay opacity, contrast limits, panel sizes, and export metadata. For
small cubes stored with exact data, the saved notebook also contains the exact cube bytes. For
large from_emd(...) widgets, the saved notebook contains only startup arrays
and the data folder URL, so reopening stays lightweight and the data folder must
remain available.
For collaborators in JupyterLab, share the full-state notebook plus any data folder it references. For GitHub’s native notebook preview, use the GitHub snapshot workflow instead of expecting live widgets. For a web page or tutorial, export HTML: exact folder HTML for full-resolution internal use, or downsampled single HTML for compact public demos.