Source code for neuralib.model.rastermap.core

from __future__ import annotations

from pathlib import Path
from typing import TypedDict

import attrs
import numpy as np
from typing_extensions import Self

from neuralib.typing import PathLike
from neuralib.util.verbose import fprint

__all__ = ['UserCluster',
           'RasterOptions',
           'RasterMapResult']


[docs] class UserCluster(TypedDict, total=False): """GUI selected clusters""" ids: np.ndarray """Neuronal ids. `Array[int, N]`""" slice: slice """Binned neurons range""" binsize: int """Neuron bins""" color: np.ndarray """Colors. `Array[float, 4]`"""
[docs] class RasterOptions(TypedDict, total=False): """Run Rastermap model options. Refer to the ``rastermap.rastermap.setting_info()``""" n_clusters: int """Number of clusters created from data before upsampling and creating embedding (any number above 150 will be very slow due to NP-hard sorting problem)""" n_PCs: int """Number of PCs to use during optimization""" time_lag_window: float """Number of time points into the future to compute cross-correlation, useful for sequence finding""" locality: float """How local should the algorithm be -- set to 1.0 for highly local + sequence finding""" n_splits: int """Recluster and sort n_splits times (increases local neighborhood preservation)""" time_bin: int """Binning of data in time before PCA is computed""" grid_upsample: int """How much to upsample clusters""" mean_time: bool """Whether to project out the mean over data samples at each timepoint, usually good to keep on to find structure""" verbose: bool """Whether to output progress during optimization""" verbose_sorting: bool """Output progress in travelling salesman""" start_time: int end_time: int
[docs] @attrs.define class RasterMapResult: """Container for storing the rastermap result, For both GUI load and customized plotting purpose `Dimension parameters`: N = Number of neurons/pixel T = Number of image pulse C = Number of clusters = N / binsize """ filename: str """ Filename of the neural activity data (i.e., *.tif or *.avi for wfield activity; .npy `Array[float, [N, T]]` file for cellular) """ save_path: str """filename for the rastermap result save""" isort: np.ndarray """`Array[int, N]`""" embedding: np.ndarray """`Array[float, [N, 1]]`""" ops: RasterOptions """``RasterOptions``""" user_clusters: list[UserCluster] = attrs.field(default=attrs.Factory(list)) """list of clusters ``UserCluster``""" super_neurons: np.ndarray | None = attrs.field(default=None) """super neuron activity. `Array[float, [C, T]]`"""
[docs] @classmethod def load(cls, path: PathLike) -> Self: """ Load the results from rastermap output :param path: file path of the rastermap output :return: :class:`RasterMapResult` """ dat = np.load(path, allow_pickle=True).item() fprint(f'LOAD ->{path}', vtype='io') return RasterMapResult( filename=dat['filename'], save_path=dat['save_path'], isort=dat['isort'], embedding=dat['embedding'], ops=dat['ops'], user_clusters=dat['user_clusters'], super_neurons=dat['super_neurons'] )
[docs] def save(self, path: Path) -> None: """For GUI loading & cache computing for plotting in different time domains""" proc = { 'filename': self.filename, 'save_path': self.save_path, 'isort': self.isort, 'embedding': self.embedding, 'ops': self.ops, 'user_clusters': self.user_clusters, 'super_neurons': self.super_neurons, } np.save(path, proc, allow_pickle=True) fprint(f'SAVE ->{path}', vtype='io')
@property def n_super(self) -> int: """number of clusters""" return len(self.super_neurons)