Metadata-Version: 2.4
Name: pygraft-gui
Version: 0.2.0
Summary: Python port of GraFT (Graph-Filtered Temporal) dictionary learning for spatio-temporal signal extraction, with a PySide6 GUI
Author: Adam Charles
License: MIT
Project-URL: Homepage, https://github.com/adamshch/pyGraFT
Project-URL: Repository, https://github.com/adamshch/pyGraFT
Project-URL: Issues, https://github.com/adamshch/pyGraFT/issues
Keywords: calcium-imaging,dictionary-learning,sparse-coding,neuroscience,signal-processing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Image Processing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.25
Requires-Dist: scipy>=1.10
Requires-Dist: scikit-learn>=1.2
Requires-Dist: PyWavelets>=1.4
Requires-Dist: scikit-image>=0.21
Requires-Dist: PySide6>=6.5
Requires-Dist: pyqtgraph>=0.13
Requires-Dist: tifffile>=2023.7
Requires-Dist: h5py>=3.9
Requires-Dist: roiapp>=0.1.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Provides-Extra: gui
Dynamic: license-file

# pyGraFT

Python port of [GraFT](https://pubmed.ncbi.nlm.nih.gov/35533160/) (Graph-Filtered
Temporal dictionary learning), originally implemented in MATLAB at
[GraFT-analysis](https://github.com/adamshch/GraFT-analysis).

GraFT decomposes a pixel &times; time movie into a shared temporal dictionary
and per-pixel sparse spatial maps, using a re-weighted L1 sparse coding step
where the re-weighting is driven by a spatial/graph kernel that couples
nearby or similar pixels. It's built for calcium-imaging data, but the
algorithm itself is domain-agnostic.

## Status

- Core algorithm (`graft.graft`), Gaussian noise model, both the fixed-
  convolution and graph-embedding spatial kernels.
- Patch-based processing + component merging (`graft.patch_graft`) for
  movies too large to fit comfortably in memory, including optional
  memory-mapped input (only the patch currently being processed is read
  from disk).
- Preprocessing: denoising (wavelet shrinkage), centering/normalization,
  triangle-threshold masking (`graft.preprocessing`).
- Motion correction: rigid and patch-based (piecewise-rigid) registration,
  built on scikit-image's subpixel phase correlation
  (`graft.motion_correction`).
- A PySide6 GUI (`graftapp`, install the `gui` extra) covering the full
  workflow: load a movie &rarr; preprocess (motion-correct/denoise/
  normalize/crop/mask) &rarr; set parameters &rarr; run &rarr; browse/
  visualize/play results &rarr; save.
- An optional compiled C++ extension (`graft._native`) accelerates the
  per-pixel sparse-inference solve, the dominant cost of a GraFT run;
  `graft` transparently falls back to an equivalent pure-Python solver if
  no C++17 compiler is available at install time.

Not yet ported: the Poisson noise model (`likely_form='poisson'` raises
`NotImplementedError`) and post-hoc coefficient refinement
(`reCalcCoefSparse/WithLS.m`).

## Install

```bash
pip install pygraft-gui          # library only
pip install "pygraft-gui[gui]"   # library + the graftapp GUI
```

From source:

```bash
pip install -e ".[test,gui]"
```

## Usage

### Library

```python
from graft import graft, patch_graft
from graft.simulate import sim_spatial_data

data, profiles, temporal = sim_spatial_data(dims=(30, 30, 100), n_dict=4)

# Single field-of-view
D, S, extras = graft(data, dict_init=None, corr_kern=None,
                      params={"n_dict": 4, "lambda": 0.6})

# Patch-based (splits into overlapping patches, then merges results).
# `data` can be a memory-mapped array (e.g. numpy.load(path, mmap_mode="r"))
# -- only each patch's own slice is read from disk.
D, S, extras = patch_graft(data, n_dict=4, patches=None, corr_kern=None,
                            params={"patchSize": (20, 20)})
```

### GUI

```bash
graftapp
# or: python -m graftapp
```

## Development

```bash
pip install -e ".[test,gui]"
pytest
python -m pyflakes src/ tests/
```
