playNano.analysis.modules package

Submodules

playNano.analysis.modules.count_nonzero module

Analysis module for counting non-zero data points in an array.

class playNano.analysis.modules.count_nonzero.CountNonzeroModule[source]

Bases: AnalysisModule

Count non-zero pixels in each frame of an AFMImageStack.

This simple analysis module computes the number of non-zero pixels per frame and returns the result as a 1D array.

Version

0.1.0

Initial implementation.

property name: str

Name of the analysis module.

Returns:

The string identifier for this module.

Return type:

str

run(stack, previous_results=None, **params) dict[str, Any][source]

Count non-zero pixels per frame in the AFMImageStack.

Parameters:
  • stack (AFMImageStack) – Stack of AFM frames with .data of shape (n_frames, H, W).

  • previous_results (dict, optional) – Ignored by this module. Included for API compatibility.

  • **params (dict) – Additional parameters (unused).

Returns:

Dictionary with key:
  • ”counts”: np.ndarray of shape (n_frames,), number of non-zero pixels per frame.

Return type:

dict

version = '0.1.0'

playNano.analysis.modules.dbscan_clustering module

DBSCAN clustering on features over the entire stack in 3D (x, y, time).

This module extracts feature points from a previous analysis step, optionally normalizes them, applies DBSCAN, and returns clusters (with noise as label -1 omitted or optionally retained), cluster cores, and a summary.

param coord_key:

Key in previous_results containing features_per_frame.

type coord_key:

str

param coord_columns:

Which keys in each feature-dict to use (e.g. (“x”,”y”)).

type coord_columns:

Sequence[str]

param use_time:

If True and coord_columns length is 2, append frame time as the third dimension.

type use_time:

bool

param eps:

The maximum distance between two samples for them to be considered as in the same neighborhood (in normalized units if normalise=True).

type eps:

float

param min_samples:

The number of samples in a neighborhood for a point to be considered as a core point.

type min_samples:

int

param normalise:

If True, min-max normalize each axis before clustering.

type normalise:

bool

param time_weight:

If given, multiply the time axis by this weight.

type time_weight:

float | None

param **dbscan_kwargs:

Forwarded to sklearn.cluster.DBSCAN.

class playNano.analysis.modules.dbscan_clustering.DBSCANClusteringModule[source]

Bases: AnalysisModule

DBSCAN clustering of features across an AFMImageStack in (x, y, time) space.

This module extracts coordinates from per-frame features, optionally adds time as a third dimension, normalizes the space, and applies DBSCAN clustering. It returns clusters with point metadata, core point means as cluster centers, and a summary of cluster sizes.

Version

0.1.0

Initial implementation.

property name: str

Name of the analysis module.

Returns:

The string identifier for this module: “dbscan_clustering”.

Return type:

str

requires = ['feature_detection', 'log_blob_detection']
run(stack, previous_results: dict[str, Any] | None = None, *, detection_module: str = 'feature_detection', coord_key: str = 'features_per_frame', coord_columns: Sequence[str] = ('centroid_x', 'centroid_y'), use_time: bool = True, eps: float = 0.3, min_samples: int = 5, normalise: bool = True, time_weight: float | None = None, **dbscan_kwargs: Any) dict[str, Any][source]

Perform DBSCAN clustering on detected features in (x, y[, t]) space.

Parameters:
  • stack (AFMImageStack) – The input stack with .data and .time_for_frame() method.

  • previous_results (dict of str to Any, optional) – Output from previous analysis steps. Must contain features under the given detection_module and coord_key.

  • detection_module (str, default="feature_detection") – Which module’s output to use from previous_results.

  • coord_key (str, default="features_per_frame") – Key in previous_results[detection_module] containing the list of per-frame features.

  • coord_columns (Sequence[str], default=("centroid_x", "centroid_y")) – Keys to extract coordinates from each feature. If missing, will fall back to centroid tuple.

  • use_time (bool, default=True) – Whether to append frame timestamp as a third coordinate.

  • eps (float, default=0.3) – Maximum distance for neighborhood inclusion (in normalized units if normalise=True).

  • min_samples (int, default=5) – Minimum number of points in a neighborhood to form a core point.

  • normalise (bool, default=True) – If True, normalize coordinate axes to [0, 1] range before clustering.

  • time_weight (float or None, optional) – Scaling factor for the time axis (after normalization). If None, no weighting is applied.

  • **dbscan_kwargs (dict) – Additional keyword arguments forwarded to sklearn.cluster.DBSCAN.

Returns:

Output dictionary with the following keys:
  • ”clusters”: list of dicts, one per cluster, containing:
    • ”id”: cluster ID (int)

    • ”frames”: list of frame indices

    • ”point_indices”: list of feature indices within frames

    • ”coords”: list of 2D or 3D coordinates (post-normalization)

  • ”cluster_centers”: np.ndarray of shape (n_clusters, D)

    Mean location of each cluster in original coordinate units.

  • ”summary”: dict with:
    • ”n_clusters”: total number of clusters found

    • ”members_per_cluster”: dict of cluster ID to count

Return type:

dict

version = '0.1.0'

playNano.analysis.modules.feature_detection module

Module for threshold based feature detection.

Module: FeatureDetectionModule Detect features in each frame of an AFM image stack through thresholding methods.

class playNano.analysis.modules.feature_detection.FeatureDetectionModule[source]

Bases: AnalysisModule

Detect contiguous features in each frame of an AFM image stack.

This module takes either a user-supplied mask function or a pre-computed boolean mask array, labels connected regions in each frame, filters them by size and edge contact, optionally fills holes, and returns per-frame feature statistics and labeled masks.

Parameters:
  • mask_fn (callable, optional) – A function frame -> bool_2D_array used to generate a mask for each frame. Required if mask_key is not provided.

  • mask_key (str, optional) – Name of a boolean mask array from a previous analysis (e.g. previous_results[“your_mask_key”]). Required if mask_fn is not provided.

  • min_size (int, default=10) – Minimum area (in pixels) for a region to be kept.

  • remove_edge (bool, default=True) – If True, discard any region that touches the frame boundary.

  • fill_holes (bool, default=False) – If True, fill holes in each mask before labeling.

  • hole_area (int or None, default=None) – If set, fills only holes smaller than this area.

  • **mask_kwargs – Additional keyword arguments forwarded to mask_fn(frame, **mask_kwargs).

Raises:
  • ValueError – If neither mask_fn nor mask_key is provided, or if the mask array has the wrong shape/dtype.

  • KeyError – If mask_key is not found in previous_results.

Returns:

  • dict[str, Any] – A dictionary with keys:

    • features_per_frame : list of list of dict Per-frame list of feature stats dicts, each with:

      • ”frame_timestamp” : float

      • ”label” : int

      • ”area” : int

      • ”min”, “max”, “mean” : float

      • ”bbox” : (min_row, min_col, max_row, max_col)

      • ”centroid” : (row, col)

    • labeled_masks : list of np.ndarray The final labeled mask (integer labels) for each frame.

    • summary : dict Aggregate metrics:

      • ”total_frames” : int

      • ”total_features” : int

      • ”avg_features_per_frame” : float

  • Version

  • ——-

  • 0.1.0 – Initial implementation.

Examples

>>> pipeline.add("feature_detection", mask_fn=mask_mean_offset, min_size=20,
...              fill_holes=True, hole_area=50)
>>> result = pipeline.run(stack)
>>> result["summary"]["total_features"]
123
property name: str

Name of the analysis module.

Returns:

The string identifier for this module: “feature_detection”.

Return type:

str

run(stack, previous_results: dict[str, Any] | None = None, *, mask_fn: callable | None = None, mask_key: str | None = None, min_size: int = 10, remove_edge: bool = True, fill_holes: bool = False, hole_area: int | None = None, **mask_kwargs) dict[str, Any][source]

Detect contiguous features on each frame of stack.data.

Parameters:
  • stack (AFMImageStack) – The AFM stack whose .data (3D array) and .time_for_frame() are used.

  • previous_results (dict[str, Any], optional) – Mapping of earlier analysis outputs. If mask_key is given, must contain a boolean mask array under that key.

  • mask_fn (callable, optional) – Function frame->bool array for masking. Required if mask_key is None.

  • mask_key (str, optional) – Key in previous_results whose value is a boolean mask array of same shape as stack.data.

  • min_size (int, default 10) – Minimum area (in pixels) to keep a region.

  • remove_edge (bool, default=True) – If True, discard regions touching any image boundary.

  • fill_holes (bool, default=False) – Whether to fill holes before labeling.

  • hole_area (int or None, default=None) – If set, only fill holes smaller than this area.

  • **mask_kwargs – Passed to mask_fn(frame, **mask_kwargs).

Returns:

{

“features_per_frame”: List[List[dict[str, Any]]], “labeled_masks”: List[np.ndarray], # labeled mask per frame “summary”: {

”total_frames”: int, “total_features”: int, “avg_features_per_frame”: float,

}

}

Return type:

dict[str, Any]

Raises:
  • ValueError – If stack.data is None or not 3D, or mask array invalid, or neither mask_fn nor mask_key provided.

  • KeyError – If mask_key not found in previous_results.

version = '0.1.0'

playNano.analysis.modules.k_means_clustering module

K-Means clustering on features over the entire stack in 3D (x, y, time).

This module extracts a point-cloud from per-frame feature dictionaries (e.g. coordinates + timestamps), optionally normalizes each axis to [0,1], applies K-Means with a user-supplied k, then returns cluster assignments, cluster centers (in original coordinate units), and a summary.

param coord_key:

Key in previous_results whose value is features_per_frame (list of lists of dicts).

type coord_key:

str

param coord_columns:

Which keys in each feature-dict to use (e.g. (“x”,”y”)).

type coord_columns:

Sequence[str]

param use_time:

If True and coord_columns length is 2, append frame time as the third dimension.

type use_time:

bool

param k:

Number of clusters.

type k:

int

param normalise:

If True, min-max normalize each axis before clustering.

type normalise:

bool

param time_weight:

If given, multiply the time axis by this weight.

type time_weight:

float | None

param **kmeans_kwargs:

Forwarded to sklearn.cluster.KMeans.

class playNano.analysis.modules.k_means_clustering.KMeansClusteringModule[source]

Bases: AnalysisModule

Cluster features across all frames using K-Means in 2D or 3D (x, y, [time]).

Extracts point coordinates from per-frame features, applies optional normalization and time weighting, then performs K-Means clustering. Returns cluster assignments, centers in original scale, and a summary report.

Parameters:
  • coord_key (str) – Key in previous_results pointing to ‘features_per_frame’ structure.

  • coord_columns (Sequence[str]) – Keys to extract coordinates from each feature (e.g. (“x”, “y”)).

  • use_time (bool) – If True, appends frame timestamp as a third clustering dimension.

  • k (int) – Number of clusters to fit.

  • normalise (bool) – If True, normalize each axis to [0, 1] before clustering.

  • time_weight (float or None) – Optional multiplier for time axis after normalization.

  • **kmeans_kwargs – Additional keyword arguments passed to sklearn.cluster.KMeans.

  • Version

  • -------

  • 0.1.0 – Initial implementation.

property name: str

Name of the analysis module.

Returns:

The string identifier for this module.

Return type:

str

requires = ['feature_detection', 'log_blob_detection']
run(stack, previous_results: dict[str, Any] | None = None, *, detection_module: str = 'feature_detection', coord_key: str = 'features_per_frame', coord_columns: Sequence[str] = ('centroid_x', 'centroid_y'), use_time: bool = True, k: int, normalise: bool = True, time_weight: float | None = None, **kmeans_kwargs: Any) dict[str, Any][source]

Perform K-Means clustering on features extracted from a stack.

Constructs a coordinate array from features (x, y[, t]), optionally applies normalization and time weighting, and fits k-means to assign clusters.

Parameters:
  • stack (AFMImageStack) – The input image stack providing frame times and data context.

  • previous_results (dict of str to Any, optional) – Dictionary containing outputs from previous analysis steps. Must contain the selected detection_module and coord_key.

  • detection_module (str, default="feature_detection") – Key identifying which previous module’s output to use.

  • coord_key (str, default="features_per_frame") – Key under the detection module that holds per-frame feature dicts.

  • coord_columns (Sequence[str], default=("centroid_x", "centroid_y")) – Keys to extract from each feature for clustering coordinates. If missing, fallback to the “centroid” tuple is attempted.

  • use_time (bool, default=True) – If True and coord_columns is 2D, append frame timestamp as third dimension.

  • k (int) – Number of clusters to compute.

  • normalise (bool, default=True) – Whether to min-max normalize each axis of the feature points before clustering.

  • time_weight (float or None, optional) – Weighting factor for time axis (applied after normalization). Only used if time is included as a third dimension.

  • **kmeans_kwargs (dict) – Additional arguments forwarded to sklearn.cluster.KMeans.

Returns:

A dictionary with the following keys:

  • ”clusters”list of dicts, each with:
    • id : int

    • frames : list of int

    • point_indices : list of int

    • coordslist of tuple

      The normalized coordinates used in clustering for each point in the cluster (e.g., (x, y[, t])).

  • ”cluster_centers”ndarray of shape (k, D)

    Cluster centers in original coordinate units.

  • ”summary”dict
    • ”n_clusters” : int

    • ”members_per_cluster” : dict mapping cluster id to point count

Return type:

dict

Raises:
  • RuntimeError – If the required detection_module output is not found in previous_results.

  • KeyError – If the required coordinate keys are missing in any feature dictionary.

version = '0.1.0'

playNano.analysis.modules.log_blob_detection module

Module for LoG blob detection.

Module: LoGBlobDetectionModule Detect “blobs” in each frame of an AFM image stack using the Laplacian-of-Gaussian method.

Provides automatic multi-scale blob detection and optional radius estimation.

class playNano.analysis.modules.log_blob_detection.LoGBlobDetectionModule[source]

Bases: AnalysisModule

Detect blobs in AFM image stacks using the Laplacian-of-Gaussian (LoG) method.

This module applies multi-scale blob detection to each frame in an AFM image stack using the Laplacian-of-Gaussian algorithm from skimage.feature.blob_log. It supports automatic scale selection and optional estimation of blob radii.

name

The name identifier for this analysis module.

Type:

str

run(stack, previous_results=None, \*, min_sigma=1.0, max_sigma=5.0, num_sigma=10,

threshold=0.1, overlap=0.5, include_radius=True) Detects blobs in each frame of the AFM image stack and returns per-frame features and a summary.

Version()
-------
0.1.0()

Initial implementation.

property name: str

Name of the analysis module.

Returns:

The string identifier for this module: “dbscan_clustering”.

Return type:

str

run(stack, previous_results: dict[str, Any] | None = None, *, min_sigma: float = 1.0, max_sigma: float = 5.0, num_sigma: int = 10, threshold: float = 0.1, overlap: float = 0.5, include_radius: bool = True) dict[str, Any][source]

Detect “blobs” in each frame via a Laplacian-of-Gaussian filter.

Parameters:
  • stack (AFMImageStack) – Must have stack.data of shape (n_frames, H, W).

  • min_sigma (float|int) – Parameters passed to skimage.feature.blob_log.

  • max_sigma (float|int) – Parameters passed to skimage.feature.blob_log.

  • num_sigma (float|int) – Parameters passed to skimage.feature.blob_log.

  • threshold (float) – Absolute intensity threshold for LoG response.

  • overlap (float) – If two detected blobs overlap more than this fraction, only the larger is kept.

  • include_radius (bool) – If True, append the estimated blob radius in each feature-dict.

Returns:

  • { – “features_per_frame”: List[List[dict]], “summary”: {

    ”total_frames”: int, “total_blobs”: int, “avg_blobs_per_frame”: float

    }

  • }

  • Each feature-dict contains at least

    • “frame_timestamp”: float

    • ”y”, “x”: blob center coordinates

    • ”sigma”: scale at which it was detected

    • optional “radius”: sqrt(2) * sigma (if include_radius=True)

version = '0.1.0'

playNano.analysis.modules.particle_tracking module

Module for linking particle features across frames to build trajectories.

This module defines the ParticleTrackingModule, which links features detected in sequential frames of an AFM image stack using nearest-neighbor matching based on feature centroids.

Features are matched across frames if they lie within a specified maximum distance. Tracks are formed by chaining these matches over time.

Each resulting track includes: - A unique track ID - A list of frames where the particle appears - A list of point indices referencing the original features - A list of centroids describing the particle’s positions

Optionally, per-track masks are extracted from the labeled feature masks.

class playNano.analysis.modules.particle_tracking.ParticleTrackingModule[source]

Bases: AnalysisModule

Link detected features frame-to-frame to produce particle trajectories.

This module links features detected by a prior featuredetection module using nearest-neighbor centroid matching across adjacent frames. A new track is created for each unmatched feature.

requires

List of required analysis modules this module depends on.

Type:

list[str]

Version
-------
0.1.0
property name: str

Name of the analysis module.

Returns:

Unique identifier: “particle_tracking”.

Return type:

str

requires = ['feature_detection', 'log_blob_detection']
run(stack: AFMImageStack, previous_results: dict[str, Any] | None = None, detection_module: str = 'feature_detection', coord_key: str = 'features_per_frame', coord_columns: Sequence[str] = ('centroid_x', 'centroid_y'), max_distance: float = 5.0, **params) dict[str, Any][source]

Track particles across frames using nearest-neighbor association.

Parameters:
  • stack (AFMImageStack) – The input AFM image stack.

  • previous_results (dict of str to Any, optional) – Must contain “feature_detection” results including: - coord_key (e.g., “features_per_frame”): list of dicts with per-frame features. - “labeled_masks”: per-frame mask of label regions

  • detection_module (str, default="feature_detection") – Which module to read features from.

  • coord_key (str, default="features_per_frame") – Key in previous_results[detection_module] containing per-frame feature dicts.

  • coord_columns (Sequence[str], default=("centroid_x", "centroid_y")) – Keys to extract coordinates from each feature. Falls back to “centroid” if needed.

  • max_distance (float, default=5.0) – Maximum allowed movement per frame (in coordinate units).

Returns:

Dictionary with keys: - “tracks”: list of dicts per track with:

  • ”id”: track ID

  • ”frames”: list of frame indices

  • ”point_indices”: list of indices into features_per_frame

  • ”centroids”: list of (x, y) positions

  • ”track_masks”: dict of int → 2D boolean arrays (last mask per track)

  • ”n_tracks”: total number of tracks

Return type:

dict

version = '0.1.0'

playNano.analysis.modules.x_means_clustering module

Module for X-Means clustering as part of the playNano analysis pipeline.

This module implements a version of the X-Means clustering algorithm, an extension of K-Means that estimates the optimal number of clusters using the Bayesian Information Criterion (BIC).

Based on: Pelleg, D., & Moore, A. W. (2000). X-means: Extending K-means with Efficient Estimation of the Number of Clusters. Carnegie Mellon University. http://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf

class playNano.analysis.modules.x_means_clustering.XMeansClusteringModule[source]

Bases: AnalysisModule

Cluster features using the X-Means algorithm over (x, y[, t]) coordinates.

This module clusters spatial (and optionally temporal) feature coordinates extracted from an AFM stack using an X-Means algorithm implemented in pure Python.

Parameters:
  • coord_key (str) – Key in previous_results[detection_module] to find feature list.

  • coord_columns (Sequence[str]) – Names of feature dictionary keys to use for coordinates (e.g. centroid_x, centroid_y).

  • use_time (bool) – Whether to append frame timestamps as the third coordinate.

  • min_k (int) – Initial number of clusters (minimum).

  • max_k (int) – Maximum number of clusters to allow.

  • normalise (bool) – Whether to min-max normalize coordinate space before clustering.

  • time_weight (float, optional) – Multiplier for time dimension (after normalization).

Returns:

  • dict – Dictionary with clustering results: - clusters: list of {id, frames, point_indices, coords} - cluster_centers: (K, D) ndarray in original units - summary: {n_clusters: int, members_per_cluster: dict}

  • Version

  • ——-

  • 0.1.0 – Initial implementation.

property name: str

Name of the analysis module.

Returns:

The string identifier for this module.

Return type:

str

requires = ['feature_detection', 'log_blob_detection']
run(stack: AFMImageStack, previous_results: dict[str, Any] | None = None, *, detection_module: str = 'feature_detection', coord_key: str = 'features_per_frame', coord_columns: Sequence[str] = ('centroid_x', 'centroid_y'), use_time: bool = True, min_k: int = 1, max_k: int = 10, normalise: bool = True, time_weight: float | None = None, replicates: int = 3, max_iter: int = 300, bic_threshold: float = 0.0) dict[str, Any][source]

Perform X-Means clustering on features extracted from an AFM stack.

This method extracts (x, y[, t]) coordinates from detected features, optionally normalizes and time-weights them, and applies the X-Means algorithm to automatically select the number of clusters based on the BIC score.

Parameters:
  • stack (AFMImageStack) – The input image stack providing frame timing and metadata context.

  • previous_results (dict of str to Any, optional) – Dictionary containing outputs from previous analysis steps. Must contain the selected detection_module and coord_key.

  • detection_module (str, default="feature_detection") – Key identifying which previous module’s output to use.

  • coord_key (str, default="features_per_frame") – Key under the detection module that holds per-frame feature dicts.

  • coord_columns (Sequence[str], default=("centroid_x", "centroid_y")) – Keys to extract from each feature for clustering coordinates. If missing, will fall back to using the “centroid” tuple if available.

  • use_time (bool, default=True) – If True and coord_columns only gives 2D coordinates, appends the frame timestamp as a third dimension.

  • min_k (int, default=1) – Initial number of clusters to start with.

  • max_k (int, default=10) – Maximum number of clusters allowed.

  • normalise (bool, default=True) – Whether to normalize the feature coordinate axes to the [0, 1] range before clustering.

  • time_weight (float or None, optional) – Multiplicative factor applied to the time axis (after normalization). Used only if time is included as a third coordinate.

  • replicates (int, default=3) – Number of times to run k-means internally to choose the best split.

  • max_iter (int, default=300) – Maximum number of iterations for each k-means call.

  • bic_threshold (float, default=0.0) – Minimum improvement in BIC required to split a cluster.

Returns:

A dictionary with the following keys:

  • ”clusters”list of dicts, each with:
    • id : int

    • frames : list of int

    • point_indices : list of int

    • coords : list of tuple (normalized x, y, [t])

  • ”cluster_centers”ndarray of shape (k, D)

    Final cluster centers in original (denormalized) coordinates.

  • ”summary”dict
    • ”n_clusters” : int

    • ”members_per_cluster” : dict mapping cluster ID to point count.

Return type:

dict

Raises:
  • RuntimeError – If the required detection module output is missing from previous_results.

  • KeyError – If the expected coordinate keys are missing from any feature dictionary.

version = '0.1.0'
playNano.analysis.modules.x_means_clustering.compute_bic(points: ndarray, center: ndarray) float[source]

Compute Bayesian Information Criterion for a cluster.

Parameters:
  • points (np.ndarray) – Points in the cluster.

  • center (np.ndarray) – Cluster center (shape (1, D)).

Returns:

BIC value.

Return type:

float

playNano.analysis.modules.x_means_clustering.core_xmeans(data: ndarray, init_k: int, max_k: int, min_cluster_size: int, distance: str, replicates: int, max_iter: int, bic_threshold: float) tuple[ndarray, ndarray][source]

Core X-Means loop.

Parameters are equivalent to those in run above.

playNano.analysis.modules.x_means_clustering.initialize_centers(points: ndarray, k: int) ndarray[source]

Initialize k centers using a k-means++-like heuristic.

Module contents

Public package initialization for analysis modules.

noindex: