Show2D#

One or many 2D images, including gallery panels with independent local slice stacks, plus contrast control, FFT, ROIs, line profiles, and a calibrated scale bar. See the Show2D tutorial for worked examples and Advanced Show2D for report-ready galleries, rich labels, local annotations, overlays, inset plots, and export patterns.

Reference#

Choose image size and gallery layout with plain keywords:

viewer = Show2D(images, size="medium", columns=2)
viewer.columns = 3

Use rows=2 instead to calculate columns from the number of images per page. If both are supplied, the grid must hold every panel. size describes each image panel: small 300, medium 450, large 600 or xlarge 900 CSS pixels. The default remains three columns for existing notebooks. ncols still works with a deprecation warning; do not combine it with columns or rows. Existing saved layout state remains readable.

class quantem.widget.show2d.Show2D(*args: t.Any, **kwargs: t.Any)#

Bases: WatchedImageFolderMixin, Show2DExport, Show2DState, Show2DStaticPng, SavedStateMixin, HtmlExportMixin, PagesMixin, PanelsMixin, StaticFallbackMixin, AnyWidget

Interactive viewer for one 2D image or a gallery of images.

Parameters:
  • data (array_like, Dataset2d, Dataset3d, or list of these) – (H, W) for one image, (N, H, W) for a gallery, (P, N, H, W) for P pages of N panels. A list may mix 2D images with 3D (frames, H, W) stacks, giving that panel its own frame scrubber. Items with a trailing dimension of 3 or 4 are RGB(A) panels. A quantem Dataset2d / Dataset3d supplies sampling, units and the title. NumPy, PyTorch and CuPy arrays are accepted.

  • labels (list of str, optional) – One label per panel. Entries may also be span lists ([{"text": "a", "color": "#f00"}, {"math": r"\lambda_3"}]).

  • page_labels (list of str, optional) – One label per page for (P, N, H, W) input.

  • title (str, optional) – Gallery title above the panels.

  • show_title (bool, optional) – Draw the title; the ui_mode preset decides when omitted.

  • ui_mode ({"interactive", "presentation", "report"}, default "interactive") – Preset for which controls are shown; the show_* flags override it.

  • cmap (str or list of str, default "inferno") – Colormap, or one per panel.

  • sampling (float or (row, col), optional) – Pixel size in units; drives the scale bar and calibrated readouts.

  • units (str, optional) – Length unit of sampling ("A", "nm", …); angstrom when sampling is given without it. Alone on a calibrated dataset it is the unit the dataset’s step is shown in.

  • show_scale_bar (bool, optional) – Draw the scale bar.

  • scale_bar_position ({"bottom-right", "bottom-left"})

  • scale_bar_panels (list of int or str, optional) – Panels (index or label) that draw a scale bar; default all.

  • scale_bar_length (float, optional) – Fixed bar length in units instead of the automatic nice length.

  • scale_bar_label (str, optional) – Fixed bar text instead of the formatted length.

  • scale_bar_style (dict, optional) – Bar and label styling (font_size, color, bar_height, …).

  • show_zoom_indicator (bool, default False) – Draw the zoom factor beside the scale bar.

  • show_fft (bool, optional) – Visibility of the FFT/histogram panel, the stats row, the control bar and the panel titles.

  • show_stats (bool, optional) – Visibility of the FFT/histogram panel, the stats row, the control bar and the panel titles.

  • show_controls (bool, optional) – Visibility of the FFT/histogram panel, the stats row, the control bar and the panel titles.

  • controls_collapsed (bool, optional) – Visibility of the FFT/histogram panel, the stats row, the control bar and the panel titles.

  • show_panel_titles (bool, optional) – Visibility of the FFT/histogram panel, the stats row, the control bar and the panel titles.

  • panel_title_spans (list, optional) – Rich title spans per panel (same schema as span labels).

  • panel_title_font_size (int, default 11)

  • panel_title_style (dict, optional) – Title badge styling (fg, bg, align, outline_width, …).

  • log_scale (bool, default False) – Signed-log1p display and 2/98 percentile contrast.

  • auto_contrast (bool, default False) – Signed-log1p display and 2/98 percentile contrast.

  • vmin (float or list of float, optional) – Fixed contrast window, or one per panel.

  • vmax (float or list of float, optional) – Fixed contrast window, or one per panel.

  • link_zoom (bool, optional) – Galleries link zoom and pan by default; a single image never does.

  • link_pan (bool, optional) – Galleries link zoom and pan by default; a single image never does.

  • link_contrast (bool, default True) – One shared contrast window across panels.

  • columns (int, optional) – Image panels across each page; three by default for compatibility. Rows are calculated automatically. For example, columns=2 places five images in three rows. Set viewer.columns to change it later.

  • rows (int, optional) – Desired initial rows per page; infer columns when supplied alone. If both are supplied, their capacity must hold every panel on a page.

  • ncols (int, optional) – Deprecated alias for columns. Do not combine it with rows or columns.

  • size ({"small", "medium", "large", "xlarge"}, default "medium") – Width of each image panel: 300, 450, 600 or 900 CSS pixels. Aspect ratio and source resolution are preserved; controls keep the shared font.

  • panel_width_px (int or None, optional) – Panel canvas width in CSS px. The medium default is 450 px per image; this changes display size only. A positive panel_width_px overrides size; 0 uses size.

  • smooth (bool, default False) – Bilinear instead of nearest-neighbor magnification.

  • zoom (float, default 1.0) – Initial zoom factor.

  • center ((row, col), optional) – Image point the initial view is centered on, in full-resolution pixels.

  • display_bin (int or "auto", default 1) – Mean-bin factor (a positive integer) of the preview sent to the browser; full-res detail streams on zoom either way. The default 1 sends native pixels. An integer above 1 bins by that factor. "auto" picks the smallest factor that keeps the gallery under 2.5 GB of browser GPU buffers (float32 + RGBA + readback per panel) and each float32 panel under 16 MiB of initial payload. Any active bin prints one line.

  • offline (bool, default False) – Quantize each panel to uint8 over its own range (256 levels) for a small standalone page, and print one line saying so.

  • panel_frame_indices (list of int, optional) – Initial frame per stack panel (negative indices count from the end).

  • panel_playback_fps (float, default 10) – Playback rate for stack panels.

  • starred (list of int or str, optional) – Panels (index or label) to star.

  • marker_colors (list of str, optional) – One identity color per panel, drawn as a bar (marker_style="left") or a frame ("around").

  • row_markers (dict, optional) – {row_index: color} / {col_index: color} frames around gallery rows or columns.

  • col_markers (dict, optional) – {row_index: color} / {col_index: color} frames around gallery rows or columns.

  • inset_plots (optional) – Per-panel inset curves, text annotations and shape overlays; the dict schema is in show2d.options and docs/api/show2d.md.

  • panel_annotations (optional) – Per-panel inset curves, text annotations and shape overlays; the dict schema is in show2d.options and docs/api/show2d.md.

  • panel_overlays (optional) – Per-panel inset curves, text annotations and shape overlays; the dict schema is in show2d.options and docs/api/show2d.md.

  • panel_gap_px (optional) – Gallery chrome: the gap between panels.

  • inter_panel_gap_color (optional) – Gallery chrome: the gap between panels.

  • gallery_outer_border_px (optional) – Gallery chrome: the frame around the whole gallery.

  • gallery_outer_border_color (optional) – Gallery chrome: the frame around the whole gallery.

  • panel_inner_border_px (optional) – Gallery chrome: each panel’s own inner stroke.

  • panel_inner_border_color (optional) – Gallery chrome: each panel’s own inner stroke.

  • denoise ({"none", "gaussian", "anscombe"} or list of str, default "none") – Display-only denoise run in the browser (the data and stats stay raw); a list gives each panel its own mode. Turns the denoise switch on and shows its controls when any panel is filtered.

  • denoise_sigma (float or list of float, default 4.0) – Smoothing width in pixels, per panel when a list.

  • denoise_bin (int or list of int, default 1) – Spatial bin (1, 2 or 4) before the denoise, per panel when a list.

  • state (dict, str or pathlib.Path, optional) – A state_dict or a file written by save to restore the view.

  • save_state (bool, default False) – Embed the full interactive state in the saved notebook (large). The default stores a static preview plus light traits.

  • verbose (bool, default True) – Add the preview size to the display-bin notice (the notice itself always prints when a bin is active).

Examples

>>> from quantem.widget import Show2D
>>> Show2D([raw, denoised], labels=["raw", "denoised"], sampling=0.2, units="nm", cmap="gray")
classmethod from_folder(path: str | Path, *, pattern: str = '*', recursive: bool = False, watch: bool = True, watch_interval: float = 1.0, page_size: int | None = 20, **kwargs) → Self#

Display readable folder images as a paged full-resolution gallery.

Files are ordered naturally (image_2 before image_10) and read through quantem.widget.io.read_image(), including EMD, TIFF, PNG, NPY, and DM calibration paths. The same widget is updated when stable files are added. Unreadable files remain retryable. At most page_size panels are visible at once; pass None to keep one unpaged gallery.

Parameters:
  • path (str or pathlib.Path) – Folder containing independent 2D image files.

  • pattern (str, default "*") – Glob selecting files within path.

  • recursive (bool, default False) – Search matching files below subdirectories as well.

  • watch (bool, default True) – Start background polling immediately.

  • watch_interval (float, default 1.0) – Seconds between background polls.

  • page_size (int or None, default 20) – Maximum visible panels per page. Paging appears only after the ready image count exceeds this value. Pass None to disable automatic folder paging.

  • **kwargs – Normal Show2D options. File-derived labels and data are managed by the folder source.

property columns: int#

Image panels across each page; the saved layout uses the same value.

set_image(data, labels: list[str | None] | None = None, *, panel_frame_indices: Sequence[int] | None = None) → None#

Replace the displayed image stack without rebuilding the widget.

This updates a live image selection. It preserves display controls such as colormap, contrast, FFT/profile toggles, and gallery layout, while resetting per-panel state tied to the previous image count or dimensions.

save_image(path: str | Path, *, idx: int | None = None, format: str | None = None, dpi: int = 150, title: bool | str = False, colorbar: bool = False, show_scale_bar: bool = False) → Path#

Save current image as PNG, PDF, or TIFF.

When title, colorbar, or show_scale_bar are enabled, the output is a publication-quality figure rendered via matplotlib. Otherwise a raw colormapped image is saved directly (faster, exact pixel output).

Parameters:
  • path (str or pathlib.Path) – Output file path.

  • idx (int, optional) – Image index in gallery mode. Defaults to current selected_idx.

  • format (str, optional) – ‘png’, ‘pdf’, or ‘tiff’. If omitted, inferred from file extension.

  • dpi (int, default 150) – Output DPI.

  • title (bool or str, default False) – True uses the widget title, a string sets a custom title.

  • colorbar (bool, default False) – Include a colorbar showing the intensity mapping.

  • show_scale_bar (bool, default False) – Include a scale bar (requires pixel_size > 0).

Returns:

The written file path.

Return type:

pathlib.Path

set_panel_frame(panel: int | str, frame: int) → Self#

Set the displayed frame for one local stack panel.

Static panels have one frame and therefore only accept frame 0. Negative indices follow normal Python indexing, so -1 selects the final frame (useful for Velox/EDS acquisitions whose exported HAADF is the last survey frame).

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

cmap

Canvas recolors to the chosen map

More menu: Color shared

panel_cmaps, panel_cmaps_memory

Shared by default. Turn off to let the Color dropdown edit only the selected gallery panel; turn on for one shared colormap, then turn off again to restore the previous individual panel colormaps

Panel identity markers

marker_colors, marker_style, row_markers, col_markers

Optional panel colors plus row/column group frames make panels easy to reference in notebooks, reports, and agent instructions

Local panel annotations

panel_annotations

Optional multiple in-image labels per panel, placed by corner, normalized point, or normalized region box

Geometric panel overlays

panel_overlays

Optional circle and rectangle overlays in data or relative coordinates, with stroke/fill opacity, dashed/dotted line styles, and z-order; More -> Overlay Edit allows live select, move, resize, delete, and reset

Contrast min / max sliders

vmin, vmax

Display clamp changes; histogram markers move

Auto-contrast toggle

auto_contrast

Re-fits vmin/vmax to the percentile range

More menu: Contrast

contrast_preset

Applies scientist-friendly percentile ranges such as 1-99, 2-98, and 3-97; the histogram stays visible below the image

Log-scale toggle

log_scale

Intensity mapped through log

FFT toggle

show_fft

Canvas shows the power spectrum; lattice spots appear

FFT window toggle

fft_window

Apodization on/off (ringing at edges differs)

FFT quality labels

fft_metrics

Compact in-panel label reports FFT sharpness, peak count, and peak SNR from the cached FFT magnitude

FFT zoom / pan

Browser-local per FFT panel; FFT Link Zoom and Link Pan controls

Wheel or pinch zoom updates an always-visible N.N× badge in that FFT panel; reset returns Show2D’s 2.0× FFT default

Viewer chrome preset

ui_mode plus explicit show_* kwargs

Applies shared display presets; see Viewer UI controls

Control visibility

show_controls, controls_collapsed

Permanently remove controls or temporarily collapse them behind the top GUI toggle

Title visibility

show_title

Top title row shows/hides

Stats visibility

show_stats

Mean/min/max/std readout shows/hides

Panel title visibility

show_panel_titles, panel_title_font_size, panel_title_style

Per-panel labels show/hide, resize, and optionally get title chrome such as background, border, and padding

Rich panel title spans

panel_title_spans

Optional structured text / math / color spans for symbols such as λ and χ² in panel titles, panel menus, stats, saved state, and exported HTML

Scale bar toggle

show_scale_bar (show_scale_bar in saved state)

Calibrated bar shows/hides (needs pixel_size > 0)

Scale bar style

scale_bar_panels, scale_bar_length, scale_bar_label, scale_bar_style

Restrict scale bars to selected panels and control exact publication text, font, outline, label spacing, offset, and bar thickness

Gallery gap and borders

panel_gap_px, inter_panel_gap_color, gallery_outer_border_px, gallery_outer_border_color, panel_inner_border_px, panel_inner_border_color

Separately controls the layer between panels, the outside gallery frame, and each panel’s own inner stroke for browser, SVG, and static previews

Pan (drag)

per-image pan

Image translates; with link_pan all panels move together

Zoom (wheel)

initial_zoom, zoom_row, zoom_col; constructor zoom=, center=(row, col) (full-resolution pixels)

Zooms about the cursor

Smooth toggle

smooth

Off by default: sharp data pixels (nearest neighbour); on: bilinear interpolation. The FFT panel has its own Smooth switch, also off by default

ROI add / drag

roi_active, roi_list, roi_selected_idx

Region overlay; stats panel reports the ROI; saved notebook previews include all ROI overlays and one comparable right-side zoom crop per visible ROI; each roi_list entry gives the shape, the center row/col and the size in full-resolution pixels

Gallery select

selected_idx

Highlights the active panel

Local stack slider / play

panel_frame_indices, panel_frame_counts, panel_playback_fps; set_panel_frame()

Every grayscale 3D list item gets independent slider/play controls; changing one panel does not move another, and constructor-configured playback speed adds no toolbar clutter

Gallery page controls

page_idx, n_pages, panels_per_page, page_labels, page_starred

Switch, star, or play through panel pages without changing the source stack

Panel reorder

panel_order (a permutation of panel indices; [] restores the natural order)

Reorders gallery display without changing source data, labels, stars, or hidden state

Diff mode

diff_mode, diff_reference

Panels render as difference vs the reference

Link Denoise switch (gallery)

denoise_scope

Linked (“all”): denoise edits apply to every panel; unlinked (“panel”): edits apply to the selected panel only

Denoise at construction

denoise=, denoise_sigma=, denoise_bin= (scalar for every panel, or one per panel)

Show2D(images, denoise="anscombe", denoise_sigma=8.0) shows the filtered view from the first paint with the switch on; a per-panel list selects per-panel scope

Denoise master

denoise_enabled

Off shows raw pixels and hides the banner without discarding method, sigma, bin, or per-panel settings

Denoise Settings

show_denoise

Expands/collapses the Method, sigma, and bin editor without changing whether the effect is active

Filter master

frequency_filter_enabled

Turns frequency filtering on/off without discarding cutoff or band settings

Filter Settings

show_frequency_filter

Chooses None, Low-pass, High-pass, or Band-pass and exposes the FFT-ring parameters

More menu: Flip

image_flips_horizontal, image_flips_vertical

Display-only horizontal/vertical flips help compare orientations and point-defect neighborhoods without changing stored arrays

More menu: Rotate

image_rotations, rotation_scope

Display-only 0/90/180/270° rotation for every panel or the selected panel; raw data and (row, col) coordinates stay unchanged

Panel inset plots

inset_plots

Optional per-panel mini line plots for calibration curves, ACF/R sweeps, or other scientific context; hover reports the nearest plotted coordinate

Scale bar placement

scale_bar_position, show_zoom_indicator

Move the scale bar between bottom corners and opt into a zoom badge when a workflow needs a live magnification readout

Rich panel labels and math#

Panel labels can be plain strings, inline math strings, or structured rich spans. Use this for parameter sweeps where the compact panel chrome should say λ, χ², σ, or similar symbols instead of spelling out the word.

from quantem.widget import Show2D

Show2D(
    [raw, residual],
    labels=[
        r"$\lambda=0.03$ raw",
        r"$\chi^2$/pixel residual",
    ],
    show_stats=True,
)

The frontend renders common Greek symbols plus simple superscripts/subscripts without requiring MathJax or KaTeX. It also normalizes doubled backslashes from JSON/state files, so \\lambda is rendered as λ rather than as raw markup. The same rich label path is used by panel titles, the Panels menu, the stats row, and exported standalone HTML.

For mixed color or explicit math spans, use panel_title_spans. Each span can contain text, math, and optional color:

Show2D(
    [raw, filtered, residual],
    labels=["raw", "filtered", "residual"],
    panel_title_spans=[
        [{"math": r"\lambda=0.03"}, {"text": " raw"}],
        [{"text": "filtered", "color": "#34d399"}],
        [{"math": r"\chi^2"}, {"text": "/pixel residual"}],
    ],
)

Use panel_annotations when the label belongs to a local region inside a panel instead of the whole panel. An annotation can also use math or spans, so a panel can have both a rich title and multiple local callouts:

Show2D(
    [raw, residual],
    panel_title_spans=[
        [{"math": r"\lambda=0.03"}, {"text": " raw"}],
        [{"math": r"\chi^2"}, {"text": "/pixel"}],
    ],
    panel_annotations={
        0: [
            {"math": r"\lambda", "position": "top-left", "variant": "pill"},
            {
                "spans": [{"text": "ROI "}, {"text": "A", "color": "#60a5fa"}],
                "box": [0.18, 0.25, 0.30, 0.16],
                "variant": "callout",
            },
        ],
        1: {"math": r"\chi^2", "position": "top-right", "variant": "outline"},
    },
)

Circle and rectangle overlays#

Use panel_overlays when the figure needs reproducible geometric callouts in addition to analysis ROIs. Overlay coordinates use microscope image coordinates by default: (row, col) for centers and (row0, col0, row1, col1) for boxes. The same state is rendered in live Jupyter widgets, saved notebook state, and standalone HTML exports.

from quantem.widget import Show2D

Show2D(
    [raw, denoised, residual],
    labels=["raw", "denoised", "residual"],
    panel_overlays={
        "raw": [
            {
                "shape": "circle",
                "center": (96, 88),
                "radius": 14,
                "color": "#60a5fa",
                "line_width": 3,
                "line_style": "dashed",
            },
            {
                "shape": "rect",
                "box": (48, 58, 126, 146),
                "color": "#facc15",
                "fill_color": "#facc15",
                "fill_opacity": 0.12,
                "line_dash": [6, 2, 1, 2],
                "z_order": 1,
            },
        ],
        "denoised": {
            "shape": "rect",
            "box": (75, 67, 117, 109),
            "color": "#34d399",
            "line_width": 2,
            "line_style": "dotted",
        },
    },
)

Overlay strokes are solid by default. Set line_style="dashed", line_style="dotted", or line_style="dashdot" for common scientific callouts, or pass line_dash=[on, off, ...] for an exact canvas dash pattern.

A flat list of shapes without panel= draws each shape on every panel. Use coords="relative" when the geometry should follow normalized panel coordinates from 0 to 1:

Show2D(
    [raw, denoised],
    labels=["raw", "denoised"],
    panel_overlays=[
        {
            "shape": "circle",
            "center": (0.5, 0.5),
            "radius": 0.08,
            "coords": "relative",
            "color": "#f87171",
        }
    ],
)

The live widget and exported HTML also expose More -> Overlay Edit when overlays are present. In edit mode, click a circle or rectangle to select it, drag inside to move it, drag an edge to resize it, press Delete to remove the selected overlay, and choose Reset Overlays to restore the constructor state. Use ROIs when the shape should drive statistics, FFT crops, or Python readback through roi_list.

Presentation and export chrome#

ui_mode="presentation" starts with controls collapsed so the scientific image gets the first view. It still leaves a compact Controls button for adjusting the widget and an Export button for saving the current standalone HTML:

w = Show2D(
    [raw, residual],
    labels=[r"$\lambda=0.03$ raw", r"$\chi^2$/pixel"],
    ui_mode="presentation",
    show_stats=True,
)
w.export_html("lambda_sweep.html", encoding="uint8")

In live Jupyter, the Export menu can request exact or uint8 standalone HTML through the Python backend. In standalone HTML, the Export button downloads the current embedded page using the representation already present in that file.

For Illustrator or Inkscape, use the Export menu’s SVG item or call w.export_svg(...). Show2D writes a hybrid publication SVG: measured image panels remain embedded rasters, while panel titles, annotations, geometric overlays, inset plots, scale bars, colorbars, and group markers are editable SVG objects that match the current figure state.

Publication SVG typography and layout keys#

Use these keys when Show2D should produce a publication figure that can go directly to Illustrator or Inkscape.

Panel title fonts#

labels set the panel title text. panel_title_font_size sets the size, and panel_title_style controls typography and placement:

PUBLICATION_FONT = (
    "Nimbus Sans, Helvetica, Arial, "
    "Liberation Sans, DejaVu Sans, sans-serif"
)

Show2D(
    panels,
    labels=["a 0° scan", "b 90° scan", "c combined"],
    panel_title_font_size=16,
    panel_title_style={
        "font_family": PUBLICATION_FONT,
        "font_weight": 700,
        "fg": "#ffffff",
        "outline_color": "#000000",
        "outline_width": 2.2,
        "x": 0.035,
        "y": 0.035,
        "anchor": "top-left",
        "align": "left",
    },
)

To match a published PDF, inspect its embedded fonts and put the matching family first:

pdffonts path/to/published_figure.pdf
fc-match "Helvetica"

If the PDF text was outlined or rasterized, no editable text font may be reported; use the source figure script or the closest installed Helvetica-like family instead.

Accepted panel_title_style keys:

Key

Meaning

font_family

CSS/SVG font-family stack, for example "Helvetica, Arial, sans-serif"

font_weight

Numeric or named weight, for example 700 or "bold"

fg

Text fill color

outline_color, outline_width

Text stroke used for publication contrast

x, y

Relative panel coordinates from 0 to 1

anchor

top-left, top-center, top-right, center, bottom-left, etc.

offset

Pixel nudge (dx, dy) after relative placement

align

Text alignment fallback when x/y are not supplied

bg, border_color, border_width, pad_x, pad_y, radius, opacity, max_width

Optional title chrome

Local annotation fonts#

Use panel_annotations for multiple labels inside the same image panel. Each annotation can have its own font, color, outline, and position:

Show2D(
    panels,
    labels=["f composite on 0° HAADF"],
    panel_annotations={
        "f composite on 0° HAADF": [
            {
                "text": "Ba+Ti",
                "x": 0.20,
                "y": 0.15,
                "anchor": "center",
                "align": "center",
                "font_family": PUBLICATION_FONT,
                "font_size": 15,
                "font_weight": 800,
                "color": "#ff4dff",
                "outline_color": "#000000",
                "outline_width": 1.8,
                "variant": "plain",
            },
            {
                "text": "Sr",
                "x": 0.80,
                "y": 0.15,
                "anchor": "center",
                "align": "center",
                "font_family": PUBLICATION_FONT,
                "font_size": 15,
                "font_weight": 800,
                "color": "#58ff58",
                "outline_color": "#000000",
                "outline_width": 1.8,
                "variant": "plain",
            },
        ],
    },
)

Use x and y to attach a label to a physical region of the panel. Use box=[left, top, width, height] when the label describes an area. Use variant="plain" for text-only publication labels, or badge, pill, outline, and callout for report-style labels.

Scale bar fonts and placement#

scale_bar_panels limits the bar to one or more panels. Values can be panel indices or label strings. scale_bar_length is in the physical unit implied by sampling and units; scale_bar_label overrides the displayed text.

Show2D(
    panels,
    labels=labels,
    sampling=0.0105,
    units="nm",
    scale_bar_panels=["f corrected combined"],
    scale_bar_length=2.0,
    scale_bar_label="2 nm",
    scale_bar_style={
        "font_family": PUBLICATION_FONT,
        "font_size": 16,
        "font_weight": 700,
        "color": "#ffffff",
        "outline_color": "#000000",
        "outline_width": 1.3,
        "bar_height": 5,
        "label_gap": 5,
        "offset": (0, -8),
    },
    show_zoom_indicator=False,
)

Accepted scale_bar_style keys:

Key

Meaning

font_family, font_size, font_weight

Scale-bar label typography

color

Bar and label fill color

outline_color, outline_width

Label text stroke

shadow_color

Fallback label shadow when no outline is used; also opts into a small scale-bar shadow

bar_height

Bar thickness in SVG/browser CSS pixels

label_gap

Pixels between label baseline and bar

offset

Pixel nudge (dx, dy) for the whole scale bar

Pixel-perfect gutters#

Use explicit gallery chrome controls for manuscript grids:

Show2D(
    panels,
    labels=labels,
    columns=3,
    panel_gap_px=2,
    inter_panel_gap_color="#000000",
    gallery_outer_border_px=2,
    gallery_outer_border_color="#000000",
    panel_inner_border_px=1,
    panel_inner_border_color="#000000",
)

panel_gap_px and inter_panel_gap_color control only the layer between panels. gallery_outer_border_* controls the frame around the whole grid. panel_inner_border_* controls the stroke drawn inside each image panel.

Which denoise filter should I use?#

The Denoise controls are hidden behind their own toggle by default; everything here is display-only (the stored array, the stats row, and raw exports keep the original counts, and an active denoise always announces itself with a one-line banner). Three methods cover the space and binning is a separate knob: for a binned Poisson smooth pick Poisson (Anscombe) and set Bin 2.

Your data

Use

Why

Sparse EDS / counting maps

Poisson (Anscombe), Bin 2, sigma 6-10

Respects Poisson count statistics; the standard choice for element maps

Very sparse maps (single counts)

Poisson (Anscombe), Bin 4, sigma 8-12

More SNR from binning before smoothing

HAADF / decent-dose images

Gaussian, Bin 1, sigma 1-2 (or nothing)

The data is not count-starved; a light smooth is enough

Anything quantitative (FFT, intensities, stats)

None

Measure on raw counts; the stats row is always computed from raw data

From Python, the same ladder is denoise="anscombe", denoise_bin=2, denoise_sigma=8 (per-panel lists supported for A/B galleries).

Reuse ROI coordinates in notebooks and agents#

ROIs are synced in roi_list and saved in state_dict(). Each entry is a dict with the shape ("circle", "square", "rectangle" or "annular"), the center row and col, and the size (radius, radius_inner for an annulus, width and height for a rectangle) in full-resolution pixels. Set the list from Python to place ROIs, and read it back after drawing them in the browser:

w = Show2D(img)
w.roi_list = [{
    "shape": "circle", "row": 72, "col": 65, "radius": 12, "radius_inner": 6,
    "width": 24, "height": 24, "color": "#4fc3f7", "line_width": 2, "highlight": False,
}]
w.roi_active = True
roi = w.roi_list[0]
roi["row"], roi["col"], roi["radius"]  # (72, 65, 12)

Save and restore a view#

state_dict() returns the display state (ROIs, selected panel, hidden panels, panel order, local stack frames, contrast, colormap, FFT, denoise and filter, zoom and scale-bar settings) without the image data. save(path) writes it to a file, and the state= argument restores it on a new widget over the same images:

w = Show2D([raw, corrected, residual], labels=["raw", "corrected", "residual"])
w.show_fft = True
w.save("defect_a.json")

Show2D([raw, corrected, residual], state="defect_a.json")

The file is {"schema": "quantem.widget-state/2", "widget_name", "widget_version", "state"}, the same for every widget with save. A file of another schema (or of an earlier release, which has none) and a state key the widget does not save raise ValueError before anything is applied; an earlier file is not converted.

Add scientific inset plots to panels#

Advanced figure-making sometimes needs a compact plot inside each image panel: for example an autocorrelation score versus an R ratio while reviewing automatic denoising calibration. Use inset_plots for that per-panel context. The top-level parameter stays singular and readable, while each dictionary keeps the plot data, placement, labels, and style together.

Show2D(
    denoised_panels,
    labels=["candidate A", "candidate B", "candidate C"],
    inset_plots=[
        {
            "x": r_values,
            "y": acf_values_for_panel,
            "point": (best_r, best_acf),
            "xlabel": "R",
            "ylabel": "ACF",
            "legend": "ACF/R",
            "annotation": f"R*={best_r:.2f}",
            "position": "bottom-right",
            "margin": 24,
            "size": 0.36,
            "height": 0.26,
            "show_ticks": True,
            "xticks": [0, 1],
            "yticks": [0, 1],
            "line_width": 2.6,
            "background_alpha": 0.58,
            "border_width": 0,
        }
        for acf_values_for_panel, best_r, best_acf in calibration_results
    ],
    scale_bar_position="bottom-left",
    show_zoom_indicator=False,
)

For normal notebooks, prefer position plus margin, size, and height. Use box=[left, top, width, height] only when a publication figure needs exact normalized panel coordinates. border_width=0 gives a clean no-frame look; increase background_alpha or use a subtle border_color when the underlying image is noisy. On hover, the live widget reports the nearest plotted coordinate using the axis labels, such as R 0.465 · ACF 0.48.

If inset_plots is present, the live widget shows an Inset Chart switch in the More menu. A scientist can hide the chart during image inspection, turn it back on for reporting, or drag the chart inside the panel. Dragging previews freely and then snaps to the closest corner on release, updating position and margin in the widget state.

Remove a background or isolate a periodicity#

Frequency Filter is deliberately separate from Denoise. Denoise promises a cleaner view of the measurement; High-pass and Band-pass deliberately remove real signal, so their displayed pixels must not be treated as measurable raw counts. The stored array, statistics row, and raw exports remain unchanged.

# Flatten a slow brightness gradient.
Show2D(eds_map, show_fft=True,
       frequency_filter="highpass", frequency_filter_cutoff=0.08)

# Isolate a lattice-frequency ring.
Show2D(lattice, show_fft=True,
       frequency_filter="bandpass",
       frequency_filter_center=0.32,
       frequency_filter_width=0.08)

Parameters are fractions of Nyquist from 0 to 1. Drag the cyan FFT ring to select the cutoff or band center by eye. The FFT overlay dims rejected frequencies: Low-pass keeps the clear area inside the ring, High-pass keeps the clear area outside, and Band-pass keeps only the clear annulus. Filter and its More-menu toggle are off by default; turning the master on with no remembered mode starts with Low-pass. Denoise and Filter are chainable in the fixed order Denoise then Filter; each active operation has its own banner. Turn the Filter master off or choose None to restore the unfiltered view without losing the settings.

For paged galleries, FFT work is demand-driven: only panels visible on the current page are transformed. Visiting another page computes that page once and retains the bounded cache for later return visits.

FFT quality labels#

Pass show_fft=True to show the FFT panel. By default, fft_metrics=True adds a small white label inside each FFT panel with three quick checks: sharpness, peak count, and peak SNR. These values are computed from the FFT magnitude already used for rendering, so the label does not trigger a second FFT. Set fft_metrics=False when a clean FFT image is more important than the readout.

The first FFT for an image, local panel frame, ROI, or window configuration may take a moment on large data. After that, Show2D reuses that bounded cache entry for redraws, zoom/pan, contrast changes, metric labels, and return visits to the same slice. During a first-time slice computation, the previous valid FFT stays visible instead of flashing to a dark loading panel.

Each interactive FFT panel also carries its own bottom-left zoom multiplier. It starts at 2.0×, follows wheel and touch-pinch zoom immediately, and returns to 2.0× on double-click, double-tap, or Reset. In a gallery, unlinked FFTs report independent values; enabling FFT Link Zoom makes their values move together without changing the real-space zoom.

Live image updates#

Use set_image() to trigger a new browser render in an already displayed Show2D widget. Keep a reference to the widget object, display it once, then replace the image or gallery data through that method:

import numpy as np
from quantem.widget import Show2D

w = Show2D(first_image, labels=["initial"])
w

for step, next_image in enumerate(image_stream, start=1):
    w.set_image(next_image, labels=[f"step {step}"])

For a gallery, pass a 3D stack (N, H, W) and one label per panel:

w.set_image(
    np.stack([raw, filtered, residual]),
    labels=["raw", "filtered", "residual"],
)

Independent local stack panels#

A bare 3D array still means a static gallery of N images. To give gallery panels their own frame or slice axes, pass a Python list whose 3D items are each shaped (frames, rows, cols). Every grayscale 3D list item becomes one panel with its own slider, play/pause control, frame count, and current frame. Counts may differ between panels. RGB(A) list items keep the color-image behavior described in the constructor reference.

This is useful for tomography or multislice studies that produce several reconstruction volumes. The scientist can keep four methods, regularization settings, or slice thicknesses side by side, stop each one at the depth where a feature or artifact is clearest, and retain linked spatial context without forcing all panels onto one global slice index:

from quantem.widget import Show2D

reconstructions = [
    recon_8_slices_20A,
    recon_16_slices_10A,
    recon_regularized,
    recon_alternative,
]

w = Show2D(
    reconstructions,
    labels=[
        "8 slices x 20 A",
        "16 slices x 10 A",
        "regularized",
        "alternative",
    ],
    panel_frame_indices=[3, 7, -1, 0],
    panel_playback_fps=4,
    columns=2,
    link_zoom=True,
    link_pan=True,
)
w.set_panel_frame("16 slices x 10 A", 8)
w

Use a list even when all reconstructions happen to have the same slice count; the outer list is what declares independent local stacks. Use Show3D instead when all panels should advance together on one global frame or slice axis.

The list may also mix stack panels with ordinary 2D images:

w = Show2D(
    [eds_sum_map, haadf_stack, ti_map, o_map],
    labels=["EDS sum", "HAADF", "Ti", "O"],
    panel_frame_indices=[0, -1, 0, 0],
    columns=2,
    auto_contrast=True,
)
w

Only the HAADF panel gets an in-panel slider and play button. Each local frame index remains keyed to its source panel when panels are hidden or reordered. Click a stack panel and use the left or right arrow key to scrub it. From Python, use w.set_panel_frame("HAADF", -1).

Set panel_playback_fps when constructing the widget to choose the cadence for all local-stack play buttons without adding another compact control. The default is 10 fps; values above the 30 fps browser budget are capped. The setting is saved in widget state and carried into standalone HTML exports, while the per-panel playing/paused state remains browser-local so reopening a report does not start playback unexpectedly.

The active panel’s histogram, stats, and FFT follow its current local frame; scrubbing it does not change neighboring panels. state_dict() records panel_frame_indices, and single HTML exports using either encoding="full" or encoding="uint8" contain every local frame. For an interactively restored notebook output, construct with save_state=True; the default save_state=False deliberately stores only a compact static preview rather than embedding the stack payload in the notebook.

For single-image ROI review, that compact saved-notebook preview keeps the scientific marks visible: the fallback PNG draws every visible ROI on the full image and adds one right-side zoom crop per ROI. The zoom crops use a common crop size where image boundaries allow it, so multiple ROIs remain visually comparable. A reader who opens the notebook or report without rerunning the cell can still see the marked features.

set_image() accepts the same mixed list form:

w.set_image(
    [next_eds_map, next_haadf_stack, next_ti_map, next_o_map],
    labels=["EDS sum", "HAADF", "Ti", "O"],
    panel_frame_indices=[0, 0, 0, 0],
)

Watch a growing image folder#

Use Show2D.from_folder(...) when a microscope or reconstruction job writes new 2D images into one folder. Each newly readable file becomes another panel in the existing gallery. The widget object is not rebuilt, so the current selection and the state of panels already present remain stable.

from quantem.widget import Show2D

w = Show2D.from_folder(
    "/data/session/haadf",
    pattern="*.tif",
    watch_interval=2.0,
    page_size=20,
    title="Live HAADF images",
)
w

watch=True is the default. Pass watch=False for a fixed folder or a reproducible script that should update only when you call poll_folder(). Folder galleries default to page_size=20: page controls appear automatically when the 21st ready image arrives. Use another positive integer to change the visible limit, or page_size=None to keep one unpaged gallery. The final page contains only real files, so 45 images form pages of 20, 20, and 5 panels. Folder pages keep selection, stars, hidden state, and ordering keyed to each source file rather than sharing a hidden slot across pages.

To change the grouping, open the folder again with another page_size.

Paging limits the panels, histograms, and FFT views rendered at one time. The current folder implementation still retains the complete full-resolution gallery in Python and transports its display previews to the browser; it is not yet a lazy, bounded-memory source-page cache. Open a smaller file selection when the complete gallery exceeds available memory.

An empty watched folder remains mounted with a waiting view and becomes the real gallery in the same widget model when its first stable file arrives. The compact title-area badge reports Watching, Updating, Waiting for file completion, Watch error, or Stopped; fixed watch=False snapshots do not show the badge.

new_panels = w.poll_folder()       # scan now; return newly appended indices
w.stop_folder_watch()             # pause background scans
w.watch_folder(interval=1.0)      # resume with a different interval
w.close()                         # stop watching and close the widget

Folder watching is append-only. A file already represented in the gallery is not duplicated, an incomplete file is deferred until a later poll, and removing or rewriting a source file does not silently remove or replace an existing panel. An incompatible shape is reported without blocking a later compatible file. Close long-running widgets when the notebook no longer needs them.

Show2D.from_folder(...) reads the scientific image data at its source resolution.

To verify the live path, add genuine EMD files after the widget is visibly mounted and check that the same browser canvas paints each full-resolution panel.

Paged galleries#

Direct Show2D(...) pages are comparison pages. Use them when each view contains the same panel grid across several analysis settings, iterations, or parameter values. A common example is a 4-by-4 reconstruction sweep where each page is one iteration or one denoising parameter, and the panels within the page are the related output images.

These repeated-slot comparison pages are distinct from the sequential item pages created by Show2D.from_folder(..., page_size=20).

Pass a 4D array with shape (pages, panels_per_page, rows, cols):

from quantem.widget import Show2D

w = Show2D(
    reconstruction_sweep,
    labels=[
        "lambda 0.01", "lambda 0.03", "lambda 0.10", "lambda 0.30",
        "lambda 1", "lambda 3", "lambda 10", "lambda 30",
        "raw", "filtered", "residual", "score",
        "phase", "amplitude", "mask", "diagnostic",
    ],
    page_labels=["iteration 10", "iteration 20", "iteration 30"],
    columns=4,
)
w

You can also pass explicit page dictionaries when the page titles naturally belong beside the image data:

w = Show2D(
    [
        {"title": "iteration 10", "images": iter10_panels, "labels": panel_labels},
        {"title": "iteration 20", "images": iter20_panels, "labels": panel_labels},
    ],
    columns=4,
)

Paged galleries keep the Python data model simple: all pages use the same panel count and image shape, the browser renders only the active page, and page stars are stored separately from panel stars. Use star_page(page) from Python (page_starred holds one 0/1 flag per page, so assigning it clears a star), or the star button beside the page slider in the widget. The page row also includes play/pause and a small FPS menu so readers can step through iteration or parameter pages without touching the main image controls. Manual slider scrubbing pauses page playback. For very large 4K sweeps, start with a reduced or representative stack; a future lazy page transport can avoid sending every page to the browser at once.

set_image() is the re-render trigger. Mutating the original NumPy array in place does not notify the frontend. The method sends fresh synced frame_bytes and resets state tied to the old image count or dimensions, including stale hidden panels, stars, view box, ROIs, line profiles, detail tiles, and panel order. Each new frame reaches the browser over the live Jupyter connection; offline=True would only quantize the panels to uint8.