playNano package

Subpackages

Submodules

playNano.afm_stack module

Defines AFMImageStack for managing AFM time-series data and processing steps.

class playNano.afm_stack.AFMImageStack(data: ndarray, pixel_size_nm: float, channel: str, file_path: Path, frame_metadata: list[dict[str, Any]] = None)[source]

Bases: object

Manage stacks of AFM images with metadata, analysis results, and provenance.

Contains snapshots of each stage of processing (including the raw data after the first processing step), any masks generated, analysis results and the provenance of each of processing and analysis step.

data

3D array of shape (n_frames, height, width) holding the raw or current data.

Type:

np.ndarray

pixel_size_nm

Physical pixel size in nanometers.

Type:

float

channel

Channel name.

Type:

str

file_path

Path to the source file or folder.

Type:

Path

frame_metadata

Per-frame metadata dicts; each will include a normalized ‘timestamp’ key.

Type:

list[dict[str, Any]]

processed

Snapshots of processed data arrays from filters. Keys like ‘step_1_remove_plane’.

Type:

dict[str, np.ndarray]

masks

Boolean mask arrays from mask steps. Keys like ‘step_2_threshold’.

Type:

dict[str, np.ndarray]

analysis

Results of analysis modules, keyed by ‘step_<i>_<module_name>’.

Type:

dict[str, Any]

provenance

Records environment info and provenance of processing and analysis pipelines:

{
    "environment": {...},
    "processing": {"steps": [...], "keys_by_name": {...}},
    "analysis": {"frame_times": [...], "steps": [...],
    "results_by_name": {...}},
}
Type:

dict[str, Any]

apply(steps: list[str], **kwargs) ndarray[source]

Apply a sequence of processing steps to each frame in the AFM image stack.

Steps can be:

  • “clear” : reset any existing mask

  • mask names : keys in MASK_MAP

  • filter names : keys in FILTER_MAP

  • plugin names : entry points in ‘playNano.filters’

  • method names : bound methods on this class

**kwargs are forwarded to mask functions or filter functions as appropriate.

This is a stateless convenience: applies clear/mask/filter steps in order, snapshots only ‘raw’ and final data in self.processed, but does not assign unique keys per step or update provenance.

Parameters:
  • steps (list of str) – Sequence of step names (e.g. [“remove_plane”, “threshold_mask”, “gaussian_filter”]).

  • **kwargs – Forwarded to each mask/filter function.

Returns:

Final processed 3D array (shape (n_frames, height, width)).

Return type:

np.ndarray

Notes

For tracked, reproducible processing, use ProcessingPipeline.

channel_for_frame(idx: int) str[source]

Get the channel name for a given frame index.

Returns the value of the ‘channel’ key in the frame’s metadata if present, otherwise falls back to the global stack-level channel.

Parameters:

idx (int) – Frame index.

Returns:

Channel name for the frame.

Return type:

str

export_analysis_log(path: str) None[source]

Export analysis provenance and results to a JSON file.

Expects that stack.analysis (or stack.analysis_results) and stack.provenance[“analysis”] are populated by AnalysisPipeline.run().

Writes

Example JSON structure:

{
"environment": { ... },
"analysis": { <step_key>: outputs, ... },
"provenance": {
    "steps": [ ... ],
    "results_by_name": { ... },
    "frame_times": [...],
}
}
param path:

File path to write the JSON log. Creates parent dirs as needed.

type path:

str

raises ValueError:

If no analysis results found on this stack.

export_processing_log(path: str) None[source]

Export processing provenance and environment metadata to a JSON file.

Writes

Example JSON structure:

{
"environment": { ... },
"processing": {
    "steps": [ ... ],
    "keys_by_name": { ... }
}
}
param path:

File path to write the JSON log. Creates parent dirs as needed.

type path:

str

frames_with_metadata()[source]

Yield tuples of (index, frame_array, metadata) for all frames.

Yields:

tuple[int, np.ndarray, dict[str, Any]] – Frame index, 2D image array, and metadata dict.

Notes

If any frame array is None, it is skipped with a warning log.

get_frame(index: int) ndarray[source]

Retrieve the 2D image array for a specific frame index.

Parameters:

index (int) – Frame index to retrieve.

Returns:

2D array of shape (height, width) for the frame.

Return type:

np.ndarray

Raises:

IndexError – If index is out of bounds.

get_frame_metadata(index: int) dict[str, Any][source]

Retrieve metadata dict for a specific frame index.

Parameters:

index (int) – Frame index.

Returns:

Metadata dict for that frame (includes normalized ‘timestamp’).

Return type:

dict[str, Any]

Raises:

IndexError – If index is out of range.

get_frame_times() list[float][source]

Return a list of timestamps (in seconds) for each frame in the stack.

This method uses time_for_frame() to retrieve the timestamp for each frame, which allows central control over fallback behavior.

Returns:

List of timestamps per frame. If unavailable, the frame index is used as a fallback.

Return type:

list of floats

Examples

>>> stack.frame_metadata = [{"timestamp": 0.0}, {"timestamp": 1.0}]
>>> stack.get_frame_times()
[0.0, 1.0]
>>> stack.frame_metadata = [{"timestamp": 0.0}, {}]
>>> stack.get_frame_times()
[0.0, 1.0]
get_frames() list[ndarray][source]

Return a list of all individual 2D frame arrays.

Returns:

List of length n_frames, each a 2D array.

Return type:

list of np.ndarray

property height: int

Get the frame number of pixel rows.

Returns:

Number of rows per frame.

Return type:

int

property image_shape: tuple[int, int]

Spatial dimensions of a single frame.

Return type:

tuple of (height, width)

classmethod load_data(path: str | Path, channel: str = 'height_trace') AFMImageStack[source]

Load AFM data from a file or folder into AFMImageStack, normalizing timestamps.

Parameters:
  • path (str or Path) – Path to AFM data file or folder.

  • channel (str, optional) – Channel name to load; default “height_trace”.

Returns:

Fully reconstructed AFMImageStack with processed snapshots and provenance.

Return type:

AFMImageStack

property n_frames: int

Number of frames in the stack.

Returns:

Number of frames (size along axis 0).

Return type:

int

restore_raw() ndarray[source]

Restore self.data from the ‘raw’ snapshot in self.processed.

Returns:

The restored raw data.

Return type:

np.ndarray

Raises:

KeyError – If ‘raw’ data is not available in self.processed.

time_for_frame(idx: int) float[source]

Get timestamp for a given frame index, fallback to index if missing.

Parameters:

idx (int) – Frame index.

Returns:

Timestamp in seconds; if metadata lacks ‘timestamp’, returns float(idx).

Return type:

float

Raises:

IndexError – If idx is out of range.

Notes

This fallback (index-as-time) assumes uniform frame intervals and is useful for stacks without explicit time metadata.

Examples

>>> stack.frame_metadata = [{"timestamp": 0.0}, {}, {"timestamp": 2.0}]
>>> stack.time_for_frame(1)
1.0
>>> stack.time_for_frame(2)
2.0
property width: int

Get the frame number of pixel columns.

Returns:

Number of columns per frame.

Return type:

int

playNano.errors module

Error classes for playNano.

exception playNano.errors.LoadError[source]

Bases: Exception

Raised when loading AFM data fails.

Module contents

Public package initialization.