Metadata-Version: 2.4
Name: cortyxa
Version: 0.3.0
Summary: Modular desktop explorer and analysis toolkit for mesoscale widefield brain imaging
Author: Daniel Ramandi and contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/ubcbraincircuits/cortyxa
Project-URL: Repository, https://github.com/ubcbraincircuits/cortyxa
Project-URL: Issues, https://github.com/ubcbraincircuits/cortyxa/issues
Project-URL: Changelog, https://github.com/ubcbraincircuits/cortyxa/blob/main/CHANGELOG.md
Keywords: neuroscience,widefield,calcium-imaging,Allen-atlas,GUI
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
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 :: Image Processing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE.md
Requires-Dist: numpy>=1.24
Requires-Dist: scipy>=1.10
Requires-Dist: pandas>=2.0
Requires-Dist: tifffile>=2023.7
Requires-Dist: scikit-image>=0.21
Requires-Dist: matplotlib>=3.7
Requires-Dist: Pillow>=10
Requires-Dist: PySide6>=6.6
Requires-Dist: pyqtgraph>=0.13.4
Requires-Dist: imageio>=2.31
Requires-Dist: imageio-ffmpeg>=0.4.9
Requires-Dist: h5py>=3.9
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-qt>=4.2; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

<p align="center">
  <img src="src/cortyxa/data/cortyxa_logo.png" alt="Cortyxa logo" width="520">
</p>

# Cortyxa

**Cortyxa** is a modular desktop explorer and analysis toolkit for mesoscale/widefield brain imaging. It is designed around a responsive PySide6 GUI and a reusable scientific Python back end, so analyses can be run interactively today and extended without rewriting the application later.

> Status: **0.3 alpha**. The core workflows are implemented and backend-tested. Validate outputs against your laboratory's established pipeline before publication.

## Highlights

- Drag-and-drop or dialog-based TIFF loading; 2-D images and arbitrarily shaped TIFF series are normalized to `time × y × x`.
- **Custom import** for HDF5 (`.h5`, `.hdf5`, `.hdf`) with recursive dataset browsing, automatic dtype detection, editable dimension-role mapping, channel selection, and random-frame preview. HDF5 data stays lazy on disk, and the saved import schema is designed for future formats and multichannel support.
- Visual **Batch analysis / exploration** builder for recursive file discovery, mixed interactive/automated workflows, resumable per-file checkpoints, disk-backed intermediate stacks, and staged exports. Installed batch operations, analysis plugins, and future stack loaders are discovered through registries rather than hard-coded into the builder.
- Optional X, Y, and temporal binning by mean or sum. Temporal binning automatically updates sampling rate.
- Memory-conscious stack ownership: the source TIFF is memory-mapped when possible; the current processed stack is float32-backed by a temporary memory map. Temporal filtering computes in float64 and writes float32.
- On first launch, Cortyxa downloads and validates `assets/allen_mask.csv` from this repository into the user cache. If it is unavailable, the application starts without an atlas rather than substituting a schematic map.
- Live atlas registration in an independently movable, non-modal tool window using X/Y offsets, scale, rotation, and optional olfactory-bulb display.
- Built-in **Custom polygon mask** plugin with click-to-draw editing, draggable/deletable vertices, reset and enable/disable controls, and a shaded preview. Excluded pixels are skipped by ΔF/F, temporal filtering, PCA, seed correlation, and event outputs; Gaussian filtering is cropped and normalized at mask boundaries.
- Static or moving-window ΔF/F, Gaussian spatial filtering, and low/high/band-pass zero-phase Butterworth temporal filtering in any user-selected order.
- Smooth playback with independent raw/processed brightness ranges and colormaps, live histogram updates, adjustable preview FPS, and optional 1-mm scale bar.
- Atlas-anchored bilateral seed selection, fast seed-pixel correlation maps, atlas-space warping/masking, grid or individual PNG export, and reusable JSON ROI files.
- Seed maps, PCA, and event previews open as separate non-modal windows. Multiple results can remain open simultaneously, and each window has independent right-click color-limit and colormap controls.
- PCA quality-control maps, explained variance, cumulative variance, and the number of components required to reach 95% variance. PCA result windows support either a shared comparison scale with a compact right-edge colorbar or independently percentile-scaled component maps without a colorbar.
- Event-triggered averages from 1-based frame-number CSV files, with preview, MP4, float32 TIFF, region/ROI CSV traces, and optional atlas-space export.
- Beta local IBL/ALF loader for common `trials.*.npy`, `wheel.timestamps.npy`, `wheel.position.npy`, and widefield timestamp arrays. It supports alignment to visual stimulus, go cue, first movement, response, feedback, or trial boundaries and filters by stimulus side, contrast, outcome, and choice.
- Headless `WidefieldSession` API and entry-point-based third-party analysis plugins.
- Project files (`.prj`) store loading/binning metadata, atlas transform, the editable custom polygon mask, display settings, ROI points, preview rate, and the ordered processing pipeline. On reload, the user may replay the saved pipeline or only restore defaults.
- Float32 TIFF export at any stage, with optional atlas transformation, plus mask-overlaid PNG snapshots.

## Install

Create a clean environment with Python 3.10–3.13:

```bash
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows PowerShell
# .venv\Scripts\Activate.ps1

python -m pip install --upgrade pip
pip install -e .
cortyxa
```

After publication on PyPI, installation becomes:

```bash
pip install cortyxa
cortyxa
```

Linux systems may require standard Qt/XCB runtime libraries. Headless servers can use the backend modules without launching the GUI.

## Custom HDF5 import

Choose **File → Custom import…** for HDF5 recordings. Cortyxa lists datasets recursively without reading their contents. Select the image dataset, map each source dimension to **Time/Z**, **Y**, **X**, **Channel**, or a fixed index, and verify the mapping using random-frame previews. Common `TYX`, `TCYX`, and `TYXC` layouts are inferred automatically but remain editable.

The HDF5 dtype, chunking, compression, and source shape are detected from metadata. Current processing is single-channel, so one active channel is selected when a channel dimension exists; the persisted profile stores channel selections in a multichannel-ready structure for future releases. X/Y/Z binning remains virtual and the HDF5 dataset is read lazily rather than copied into RAM.

The complete mapping is stored in `.prj` files. In **Batch analysis / exploration**, configure a representative HDF5 file once under the import settings; the same dataset path and axis mapping are then validated against every matched HDF5 input before the workflow starts. See [`docs/custom_import.md`](docs/custom_import.md).

## Large TIFF recordings

Cortyxa opens recordings lazily rather than loading the complete stack into RAM:

- Contiguous, uncompressed TIFF and BigTIFF stacks are read by direct memory mapping.
- Compressed page-based TIFF stacks decode only frames that are displayed or requested.
- Opening-time X/Y/Z binning is virtual; it does not generate a second complete stack before the
  first preview appears.
- Operations that require the entire time series stream the data into a temporary disk-backed
  array with progress reporting.
- Opening another recording removes temporary arrays from the preceding recording.

For the fastest workflow, save acquisition files as standard `TYX`, one-frame-per-page,
uncompressed BigTIFF stacks. Compression reduces storage but necessarily adds per-frame decode
cost during playback and analysis. The status bar reports whether the current stack is using a
`direct memory map`, `lazy page decoding`, or a `temporary memory map`.

If the progress display reaches **99%**, Cortyxa is installing and rendering the first preview on
the GUI thread. Version 0.1.2 and later no longer report 100% until that step has completed.

## Batch analysis and exploration

Choose **File → Batch analysis / exploration…** to build a reusable workflow without loading a
recording first. A workflow can mix:

- **Individual steps**, where Cortyxa restores each file into the main canvas or the appropriate
  plugin/result window and presents a floating **Previous / Next** navigator.
- **Batch steps**, which run automatically file-by-file and checkpoint after every successful file.
- **Save outputs** steps at any position, including a required final save stage.

Inputs can be selected explicitly or discovered recursively from one or more directories using
starts-with, ends-with, and contains rules joined by AND/OR. Every run requires a `.cortyxabatch`
project and cache directory. The run manifest, per-file projects, registration sidecars, processing
checkpoints, and analysis artifacts are written atomically enough to resume from the first
incomplete file after a pause, process termination, or recoverable error.

Large intermediate stacks are float32 memory-mapped `.npy` files in the selected cache directory;
they are never all held in RAM. Cortyxa retains stage-addressable checkpoints while a run remains
recoverable, and can remove them automatically after a completely successful workflow. See
[`docs/batch_workflows.md`](docs/batch_workflows.md) for workflow semantics, disk planning, recovery,
and extension APIs.

## Typical workflow

1. Open/drop a TIFF stack, or choose **Custom import…** for an HDF5 source.
2. Confirm dimensions and choose X/Y/time binning, mean versus sum, original sampling rate, and optional source pixel size. For HDF5, also choose the dataset, dimension roles, and active channel.
3. Use the automatically cached Allen atlas or load a custom atlas CSV, then register it interactively.
4. Optionally open **Plugins → Custom polygon mask…** and draw the image-space area retained for processing.
5. Compute ΔF/F and apply spatial and/or temporal filters in the desired order.
6. Toggle raw/processed data during playback; right-click for brightness, LUT, playback rate, snapshots, or stack export.
7. Run seed correlation, PCA, event-triggered analyses, or IBL alignment.
8. Save a `.prj` file to reproduce registration, custom mask, display, ROIs, and processing across recordings.

## Package layout

```text
src/cortyxa/
├── app.py                 # application entry point
├── models.py              # serializable data models
├── stack.py               # stack ownership, TIFF/HDF5 loading, cache/memory maps, projects
├── importing.py           # custom-import profiles, HDF5 discovery and lazy dataset views
├── atlas.py               # atlas parser, transforms, masks, image↔atlas warping
├── masking.py             # normalized polygon storage and rasterization
├── resources.py           # logo lookup and first-run Allen atlas cache/download
├── processing.py          # ΔF/F and filters
├── export.py              # TIFF, video, PNG, and CSV output
├── analysis/
│   ├── seed.py            # chunked seed-pixel correlation
│   ├── pca.py             # chunked method-of-snapshots PCA
│   ├── events.py          # event-triggered stacks and traces
│   └── ibl.py             # dependency-free local IBL ALF reader
├── gui/
│   ├── main_window.py     # workflow orchestration
│   ├── canvas.py          # fast PyQtGraph image canvas
│   ├── dialogs.py         # focused parameter dialogs
│   ├── custom_import.py   # dataset browser, dimension mapping and HDF5 preview
│   ├── mask_editor.py     # independent editable polygon-mask window
│   ├── results.py         # map/PCA/event result windows
│   └── workers.py         # non-blocking worker execution
└── data/
    └── cortyxa_logo.png   # packaged splash/canvas/application logo

assets/
└── allen_mask.csv         # validated default atlas downloaded on first launch
```

The GUI depends on public functions rather than embedding numerical code in widgets. The `WidefieldSession` class provides a high-level non-GUI API, and installed packages may register analyses under the `cortyxa.analysis_plugins` entry-point group. New analyses should be added to `analysis/`, then exposed with a small dialog and worker callback. See [`docs/development.md`](docs/development.md).


## Headless use

```python
from cortyxa import WidefieldSession

with WidefieldSession() as session:
    session.load_tiff(
        "recording.tif",
        sampling_rate_hz=30,
        pixel_size_mm=0.025,
        bin_x=2,
        bin_y=2,
        bin_z=1,
        method="mean",
    )
    session.compute_dff(baseline="moving", window_ms=10_000)
    session.gaussian_filter(1.2)
    maps, atlas_canvas = session.seed_correlation_atlas([(1.2, 1.8), (-1.2, 1.8)])
```

## Analysis plugins

Cortyxa includes a built-in **Custom polygon mask** plugin. External packages can expose an object implementing `configure`, `run`, and `present` through the entry-point group `cortyxa.analysis_plugins`. The plugin appears automatically in the GUI's **Plugins** menu. See [`examples/plugin_example.py`](examples/plugin_example.py) and [`docs/development.md`](docs/development.md).

## Atlas data and coordinates

Cortyxa stores selected ROI locations in **atlas millimetres**, with positive X on the right hemisphere and positive Y anterior. Registration maps atlas millimetres to image pixels using a similarity transform. Right-hemisphere points are mirrored automatically for bilateral analyses.

Cortyxa does **not** bundle or fall back to a schematic brain map. On first launch it requests the repository file at `assets/allen_mask.csv`, validates its polygon schema, and stores a local copy in the user cache. If the network or file is unavailable, no atlas is displayed. Users can always load a validated laboratory projection using either Cortyxa's long vertex-table schema or the supported Allen/NeuraLib-style bilateral region-row schema documented in [`docs/atlas_csv.md`](docs/atlas_csv.md). Olfactory polygons are tagged so they can be included or excluded consistently.

The authoritative repository location is:

```text
assets/allen_mask.csv
```

Do not move or rename that file without also updating `DEFAULT_ATLAS_URL` in `src/cortyxa/resources.py`.

## IBL/ALF beta support

Select a session or ALF folder. Cortyxa recursively searches for local arrays with names such as:

```text
_ibl_trials.stimOn_times.npy
_ibl_trials.goCue_times.npy
_ibl_trials.firstMovement_times.npy
_ibl_trials.response_times.npy
_ibl_trials.feedback_times.npy
_ibl_trials.feedbackType.npy
_ibl_trials.choice.npy
_ibl_trials.contrastLeft.npy
_ibl_trials.contrastRight.npy
_ibl_trials.intervals.npy
_ibl_wheel.timestamps.npy
_ibl_wheel.position.npy
```

If a one-dimensional widefield time/timestamp array is found, events are mapped to the nearest imaging frame. Otherwise, Cortyxa uses the imaging sampling rate and a user-entered time-zero offset. Event CSVs and returned IBL frames are treated as **1-based** to match the GUI convention.

See [`docs/ibl.md`](docs/ibl.md) for assumptions and validation advice.

## Tests

```bash
pip install -e .[dev]
pytest -q
```

The GitHub Actions workflow tests Python 3.10, 3.12, and 3.13 on Linux, Windows, and macOS. GUI smoke tests require a Qt-capable environment; numerical tests are display-independent.

## Build and publish

```bash
python -m build
python -m twine check dist/*
```

The included release workflow uses PyPI Trusted Publishing. The repository is configured for
[`ubcbraincircuits/cortyxa`](https://github.com/ubcbraincircuits/cortyxa). Follow
[`docs/releasing.md`](docs/releasing.md) to configure the `pypi` GitHub Environment and the PyPI
pending publisher. Publishing a GitHub Release whose tag matches the package version builds, checks,
and uploads the wheel and source distribution to PyPI.

## Scientific and implementation notes

- Processing is cumulative and order-dependent. Only the immutable raw source and the latest processed result are presented in the GUI; project files preserve the ordered operation list.
- Spatial Gaussian preview affects only the current displayed frame until Apply is selected.
- Display ranges and LUTs are metadata, not destructive image operations.
- Correlation and PCA calculations are chunked over pixels to avoid unnecessary full-stack copies.
- A custom polygon is stored as normalized image coordinates in the project file. Changing it resets the current processed stack so a saved processing pipeline cannot silently mix old and new masks.
- Atlas-space exports use interpolation and set pixels outside the outer atlas boundary to NaN.
- MP4 output requires the bundled or system-accessible FFmpeg used by `imageio-ffmpeg`. Cortyxa pads odd image dimensions by one edge row/column so H.264/yuv420p export does not rescale the data.

## License and attribution

Code is released under the MIT License. See [`NOTICE.md`](NOTICE.md) for Allen CCF and IBL attribution.
