Mark2D#
- class quantem.widget.Mark2D(**kwargs: Any)[source]#
Bases:
AnyWidgetInteractive point picker for 2D images.
Click on an image to select points (atom positions, features, lattice vectors). Supports gallery mode for comparing multiple images, pre-loaded points from detection algorithms, multiple ROI overlays with pixel statistics, snap-to-peak for precise atom column picking, and calibrated distance measurements between points.
- Parameters:
data (array_like) –
Image data. Accepts:
2D array
(H, W)— single image3D array
(N, H, W)— gallery of N imagesList of 2D arrays — gallery (resized to common dimensions)
Dataset2dobject — array and sampling auto-extracted
scale (float, default 1.0) – Display scale factor. Values > 1 enlarge the canvas.
dot_size (int, default 12) – Diameter of point markers in CSS pixels.
max_points (int, default 10) – Maximum number of points per image. Oldest points are removed when the limit is exceeded.
ncols (int, default 3) – Number of columns in the gallery grid (ignored for single images).
labels (list of str, optional) – Per-image labels shown below each gallery tile and in the header. Defaults to
"Image 1","Image 2", etc.marker_border (int, default 2) – Border width of point markers in pixels (0–6). The border grows inward from the marker edge, so the overall marker size stays constant. Set to 0 for borderless markers.
marker_opacity (float, default 1.0) – Opacity of point markers (0.1–1.0).
label_size (int, default 0) – Font size in pixels for the numbered label above each marker.
0means auto-scale relative todot_size.label_color (str, default "") – CSS color for numbered labels (e.g.
"white","#ff0"). Empty string uses the automatic theme color.pixel_size (float, default 0.0) – Pixel size in angstroms. When set, the widget displays a calibrated scale bar and shows point-to-point distances in physical units (angstroms or nanometers).
0means uncalibrated.points (list or ndarray, optional) –
Pre-populate the widget with initial points. Useful for reviewing or refining positions from an atom-finding algorithm. Accepts:
List of
(row, col)tuples:[(10, 20), (30, 40)]List of dicts with optional shape/color:
[{"row": 10, "col": 20, "shape": "star", "color": "#f00"}]NumPy array of shape
(N, 2)with columns[row, col]For gallery: list of the above, one per image
When
shapeorcolorare omitted, they cycle through the built-in palettes (5 shapes, 10 colors).marker_shape (str, default "circle") – Active marker shape for new points. One of
"circle","triangle","square","diamond","star". Synced bidirectionally — changes in the UI are reflected in Python.marker_color (str, default "#f44336") – Active marker color for new points (CSS color string). Synced bidirectionally — changes in the UI are reflected in Python.
snap_enabled (bool, default False) – Whether snap-to-peak is active. When
True, clicked positions are snapped to the local intensity maximum withinsnap_radius.snap_radius (int, default 5) – Search radius in pixels for snap-to-peak.
title (str, default "") – Title displayed in the widget header. Empty string shows
"Mark2D".show_stats (bool, default True) – Show statistics bar (mean, min, max, std) below the canvas.
cmap (str, default "gray") – Colormap for image rendering. Options:
"gray","inferno","viridis","plasma","magma","hot".auto_contrast (bool, default True) – Enable automatic contrast via 2–98% percentile clipping. When
False, contrast is controlled by the histogram slider.log_scale (bool, default False) – Apply log(1+x) transform before rendering. Useful for images with large dynamic range (e.g. diffraction patterns).
show_fft (bool, default False) – Show FFT power spectrum alongside the image.
disabled_tools (list of str, optional) – Tool groups to disable in the frontend UI/interaction layer. This is useful for shared notebooks where viewers should not be able to modify selected controls or annotations. Supported values:
"points","roi","profile","display","marker_style","snap","navigation","view","export","all".disable_points (bool, default False) – Convenience flag equivalent to including
"points"indisabled_tools.disable_roi (bool, default False) – Convenience flag equivalent to including
"roi"indisabled_tools.disable_profile (bool, default False) – Convenience flag equivalent to including
"profile"indisabled_tools.disable_display (bool, default False) – Convenience flag equivalent to including
"display"indisabled_tools.disable_marker_style (bool, default False) – Convenience flag equivalent to including
"marker_style"indisabled_tools.disable_snap (bool, default False) – Convenience flag equivalent to including
"snap"indisabled_tools.disable_navigation (bool, default False) – Convenience flag equivalent to including
"navigation"indisabled_tools.disable_view (bool, default False) – Convenience flag equivalent to including
"view"indisabled_tools.disable_export (bool, default False) – Convenience flag equivalent to including
"export"indisabled_tools.disable_all (bool, default False) – Convenience flag equivalent to
disabled_tools=["all"].hidden_tools (list of str, optional) – Tool groups to hide from the frontend UI. Hidden tools are also interaction-locked (equivalent to disabled for behavior), but their controls are not rendered. Supported values:
"points","roi","profile","display","marker_style","snap","navigation","view","export","all".hide_points (bool, default False) – Convenience flag equivalent to including
"points"inhidden_tools.hide_roi (bool, default False) – Convenience flag equivalent to including
"roi"inhidden_tools.hide_profile (bool, default False) – Convenience flag equivalent to including
"profile"inhidden_tools.hide_display (bool, default False) – Convenience flag equivalent to including
"display"inhidden_tools.hide_marker_style (bool, default False) – Convenience flag equivalent to including
"marker_style"inhidden_tools.hide_snap (bool, default False) – Convenience flag equivalent to including
"snap"inhidden_tools.hide_navigation (bool, default False) – Convenience flag equivalent to including
"navigation"inhidden_tools.hide_view (bool, default False) – Convenience flag equivalent to including
"view"inhidden_tools.hide_export (bool, default False) – Convenience flag equivalent to including
"export"inhidden_tools.hide_all (bool, default False) – Convenience flag equivalent to
hidden_tools=["all"].
- selected_points#
Currently placed points, synced bidirectionally with the widget.
Single image: flat list of point dicts
[{"row": 10, "col": 20, "shape": "circle", "color": "#f44336"}, ...]Gallery mode: list of lists, one per image
[[point, ...], [point, ...], ...]
Each point dict has keys:
row(int),col(int),shape(str),color(str). You can set this attribute from Python to update the widget in real time.- Type:
- roi_list#
Currently defined ROI overlays, synced with the widget. Each ROI is a dict with keys:
id(int) — unique identifiermode(str) —"circle","square", or"rectangle"row,col(int) — center position in image pixelsradius(int) — radius for circle/square modesrectW,rectH(int) — width/height for rectangle modecolor(str) — CSS stroke coloropacity(float) — opacity (0.1–1.0)
Set from Python to programmatically define ROIs, or read after interactive use to retrieve user-defined regions.
- Type:
Notes
Marker shapes: circle, triangle, square, diamond, star (5 shapes that cycle automatically).
Marker colors: 10 colors that cycle: red, green, blue, orange, purple, cyan, yellow, pink, lime, deep orange.
Snap-to-peak: When enabled in the UI, clicking snaps the point to the local intensity maximum within a configurable search radius. Useful for precise atom column picking on HAADF-STEM images.
Distance measurements: Distances between consecutive points are displayed in the point list. With
pixel_sizeset, distances are shown in angstroms (< 10 Å) or nanometers (>= 10 Å).ROI statistics: When an ROI is active, the widget computes and displays mean, standard deviation, min, max, and pixel count for the region. When multiple ROIs exist, a summary table shows all ROI stats. Active ROIs also show dotted horizontal/vertical center guide lines.
Pairwise distances: When 2+ points are placed, a table below the point list shows distances between all pairs of points.
Line profile: Toggle “Profile” mode in the controls, then click two points to sample intensity along a line. A sparkline graph with calibrated x-axis appears below the canvas. Also available programmatically via
set_profile(),profile_values, andprofile_distance.Keyboard shortcuts (widget must be focused):
Delete/Backspace— remove last point (undo)Ctrl+Z/Cmd+Z— undoCtrl+Shift+Z/Cmd+Shift+Z— redo1–6— select ROI #1–6Arrow keys — nudge active ROI by 1 pixel
Arrow keys (no ROI, gallery) — navigate between images
Escape— deselect ROI
Examples
Basic point picking:
>>> import numpy as np >>> from quantem.widget import Mark2D >>> img = np.random.rand(256, 256).astype(np.float32) >>> w = Mark2D(img, scale=1.5, max_points=5) >>> w # display in notebook; click to place points >>> w.selected_points # read back placed points
Pre-loaded points from a detection algorithm:
>>> peaks = find_atom_columns(img) # returns (N, 2) array >>> w = Mark2D(img, points=peaks, pixel_size=0.82) >>> # Points appear immediately; user can add/remove/adjust
Pre-loaded points with custom appearance:
>>> pts = [ ... {"row": 200, "col": 100, "shape": "star", "color": "#ff0"}, ... {"row": 250, "col": 150, "shape": "diamond", "color": "#0ff"}, ... ] >>> w = Mark2D(img, points=pts, marker_border=0, marker_opacity=0.8)
Gallery mode for comparing multiple images:
>>> imgs = [original, filtered, denoised] >>> w = Mark2D(imgs, ncols=3, labels=["Raw", "Filtered", "Denoised"]) >>> # Points are tracked independently per image
Gallery with per-image pre-loaded points:
>>> per_image_pts = [[(10, 20)], [(30, 40), (50, 60)], []] >>> w = Mark2D(imgs, points=per_image_pts)
Programmatic ROI management:
>>> w = Mark2D(img) >>> w.add_roi(row=128, col=128, mode="circle", radius=30, color="#0f0") >>> w.add_roi(row=200, col=200, mode="rectangle", rect_w=80, rect_h=40) >>> w.roi_list # inspect ROI parameters >>> w.roi_center() # center of most recently added ROI -> (200, 200) >>> w.roi_radius() # radius for circle/square, None for rectangle >>> w.roi_size() # shape-aware size dict (e.g. width/height for rectangle) >>> w.roi_list = [] # clear all ROIs
Snap-to-peak for precise atom picking:
>>> w = Mark2D(haadf_image, snap_enabled=True, snap_radius=8, ... pixel_size=0.82) >>> # Clicks auto-snap to the nearest intensity maximum
Custom marker defaults:
>>> w = Mark2D(img, marker_shape="star", marker_color="#ff9800") >>> # All new points will be orange stars until changed in the UI
Human-friendly tool locking:
>>> w = Mark2D(img, disable_points=True, disable_roi=True, disable_display=True) >>> w_read_only = Mark2D(img, disable_all=True) >>> w_clean = Mark2D(img, hide_display=True, hide_export=True)
Save and restore full widget state (state portability):
>>> # User A: create widget, place points and ROIs interactively >>> w = Mark2D(img, pixel_size=1.5) >>> # ... user clicks to place points, adds ROIs, enables snap ... >>> state = { ... "points": w.selected_points, ... "rois": w.roi_list, ... "marker_shape": w.marker_shape, ... "marker_color": w.marker_color, ... "snap_enabled": w.snap_enabled, ... "snap_radius": w.snap_radius, ... } >>> # User B: restore exact same state on another machine >>> w2 = Mark2D(img, pixel_size=1.5, ... points=state["points"], ... marker_shape=state["marker_shape"], ... marker_color=state["marker_color"], ... snap_enabled=state["snap_enabled"], ... snap_radius=state["snap_radius"]) >>> w2.roi_list = state["rois"]
Line profile (programmatic):
>>> w = Mark2D(img, pixel_size=0.82) >>> w.set_profile((10, 20), (100, 200)) >>> w.profile_values # sampled intensities along the line >>> w.profile_distance # total distance in angstroms
Export points as NumPy array:
>>> w = Mark2D(img, points=[(10, 20), (30, 40)]) >>> w.points_as_array() # shape (2, 2), columns [row, col] >>> w.points_as_dict() # [{"row": 10, "col": 20}, ...]
Key Methods
- Mark2D.set_image(data, labels=None)[source]#
Replace the displayed image(s) and reset all points.
Can switch between single-image and gallery modes. All existing points are cleared; ROIs are preserved.
- Parameters:
Examples
>>> w = Mark2D(img1) >>> w.set_image(img2) # switch to a different image >>> w.set_image([img1, img2, img3], labels=["A", "B", "C"])
- Mark2D.save_image(path: str | Path, *, idx: int | None = None, include_markers: bool = True, format: str | None = None, dpi: int = 150) Path[source]#
Save current image as PNG or PDF, optionally with marker overlays.
- Parameters:
path (str or pathlib.Path) – Output file path.
idx (int, optional) – Image index in gallery mode. Defaults to current selected_idx.
include_markers (bool, default True) – If True, render marker points on the exported image.
format (str, optional) – ‘png’ or ‘pdf’. If omitted, inferred from file extension.
dpi (int, default 150) – Output DPI metadata.
- Returns:
The written file path.
- Return type:
- Mark2D.add_roi(row, col, shape='square', radius=30, width=60, height=40, color='#0f0', opacity=0.8)[source]#
Add an ROI overlay to the widget.
Multiple ROIs can be added. Each gets a unique ID. In the widget, the user can click ROI centers to select them, drag to reposition, and adjust size/color/opacity interactively. The widget also displays pixel statistics (mean, std, min, max) for the active ROI.
- Parameters:
row (int) – Center position in image pixel coordinates (row, col).
col (int) – Center position in image pixel coordinates (row, col).
shape (str, default "circle") – ROI shape. One of
"circle","square", or"rectangle".radius (int, default 30) – Radius in pixels for circle and square modes.
width (int, default 60) – Width in pixels for rectangle mode.
height (int, default 40) – Height in pixels for rectangle mode.
color (str, default "#0f0") – Stroke color as a CSS color string (e.g.
"#ff0","red").opacity (float, default 0.8) – Stroke opacity (0.1–1.0).
Examples
>>> w = Mark2D(img) >>> w.add_roi(128, 128) # green circle at center >>> w.add_roi(50, 50, shape="square", radius=20, color="#ff0") >>> w.add_roi(200, 100, shape="rectangle", width=80, height=30) >>> len(w.roi_list) # 3
- Mark2D.clear_rois()[source]#
Remove all ROI overlays.
Examples
>>> w.add_roi(100, 100) >>> w.add_roi(200, 200) >>> w.clear_rois() >>> w.roi_list # []
- Mark2D.roi_center(index: int | None = None, roi_id: int | None = None)[source]#
Return ROI center coordinates as
(row, col).By default, returns the center of the most recently added ROI.
- Mark2D.roi_radius(index: int | None = None, roi_id: int | None = None)[source]#
Return ROI radius for
circle/squareROIs.For
rectangleROIs, returnsNone(useroi_size()for rectangle width/height). By default, queries the most recently added ROI.
- Mark2D.roi_size(index: int | None = None, roi_id: int | None = None)[source]#
Return shape-aware ROI size information.
circle/square->{"shape", "radius", "diameter"}rectangle->{"shape", "width", "height"}
- Mark2D.set_profile(start: tuple, end: tuple)[source]#
Set a line profile between two points.
The profile is drawn on the canvas and intensity values are sampled along the line with bilinear interpolation. A sparkline graph appears below the canvas.
- Parameters:
Examples
>>> w = Mark2D(img, pixel_size=0.82) >>> w.set_profile((10, 20), (100, 200)) >>> w.profile_values # sampled intensities along the line
- Mark2D.points_as_array()[source]#
Return placed points as a NumPy array of shape
(N, 2)with columns[row, col].In gallery mode, returns a list of arrays (one per image).
Examples
>>> w = Mark2D(img, points=[(10, 20), (30, 40)]) >>> w.points_as_array() array([[10, 20], [30, 40]])
- Mark2D.points_as_dict()[source]#
Return placed points as a list of
{"row": int, "col": int}dicts.In gallery mode, returns a list of lists (one per image).
Examples
>>> w = Mark2D(img, points=[(10, 20), (30, 40)]) >>> w.points_as_dict() [{'row': 10, 'col': 20}, {'row': 30, 'col': 40}]
- Mark2D.clear_points()[source]#
Remove all placed points from all images.
Examples
>>> w.clear_points() >>> w.selected_points # [] or [[], [], ...]
- Mark2D.state_dict()[source]#
Return a dict of all restorable widget state.
Use this to persist the widget state across kernel restarts. Pass the returned dict as the
stateparameter to a newMark2Dto restore everything.Examples
>>> w = Mark2D(img, pixel_size=1.5) >>> # ... user places points, adds ROIs, changes settings ... >>> state = w.state_dict() >>> # Later (or after kernel restart): >>> w2 = Mark2D(img, state=state)
- Mark2D.save(path: str)[source]#
Save widget state to a JSON file.
- Parameters:
path (str) – File path to write (e.g.
"analysis.json").
Examples
>>> w = Mark2D(img) >>> # ... place points, add ROIs ... >>> w.save("my_analysis.json") >>> # After kernel restart: >>> w2 = Mark2D(img, state="my_analysis.json")
- Mark2D.load_state_dict(state)[source]#
Restore widget state from a dict returned by
state_dict().- Parameters:
state (dict) – State dict from a previous
state_dict()call. Missing keys are silently skipped.
Examples
>>> state = old_widget.state_dict() >>> new_widget = Mark2D(img) >>> new_widget.load_state_dict(state)
- Mark2D.summary()[source]#
Print a detailed summary of the widget state.
Shows image info, display settings, points with coordinates, ROI details, and marker configuration.
Examples
>>> w = Mark2D(img, points=[(10, 20), (30, 40)], ... pixel_size=0.82, cmap='viridis') >>> w.summary() Mark2D ═══════════════════════════════ Image: 128×128 (0.82 Å/px) Display: viridis | auto contrast | linear ...