Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
cff-version: 1.2.0
message: "If you use nSTAT, please cite the toolbox paper below."
title: "nSTAT-python: Neural Spike Train Analysis Toolbox for Python"
type: software
license: GPL-2.0-only
repository-code: "https://github.com/cajigaslab/nSTAT-python"
authors:
- family-names: Cajigas
given-names: Iahn
email: icajigas@upenn.edu
- family-names: Malik
given-names: Wasim Q.
- family-names: Brown
given-names: Emery N.
preferred-citation:
type: article
title: "nSTAT: Open-source neural spike train analysis toolbox for Matlab"
authors:
- family-names: Cajigas
given-names: I.
- family-names: Malik
given-names: W. Q.
- family-names: Brown
given-names: E. N.
journal: "Journal of Neuroscience Methods"
year: 2012
volume: 211
issue: 2
start: 245
end: 264
doi: "10.1016/j.jneumeth.2012.08.009"
234 changes: 33 additions & 201 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# nSTAT-python

**Neural Spike Train Analysis Toolbox for Python**

[![test-and-build](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml/badge.svg)](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml)

`nSTAT-python` is a Python port of the [nSTAT](https://github.com/cajigaslab/nSTAT)
open-source neural spike train analysis toolbox. It implements a range of models and
algorithms for neural spike train data analysis, with a focus on point-process
Expand All @@ -11,10 +15,7 @@ continuous neural signals such as LFP, EEG, and ECoG.
One of nSTAT's key strengths is point-process generalized linear models for spike
train signals that provide a formal statistical framework for processing signals
recorded from ensembles of single neurons. It also has extensive support for model
fitting, model-order analysis, and adaptive decoding — including state-space GLM
(SSGLM) estimation via EM, unscented Kalman filtering (UKF), goal-directed
point-process adaptive filters (PPAF), and hybrid discrete/continuous
point-process filters (PPHF).
fitting, model-order analysis, and adaptive decoding.

Although created with neural signal processing in mind, nSTAT can be used as a
generic tool for analyzing any types of discrete and continuous signals, and thus
Expand All @@ -25,13 +26,13 @@ suggestions and contributions. This platform is intended as a repository for
extensions to the toolbox based on your code contributions as well as for flagging
and tracking open issues.

[![test-and-build](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml/badge.svg)](https://github.com/cajigaslab/nSTAT-python/actions/workflows/ci.yml)
The current release can be installed from PyPI: `pip install nstat-toolbox`

Lab websites:
- Neuroscience Statistics Research Laboratory: https://www.neurostat.mit.edu
- RESToRe Lab: https://www.med.upenn.edu/cajigaslab/

## Installation
## How to install nSTAT

```bash
python -m pip install nstat-toolbox
Expand All @@ -45,11 +46,7 @@ cd nSTAT-python
python -m pip install -e .[dev]
```

## Example data

`nSTAT-python` does not commit raw example data to the repository.

Install the example dataset with:
Install the example dataset:

```bash
nstat-install --download-example-data always
Expand All @@ -59,57 +56,19 @@ Equivalent Python API:

```python
from nstat.data_manager import ensure_example_data

data_dir = ensure_example_data(download=True)
print(data_dir)
```

## How to install nSTAT (post-install setup)

Run the setup helper:

```bash
nstat-install
```

Module form:

```bash
python -m nstat.install --download-example-data never --no-rebuild-doc-search
```

Equivalent Python API:

```python
from nstat.install import nstat_install

report = nstat_install()
```

`clean_user_path_prefs` is accepted for MATLAB-API compatibility, but it is a
Python no-op because import paths are managed by the environment rather than a
MATLAB-style saved user path.

## Quickstart

```bash
git clone https://github.com/cajigaslab/nSTAT-python
cd nSTAT-python
python -m pip install -e .[dev]
python -m nstat.install --download-example-data prompt
pytest -q
```

For a gallery refresh that mirrors the MATLAB repo's paper-example workflow:
Quickstart:

```bash
python tools/paper_examples/build_gallery.py
python tools/parity/build_report.py
cd /path/to/nSTAT-python
pip install -e .[dev]
nstat-install --download-example-data always
pytest -q && python tools/paper_examples/build_gallery.py
```

## Examples

### Paper Examples (Self-Contained)
## Paper Examples (Self-Contained)

Canonical source files:
- `examples/paper/*.py`
Expand All @@ -136,32 +95,7 @@ refreshes the canonical README paper-example table from
Expanded paper-example index and figure gallery:
- [docs/paper_examples.md](docs/paper_examples.md)

### Supplementary Examples

These smaller demos remain useful as quick install and plotting checks.

| Example | Run command | Output |
|---|---|---|
| Multitaper spectrum + spectrogram | `python examples/readme_examples/example1_multitaper_and_spectrogram.py` | [PNG](examples/readme_examples/images/readme_example1_multitaper_and_spectrogram.png) |
| Simulated CIF spike train | `python examples/readme_examples/example2_simulate_cif_spiketrain_10s.py` | [PNG](examples/readme_examples/images/readme_example2_simulate_cif_spiketrain_10s.png) |
| Spike-train raster | `python examples/readme_examples/example3_nstcoll_raster_from_example2.py` | [PNG](examples/readme_examples/images/readme_example3_nstcoll_raster.png) |
## Documentation

- Docs home: [cajigaslab.github.io/nSTAT-python](https://cajigaslab.github.io/nSTAT-python/)
- Help home: [cajigaslab.github.io/nSTAT-python/help](https://cajigaslab.github.io/nSTAT-python/help/index.html)
- Paper overview: [cajigaslab.github.io/nSTAT-python/help/paper_overview.html](https://cajigaslab.github.io/nSTAT-python/help/paper_overview.html)
- Example index: [cajigaslab.github.io/nSTAT-python/help/examples_index.html](https://cajigaslab.github.io/nSTAT-python/help/examples_index.html)
- Class definitions: [cajigaslab.github.io/nSTAT-python/help/class_definitions.html](https://cajigaslab.github.io/nSTAT-python/help/class_definitions.html)
- Documentation setup: [cajigaslab.github.io/nSTAT-python/help/examples/DocumentationSetup2025b.html](https://cajigaslab.github.io/nSTAT-python/help/examples/DocumentationSetup2025b.html)

Source pages:
- [docs/NeuralSpikeAnalysis_top.md](docs/NeuralSpikeAnalysis_top.md)
- [docs/PaperOverview.md](docs/PaperOverview.md)
- [docs/Examples.md](docs/Examples.md)
- [docs/ClassDefinitions.md](docs/ClassDefinitions.md)
- [docs/DocumentationSetup.md](docs/DocumentationSetup.md)

## Plot Style
Plot style policy:

```python
from nstat.plot_style import set_plot_style
Expand All @@ -173,6 +107,16 @@ set_plot_style('modern')
set_plot_style('legacy')
```

Rendered help documentation (GitHub Pages):
- https://cajigaslab.github.io/nSTAT-python/

For mathematical and programmatic details of the toolbox, see:

Cajigas I, Malik WQ, Brown EN. nSTAT: Open-source neural spike train analysis
toolbox for Matlab. Journal of Neuroscience Methods 211: 245–264, Nov. 2012.
https://doi.org/10.1016/j.jneumeth.2012.08.009
PMID: 22981419

## Paper-Aligned Toolbox Map

To keep terminology and workflows consistent with the 2012 toolbox paper,
Expand All @@ -185,32 +129,17 @@ This page ties the Python toolbox to the paper's workflow categories:
`Analysis`, `FitResult`, `DecodingAlgorithms`)
- Fitting and assessment workflow (GLM fitting, diagnostics, summaries)
- Simulation workflow (conditional intensity and thinning examples)
- State-space GLM (SSGLM) workflow — full EM algorithm (`PPSS_EMFB`)
for across-trial coefficient dynamics with forward-backward Kalman
smoothing (Section 2.4)
- Decoding workflow — point-process adaptive filter (`PPDecodeFilterLinear`),
hybrid filter (`PPHybridFilterLinear`), unscented Kalman filter (`ukf`),
and stimulus confidence intervals (Sections 2.5–2.6)
- Signal processing — multi-taper spectral estimation (`MTMspectrum`),
spectrogram, cross-covariance, and peak-finding methods
- Decoding workflow (univariate/bivariate and history-aware decoding)
- Example-to-paper section mapping via `nSTATPaperExamples`

If you use nSTAT in your work, please remember to cite the above paper in any
publications.

## Developer notes

- Run tests:

```bash
pytest -q
```

- Build docs:
If you use nSTAT in your work, please remember to cite the above paper in any publications.
nSTAT is protected by the GPL v2 Open Source License.

```bash
sphinx-build -b html docs docs/_build
```
The code repository for the Python port of nSTAT is hosted on GitHub at
https://github.com/cajigaslab/nSTAT-python.
The paper-example dataset is distributed separately from the Git repository:
- Figshare dataset DOI: https://doi.org/10.6084/m9.figshare.4834640.v3
- Paper DOI: https://doi.org/10.1016/j.jneumeth.2012.08.009

## Code audit (2026-03-11)

Expand Down Expand Up @@ -242,103 +171,6 @@ parity verified.

See [parity/report.md](parity/report.md) for the full audit.

## License

nSTAT is protected by the GPL v2 Open Source License.

## Cite

If you use nSTAT in your work, please cite:

Cajigas I, Malik WQ, Brown EN. nSTAT: Open-source neural spike train analysis
toolbox for Matlab. Journal of Neuroscience Methods 211: 245–264, Nov. 2012.
https://doi.org/10.1016/j.jneumeth.2012.08.009
PMID: 22981419

## Data and Related Repositories

- **Paper-example dataset (Figshare)**: https://doi.org/10.6084/m9.figshare.4834640.v3
- **Paper DOI**: https://doi.org/10.1016/j.jneumeth.2012.08.009

The code repository for the Python port of nSTAT is hosted on GitHub at
https://github.com/cajigaslab/nSTAT-python.

## MATLAB / Simulink Dependency for CIF Simulation

The `CIF` class can simulate spike trains from a fitted conditional intensity
function. The original MATLAB implementation drives this simulation through
**Simulink models** (`PointProcessSimulation.slx`,
`PointProcessSimulationThinning.mdl`, and `SimulatedNetwork2.mdl`). These
models solve the point-process thinning algorithm as a continuous-time
block diagram and produce exact spike-train realisations.

The Python port includes a **native discrete-time Bernoulli fallback** that
runs without MATLAB, but the results are approximate. For exact parity with
the MATLAB toolbox you need a working MATLAB + Simulink installation and the
MATLAB Engine API for Python.

### The `backend` flag

`CIF.simulateCIF()` accepts a `backend` parameter that controls which
simulation engine is used:

| Flag | Behaviour |
|---|---|
| `backend='auto'` (default) | Uses MATLAB/Simulink when available; silently falls back to the native Python implementation with a `MatlabFallbackWarning` when it is not. |
| `backend='matlab'` | Forces the Simulink backend. Raises `RuntimeError` if MATLAB Engine or the MATLAB nSTAT repo cannot be found. |
| `backend='python'` | Forces the native Python implementation. No MATLAB is required and no warning is issued. |

### Setting up the MATLAB backend

1. **Install MATLAB** (R2020a or later recommended) with the **Simulink**
add-on.
2. **Install the MATLAB Engine API for Python**
([MathWorks instructions](https://www.mathworks.com/help/matlab/matlab_external/install-the-matlab-engine-for-python.html)):
```bash
cd "$(matlab -batch "disp(matlabroot)" | tail -1)/extern/engines/python"
python -m pip install .
```
3. **Point to the MATLAB nSTAT repo** so the engine can find the `.slx` / `.mdl`
models. Use either:
- The `NSTAT_MATLAB_PATH` environment variable:
```bash
export NSTAT_MATLAB_PATH=/path/to/nSTAT
```
- Place the MATLAB repo as a sibling directory named `nSTAT/` next to this
Python repo (auto-detected).
- Or call `set_matlab_nstat_path()` at runtime:
```python
from nstat.matlab_engine import set_matlab_nstat_path
set_matlab_nstat_path("/path/to/nSTAT")
```

### Why this matters

The native Python simulation uses a discrete-time Bernoulli draw at each time
step: at every bin the probability of a spike is `p = lambda * delta`, and a
uniform random draw decides whether a spike is emitted. The Simulink model,
by contrast, solves the point-process thinning integral in continuous time,
producing more accurate inter-spike-interval statistics — particularly at high
firing rates or with fast-varying stimuli.

If your analysis depends on precise spike-timing statistics (e.g. KS
goodness-of-fit tests on simulated data, or decoding benchmarks), use the
MATLAB backend.

### Call for contributions

Replacing the Simulink dependency with a pure-Python continuous-time thinning
solver is an open goal for the project. A faithful implementation would need
to:

- Implement Ogata's modified thinning algorithm (Lewis & Shedler 1979) for
the conditional intensity with history dependence.
- Match the Simulink model's interpolation and adaptive step-size behaviour.
- Pass parity tests against the MATLAB output for the existing paper examples.

If you are interested in contributing this, please open an issue or pull
request — contributions are very welcome.

## MATLAB Toolbox

The original MATLAB nSTAT toolbox lives in a separate repository:
Expand Down
Binary file modified docs/figures/example01/fig01_constant_mg_summary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example01/fig02_washout_raster_overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example02/fig01_data_overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example02/fig02_lag_and_model_comparison.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig01_simulated_and_real_rasters.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig02_psth_comparison.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig03_ssglm_simulation_summary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig04_ssglm_fit_diagnostics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig05_stimulus_effect_surfaces.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example03/fig06_learning_trial_comparison.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig01_example_cells_path_overlay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig02_model_summary_statistics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig03_gaussian_place_fields_animal1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig04_zernike_place_fields_animal1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig05_gaussian_place_fields_animal2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig06_zernike_place_fields_animal2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example04/fig07_example_cell_mesh_comparison.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig01_univariate_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig02_univariate_decoding.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig03_reach_and_population_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig04_ppaf_goal_vs_free.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig05_hybrid_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/figures/example05/fig06_hybrid_decoding_summary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading