spikestats 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spikestats-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- spikestats-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +18 -0
- spikestats-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- spikestats-0.2.0/.github/workflows/ci.yml +22 -0
- spikestats-0.2.0/.gitignore +15 -0
- spikestats-0.2.0/CHANGELOG.md +55 -0
- spikestats-0.2.0/CLAUDE.md +49 -0
- spikestats-0.2.0/CODE_OF_CONDUCT.md +37 -0
- spikestats-0.2.0/CONTRIBUTING.md +33 -0
- spikestats-0.2.0/LICENSE +21 -0
- spikestats-0.2.0/PKG-INFO +174 -0
- spikestats-0.2.0/README.md +123 -0
- spikestats-0.2.0/SECURITY.md +18 -0
- spikestats-0.2.0/assets/logo.png +0 -0
- spikestats-0.2.0/docs/architecture.md +72 -0
- spikestats-0.2.0/docs/charter.md +35 -0
- spikestats-0.2.0/docs/logo-prompt.md +7 -0
- spikestats-0.2.0/examples/summary.py +51 -0
- spikestats-0.2.0/pyproject.toml +61 -0
- spikestats-0.2.0/src/spikestats/__init__.py +34 -0
- spikestats-0.2.0/src/spikestats/_validate.py +31 -0
- spikestats-0.2.0/src/spikestats/metrics.py +140 -0
- spikestats-0.2.0/src/spikestats/py.typed +0 -0
- spikestats-0.2.0/src/spikestats/time_resolved.py +208 -0
- spikestats-0.2.0/tests/test_metrics.py +147 -0
- spikestats-0.2.0/tests/test_properties.py +62 -0
- spikestats-0.2.0/tests/test_time_resolved.py +374 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: A wrong or surprising statistic
|
|
4
|
+
title: ""
|
|
5
|
+
labels: bug
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Call
|
|
9
|
+
|
|
10
|
+
The metric and parameters, including the spike times, for example
|
|
11
|
+
`cv_isi([0.0, 0.1, 0.3, 0.6])` or `fano_factor(spikes, duration=2, bin_width=0.1)`.
|
|
12
|
+
|
|
13
|
+
## Expected
|
|
14
|
+
|
|
15
|
+
The value you expected, and the definition or source it follows.
|
|
16
|
+
|
|
17
|
+
## Actual
|
|
18
|
+
|
|
19
|
+
What you observed.
|
|
20
|
+
|
|
21
|
+
## Environment
|
|
22
|
+
|
|
23
|
+
- spikestats version:
|
|
24
|
+
- Python version:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a metric or capability for spikestats
|
|
4
|
+
title: ""
|
|
5
|
+
labels: enhancement
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What
|
|
9
|
+
|
|
10
|
+
The metric or capability you would like.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
The workflow this would support.
|
|
15
|
+
|
|
16
|
+
## References
|
|
17
|
+
|
|
18
|
+
The definition or paper that pins down the expected behavior.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
What this changes and why.
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] Tests added or updated (a bug fix starts with a failing test)
|
|
8
|
+
- [ ] Exact-value test and any known limit (regular train, Poisson) covered for a new metric
|
|
9
|
+
- [ ] `uv run ruff check .` passes
|
|
10
|
+
- [ ] `uv run mypy src` passes
|
|
11
|
+
- [ ] `uv run pytest` passes
|
|
12
|
+
- [ ] No runtime dependencies added
|
|
13
|
+
- [ ] No em dash characters in docs or commit messages
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: ruff check .
|
|
21
|
+
- run: mypy src
|
|
22
|
+
- run: pytest -q
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.2.0]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `binned_spike_counts(spikes, *, duration, bin_width) -> list[int]`: spike counts in
|
|
12
|
+
`int(duration / bin_width)` consecutive non-overlapping bins tiling `[0, duration)`.
|
|
13
|
+
- `time_resolved_rate(spikes, *, duration, bin_width, step) -> tuple[list[float], list[float]]`:
|
|
14
|
+
sliding-window firing rate. Returns `(window_center_times, rates_in_hz)`. Window positions use
|
|
15
|
+
integer indexing of `step` to avoid floating-point drift. The last window included is the
|
|
16
|
+
largest k where `k * step + bin_width <= duration`.
|
|
17
|
+
- `psth(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`: peristimulus time
|
|
18
|
+
histogram over multiple trials. Returns `(bin_center_times, mean_rate_per_bin_hz)` averaged
|
|
19
|
+
over all trials. Raises `ValueError` on empty `trials`.
|
|
20
|
+
- `time_resolved_fano(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`:
|
|
21
|
+
per-bin Fano factor (population variance / mean of per-trial counts) across trials. Returns
|
|
22
|
+
`(bin_center_times, fano_per_bin)`. Bins where the mean count across all trials is 0 are
|
|
23
|
+
returned as `float('nan')`.
|
|
24
|
+
|
|
25
|
+
### Design notes
|
|
26
|
+
|
|
27
|
+
- Boundary policy: all time-resolved functions use `[0, duration)` -- a spike at exactly
|
|
28
|
+
`duration` is excluded, matching the existing `spike_counts` convention.
|
|
29
|
+
- Variance choice: `time_resolved_fano` uses population variance (denominator N), matching
|
|
30
|
+
`fano_factor` in metrics.py. With one trial, pvariance of a single sample is 0, so all
|
|
31
|
+
non-empty bins return 0. Callers who need sample variance should use multiple trials.
|
|
32
|
+
- Zero-mean bins in `time_resolved_fano`: returned as `float('nan')` so callers can identify
|
|
33
|
+
and exclude them.
|
|
34
|
+
|
|
35
|
+
### Not included in this release
|
|
36
|
+
|
|
37
|
+
- PyPI publish is queued behind the new-project-creation quota (currently returning 429 for new
|
|
38
|
+
packages). The sdist and wheel are twine-verified in `dist/`; upload will proceed once the
|
|
39
|
+
quota resets.
|
|
40
|
+
|
|
41
|
+
## [0.1.0]
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
- `firing_rate(spikes, *, duration)`: mean firing rate.
|
|
45
|
+
- `inter_spike_intervals(spikes)`: consecutive interval list.
|
|
46
|
+
- `cv_isi(spikes)`: coefficient of variation of the inter-spike intervals.
|
|
47
|
+
- `cv2(spikes)`: local CV2 averaged over adjacent interval pairs (Holt et al. 1996).
|
|
48
|
+
- `lv(spikes)`: local variation (Shinomoto et al. 2003).
|
|
49
|
+
- `lvr(spikes, *, refractory)`: revised local variation LvR (Shinomoto et al. 2009).
|
|
50
|
+
- `spike_counts(spikes, *, duration, bin_width)`: counts per equal-width bin.
|
|
51
|
+
- `fano_factor(spikes, *, duration, bin_width)`: Fano factor of binned counts.
|
|
52
|
+
- Pure Python, zero runtime dependencies. Inputs are plain lists of spike times, matching
|
|
53
|
+
spikegen and spikedist.
|
|
54
|
+
- Test suite: exact-value tests, known-limit tests (regular train 0, Poisson 1), and
|
|
55
|
+
property-based invariants.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# spikestats
|
|
2
|
+
|
|
3
|
+
Pure-Python spike-train statistics. Zero runtime dependencies. Completes the toolkit with
|
|
4
|
+
spikegen (generate) and spikedist (compare).
|
|
5
|
+
|
|
6
|
+
## Commands
|
|
7
|
+
|
|
8
|
+
- Create env and install: `uv venv && uv pip install -e ".[dev]"`
|
|
9
|
+
- Test: `uv run pytest -q`
|
|
10
|
+
- Lint: `uv run ruff check .` (format with `uv run ruff format .`)
|
|
11
|
+
- Types: `uv run mypy src`
|
|
12
|
+
- Build: `uv build` (then `uv run --with twine twine check dist/*` before publishing)
|
|
13
|
+
- Example: `python examples/summary.py`
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
`src/spikestats/`:
|
|
18
|
+
- `_validate.py` shared validation (positivity, non-negativity, finite times, minimum spikes)
|
|
19
|
+
- `metrics.py` the statistics (firing_rate, inter_spike_intervals, cv_isi, cv2, lv, lvr,
|
|
20
|
+
spike_counts, fano_factor)
|
|
21
|
+
- `__init__.py` public surface
|
|
22
|
+
|
|
23
|
+
See `docs/architecture.md` for the formulas and references.
|
|
24
|
+
|
|
25
|
+
## Conventions
|
|
26
|
+
|
|
27
|
+
- A spike train is a plain `list[float]` of times; functions sort the input internally.
|
|
28
|
+
- Metrics return plain `float`; intervals and counts return lists.
|
|
29
|
+
- Parameters after `*` are keyword-only; no default values.
|
|
30
|
+
- No runtime dependencies (standard library `statistics` and `math` only). Note the module
|
|
31
|
+
is `metrics.py`, not `statistics.py`, to avoid shadowing the standard library module.
|
|
32
|
+
|
|
33
|
+
## Testing rules
|
|
34
|
+
|
|
35
|
+
- Exact value for every metric against a hand-computed example.
|
|
36
|
+
- Known limits: a regular train gives 0, a Poisson process gives 1 (CV, Lv, Fano).
|
|
37
|
+
- The identity LvR(refractory=0) == Lv is asserted.
|
|
38
|
+
- Hypothesis property tests for bounds and invariants; bug fixes start with a failing test.
|
|
39
|
+
|
|
40
|
+
## Release
|
|
41
|
+
|
|
42
|
+
- Semantic versioning; update `CHANGELOG.md` and `__version__`.
|
|
43
|
+
- Gates: `uv run pytest && uv run ruff check . && uv run mypy src && uv build && uv run twine check dist/*`.
|
|
44
|
+
- Publish to PyPI, tag `vX.Y.Z`, GitHub release.
|
|
45
|
+
|
|
46
|
+
## Style
|
|
47
|
+
|
|
48
|
+
- No em dash characters in docs, comments, or commit messages.
|
|
49
|
+
- Comments explain non-obvious reasoning only.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and maintainers pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
## Our standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to a positive environment:
|
|
15
|
+
|
|
16
|
+
- Showing empathy and kindness toward other people.
|
|
17
|
+
- Being respectful of differing opinions, viewpoints, and experiences.
|
|
18
|
+
- Giving and gracefully accepting constructive feedback.
|
|
19
|
+
- Focusing on what is best for the community.
|
|
20
|
+
|
|
21
|
+
Examples of unacceptable behavior:
|
|
22
|
+
|
|
23
|
+
- Harassment, insulting or derogatory comments, and personal or political attacks.
|
|
24
|
+
- Public or private harassment.
|
|
25
|
+
- Publishing others' private information without explicit permission.
|
|
26
|
+
- Other conduct which could reasonably be considered inappropriate.
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
31
|
+
reported to the maintainer at amaar2cool@gmail.com. All complaints will be
|
|
32
|
+
reviewed and investigated promptly and fairly.
|
|
33
|
+
|
|
34
|
+
## Attribution
|
|
35
|
+
|
|
36
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
|
|
37
|
+
version 2.1.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Contributing to spikestats
|
|
2
|
+
|
|
3
|
+
Thanks for your interest. This project values correctness, clear references, and zero
|
|
4
|
+
runtime dependencies.
|
|
5
|
+
|
|
6
|
+
## Development
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
uv venv
|
|
10
|
+
uv pip install -e ".[dev]"
|
|
11
|
+
uv run pytest -q
|
|
12
|
+
uv run ruff check .
|
|
13
|
+
uv run mypy src
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
A standard virtual environment with `pip install -e ".[dev]"` works the same way.
|
|
17
|
+
|
|
18
|
+
## Guidelines
|
|
19
|
+
|
|
20
|
+
- No runtime dependencies. The standard library `statistics` and `math` are enough.
|
|
21
|
+
- Every metric needs an exact-value test against a hand-computed example and, where it
|
|
22
|
+
applies, a known limit (a regular train is 0, a Poisson process is 1).
|
|
23
|
+
- New metrics must cite the definition they implement in the docstring and in
|
|
24
|
+
docs/architecture.md, so the formula can be checked against a source.
|
|
25
|
+
- Parameters after `*` are keyword-only with no default values.
|
|
26
|
+
- A bug fix starts with a failing test.
|
|
27
|
+
- Run `uv run ruff format .` before committing.
|
|
28
|
+
- Commit messages follow `type(scope): description`.
|
|
29
|
+
|
|
30
|
+
## Reporting issues
|
|
31
|
+
|
|
32
|
+
Open an issue with the spike times, the call and its parameters, and the value you expected
|
|
33
|
+
versus the value you observed.
|
spikestats-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amaar Chughtai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spikestats
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Spike-train statistics (firing rate, CV, CV2, Fano factor, local variation Lv and LvR, PSTH, time-resolved rate and Fano) in pure Python with zero dependencies.
|
|
5
|
+
Project-URL: Homepage, https://github.com/amaar-mc/spikestats
|
|
6
|
+
Project-URL: Repository, https://github.com/amaar-mc/spikestats
|
|
7
|
+
Project-URL: Issues, https://github.com/amaar-mc/spikestats/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/amaar-mc/spikestats/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Amaar Chughtai
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Amaar Chughtai
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: coefficient-of-variation,computational-neuroscience,fano-factor,firing-rate,local-variation,neuromorphic,neuroscience,point-process,spike-train,spiking-neural-networks
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
43
|
+
Classifier: Typing :: Typed
|
|
44
|
+
Requires-Python: >=3.10
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: hypothesis>=6; extra == 'dev'
|
|
47
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
49
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# spikestats
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="assets/logo.png" alt="spikestats logo" width="160">
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
Spike-train statistics in pure Python, with zero dependencies.
|
|
59
|
+
|
|
60
|
+
`spikestats` computes the standard measures of spike-train rate and variability from a plain
|
|
61
|
+
list of spike times: firing rate, inter-spike intervals, coefficient of variation, CV2,
|
|
62
|
+
local variation (Lv and the refractory-corrected LvR), spike counts, and the Fano factor.
|
|
63
|
+
There is nothing to configure and nothing to install beyond the package itself: the input
|
|
64
|
+
is a `list[float]` of spike times and the output is a `float`.
|
|
65
|
+
|
|
66
|
+
It pairs with [spikegen](https://github.com/amaar-mc/spikegen) for generating trains and
|
|
67
|
+
[spikedist](https://github.com/amaar-mc/spikedist) for comparing them. The three share the
|
|
68
|
+
same plain-list data model, so they compose without adapters.
|
|
69
|
+
|
|
70
|
+
## Why
|
|
71
|
+
|
|
72
|
+
The established tools for these measures, Elephant and spiketools, are excellent but pull in
|
|
73
|
+
NumPy, SciPy, and custom data objects (`neo.SpikeTrain` and friends). When you only need a
|
|
74
|
+
firing rate or a CV from a list of spike times, that is a heavy dependency tree to carry, and
|
|
75
|
+
it is awkward in teaching material, small scripts, and lightweight pipelines. `spikestats`
|
|
76
|
+
keeps the math, drops the dependencies, and works on the lists you already have.
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pip install spikestats
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import spikestats as ss
|
|
88
|
+
|
|
89
|
+
spikes = [0.012, 0.031, 0.058, 0.090, 0.110, 0.155] # seconds
|
|
90
|
+
|
|
91
|
+
ss.firing_rate(spikes, duration=0.2) # spikes per second
|
|
92
|
+
ss.inter_spike_intervals(spikes) # consecutive differences
|
|
93
|
+
ss.cv_isi(spikes) # coefficient of variation of the ISIs
|
|
94
|
+
ss.cv2(spikes) # Holt et al. 1996, robust to rate drift
|
|
95
|
+
ss.lv(spikes) # Shinomoto et al. 2003 local variation
|
|
96
|
+
ss.lvr(spikes, refractory=0.002) # Shinomoto et al. 2009, refractory-corrected
|
|
97
|
+
ss.spike_counts(spikes, duration=0.2, bin_width=0.05)
|
|
98
|
+
ss.fano_factor(spikes, duration=0.2, bin_width=0.05)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Time-resolved metrics
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import spikestats as ss
|
|
105
|
+
|
|
106
|
+
spikes = [0.012, 0.031, 0.058, 0.090, 0.110, 0.155, 0.210, 0.245] # seconds
|
|
107
|
+
|
|
108
|
+
# Non-overlapping bin counts tiling [0, duration)
|
|
109
|
+
counts = ss.binned_spike_counts(spikes, duration=0.3, bin_width=0.1)
|
|
110
|
+
# => [3, 3, 2] (one list[int] per bin)
|
|
111
|
+
|
|
112
|
+
# Sliding-window firing rate: returns (center_times, rates_hz)
|
|
113
|
+
centers, rates = ss.time_resolved_rate(spikes, duration=0.3, bin_width=0.1, step=0.05)
|
|
114
|
+
|
|
115
|
+
# PSTH averaged over multiple trials: returns (bin_center_times, mean_rate_hz)
|
|
116
|
+
trials = [spikes, [0.020, 0.060, 0.100, 0.140, 0.200]]
|
|
117
|
+
bin_centers, mean_rates = ss.psth(trials, duration=0.3, bin_width=0.1)
|
|
118
|
+
|
|
119
|
+
# Per-bin Fano factor across trials: returns (bin_center_times, fano_per_bin)
|
|
120
|
+
bin_centers, fano = ss.time_resolved_fano(trials, duration=0.3, bin_width=0.1)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## API
|
|
124
|
+
|
|
125
|
+
All functions take spike times as a sequence of numbers and sort them internally.
|
|
126
|
+
|
|
127
|
+
### Scalar metrics
|
|
128
|
+
|
|
129
|
+
- `firing_rate(spikes, *, duration)`: spike count divided by `duration`.
|
|
130
|
+
- `inter_spike_intervals(spikes)`: list of consecutive differences (empty for fewer than two spikes).
|
|
131
|
+
- `cv_isi(spikes)`: population standard deviation of the ISIs over their mean. Regular train 0, Poisson 1.
|
|
132
|
+
- `cv2(spikes)`: mean of `2 * |I(n+1) - I(n)| / (I(n+1) + I(n))` over adjacent intervals.
|
|
133
|
+
- `lv(spikes)`: mean of `3 * ((I(n) - I(n+1)) / (I(n) + I(n+1)))^2`. Regular train 0, Poisson 1.
|
|
134
|
+
- `lvr(spikes, *, refractory)`: LvR with a refractoriness constant in the spike-time unit.
|
|
135
|
+
- `spike_counts(spikes, *, duration, bin_width)`: counts per equal-width bin tiling `[0, n * bin_width)`.
|
|
136
|
+
- `fano_factor(spikes, *, duration, bin_width)`: population variance of the bin counts over their mean.
|
|
137
|
+
|
|
138
|
+
### Time-resolved metrics
|
|
139
|
+
|
|
140
|
+
All functions use the half-open boundary `[0, duration)`: a spike at exactly `duration` is excluded.
|
|
141
|
+
|
|
142
|
+
- `binned_spike_counts(spikes, *, duration, bin_width) -> list[int]`: spike counts in
|
|
143
|
+
`int(duration / bin_width)` consecutive non-overlapping bins tiling `[0, duration)`.
|
|
144
|
+
- `time_resolved_rate(spikes, *, duration, bin_width, step) -> tuple[list[float], list[float]]`:
|
|
145
|
+
sliding-window firing rate. Window of width `bin_width` steps by `step` across `[0, duration)`.
|
|
146
|
+
Returns `(window_center_times, rates_in_hz)`. Window positions are computed by integer indexing
|
|
147
|
+
of the step size to avoid floating-point drift.
|
|
148
|
+
- `psth(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`: peristimulus time
|
|
149
|
+
histogram. `trials` is a sequence of spike-time sequences. Returns `(bin_center_times,
|
|
150
|
+
mean_rate_per_bin_hz)` averaged over trials. Raises `ValueError` on empty `trials`.
|
|
151
|
+
- `time_resolved_fano(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`:
|
|
152
|
+
per-bin Fano factor (population variance / mean of per-trial counts). Returns
|
|
153
|
+
`(bin_center_times, fano_per_bin)`. Bins with zero mean across all trials are returned as
|
|
154
|
+
`float('nan')`. Uses population variance (denominator N), so a single trial always gives 0.
|
|
155
|
+
|
|
156
|
+
Parameters after `*` are keyword-only and have no default values; pass them explicitly.
|
|
157
|
+
|
|
158
|
+
## Notes
|
|
159
|
+
|
|
160
|
+
- `cv_isi` uses the population standard deviation, matching the common `numpy.std` default.
|
|
161
|
+
- `cv2`, `lv`, and `lvr` need at least three spikes; they raise a clear `ValueError` otherwise.
|
|
162
|
+
- `spike_counts` uses `floor(duration / bin_width)` equal-width bins, so every bin has the same
|
|
163
|
+
width; any remainder of the duration and any spikes outside the binned window are ignored.
|
|
164
|
+
- `binned_spike_counts` uses `int(duration / bin_width)` bins (same count). All time-resolved
|
|
165
|
+
functions use the half-open interval `[0, duration)`: a spike at `t == duration` is excluded.
|
|
166
|
+
- `time_resolved_fano` uses population variance (denominator N). With a single trial, variance
|
|
167
|
+
is 0 for every bin; use multiple trials to get meaningful Fano estimates. Bins where the
|
|
168
|
+
mean count is 0 across all trials are returned as `float('nan')`.
|
|
169
|
+
- PyPI publish is queued behind the new-project-creation quota (currently returning 429 for new
|
|
170
|
+
packages). The dist is twine-verified and ready; upload will proceed once the quota resets.
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# spikestats
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/logo.png" alt="spikestats logo" width="160">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Spike-train statistics in pure Python, with zero dependencies.
|
|
8
|
+
|
|
9
|
+
`spikestats` computes the standard measures of spike-train rate and variability from a plain
|
|
10
|
+
list of spike times: firing rate, inter-spike intervals, coefficient of variation, CV2,
|
|
11
|
+
local variation (Lv and the refractory-corrected LvR), spike counts, and the Fano factor.
|
|
12
|
+
There is nothing to configure and nothing to install beyond the package itself: the input
|
|
13
|
+
is a `list[float]` of spike times and the output is a `float`.
|
|
14
|
+
|
|
15
|
+
It pairs with [spikegen](https://github.com/amaar-mc/spikegen) for generating trains and
|
|
16
|
+
[spikedist](https://github.com/amaar-mc/spikedist) for comparing them. The three share the
|
|
17
|
+
same plain-list data model, so they compose without adapters.
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
The established tools for these measures, Elephant and spiketools, are excellent but pull in
|
|
22
|
+
NumPy, SciPy, and custom data objects (`neo.SpikeTrain` and friends). When you only need a
|
|
23
|
+
firing rate or a CV from a list of spike times, that is a heavy dependency tree to carry, and
|
|
24
|
+
it is awkward in teaching material, small scripts, and lightweight pipelines. `spikestats`
|
|
25
|
+
keeps the math, drops the dependencies, and works on the lists you already have.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install spikestats
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import spikestats as ss
|
|
37
|
+
|
|
38
|
+
spikes = [0.012, 0.031, 0.058, 0.090, 0.110, 0.155] # seconds
|
|
39
|
+
|
|
40
|
+
ss.firing_rate(spikes, duration=0.2) # spikes per second
|
|
41
|
+
ss.inter_spike_intervals(spikes) # consecutive differences
|
|
42
|
+
ss.cv_isi(spikes) # coefficient of variation of the ISIs
|
|
43
|
+
ss.cv2(spikes) # Holt et al. 1996, robust to rate drift
|
|
44
|
+
ss.lv(spikes) # Shinomoto et al. 2003 local variation
|
|
45
|
+
ss.lvr(spikes, refractory=0.002) # Shinomoto et al. 2009, refractory-corrected
|
|
46
|
+
ss.spike_counts(spikes, duration=0.2, bin_width=0.05)
|
|
47
|
+
ss.fano_factor(spikes, duration=0.2, bin_width=0.05)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Time-resolved metrics
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import spikestats as ss
|
|
54
|
+
|
|
55
|
+
spikes = [0.012, 0.031, 0.058, 0.090, 0.110, 0.155, 0.210, 0.245] # seconds
|
|
56
|
+
|
|
57
|
+
# Non-overlapping bin counts tiling [0, duration)
|
|
58
|
+
counts = ss.binned_spike_counts(spikes, duration=0.3, bin_width=0.1)
|
|
59
|
+
# => [3, 3, 2] (one list[int] per bin)
|
|
60
|
+
|
|
61
|
+
# Sliding-window firing rate: returns (center_times, rates_hz)
|
|
62
|
+
centers, rates = ss.time_resolved_rate(spikes, duration=0.3, bin_width=0.1, step=0.05)
|
|
63
|
+
|
|
64
|
+
# PSTH averaged over multiple trials: returns (bin_center_times, mean_rate_hz)
|
|
65
|
+
trials = [spikes, [0.020, 0.060, 0.100, 0.140, 0.200]]
|
|
66
|
+
bin_centers, mean_rates = ss.psth(trials, duration=0.3, bin_width=0.1)
|
|
67
|
+
|
|
68
|
+
# Per-bin Fano factor across trials: returns (bin_center_times, fano_per_bin)
|
|
69
|
+
bin_centers, fano = ss.time_resolved_fano(trials, duration=0.3, bin_width=0.1)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
All functions take spike times as a sequence of numbers and sort them internally.
|
|
75
|
+
|
|
76
|
+
### Scalar metrics
|
|
77
|
+
|
|
78
|
+
- `firing_rate(spikes, *, duration)`: spike count divided by `duration`.
|
|
79
|
+
- `inter_spike_intervals(spikes)`: list of consecutive differences (empty for fewer than two spikes).
|
|
80
|
+
- `cv_isi(spikes)`: population standard deviation of the ISIs over their mean. Regular train 0, Poisson 1.
|
|
81
|
+
- `cv2(spikes)`: mean of `2 * |I(n+1) - I(n)| / (I(n+1) + I(n))` over adjacent intervals.
|
|
82
|
+
- `lv(spikes)`: mean of `3 * ((I(n) - I(n+1)) / (I(n) + I(n+1)))^2`. Regular train 0, Poisson 1.
|
|
83
|
+
- `lvr(spikes, *, refractory)`: LvR with a refractoriness constant in the spike-time unit.
|
|
84
|
+
- `spike_counts(spikes, *, duration, bin_width)`: counts per equal-width bin tiling `[0, n * bin_width)`.
|
|
85
|
+
- `fano_factor(spikes, *, duration, bin_width)`: population variance of the bin counts over their mean.
|
|
86
|
+
|
|
87
|
+
### Time-resolved metrics
|
|
88
|
+
|
|
89
|
+
All functions use the half-open boundary `[0, duration)`: a spike at exactly `duration` is excluded.
|
|
90
|
+
|
|
91
|
+
- `binned_spike_counts(spikes, *, duration, bin_width) -> list[int]`: spike counts in
|
|
92
|
+
`int(duration / bin_width)` consecutive non-overlapping bins tiling `[0, duration)`.
|
|
93
|
+
- `time_resolved_rate(spikes, *, duration, bin_width, step) -> tuple[list[float], list[float]]`:
|
|
94
|
+
sliding-window firing rate. Window of width `bin_width` steps by `step` across `[0, duration)`.
|
|
95
|
+
Returns `(window_center_times, rates_in_hz)`. Window positions are computed by integer indexing
|
|
96
|
+
of the step size to avoid floating-point drift.
|
|
97
|
+
- `psth(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`: peristimulus time
|
|
98
|
+
histogram. `trials` is a sequence of spike-time sequences. Returns `(bin_center_times,
|
|
99
|
+
mean_rate_per_bin_hz)` averaged over trials. Raises `ValueError` on empty `trials`.
|
|
100
|
+
- `time_resolved_fano(trials, *, duration, bin_width) -> tuple[list[float], list[float]]`:
|
|
101
|
+
per-bin Fano factor (population variance / mean of per-trial counts). Returns
|
|
102
|
+
`(bin_center_times, fano_per_bin)`. Bins with zero mean across all trials are returned as
|
|
103
|
+
`float('nan')`. Uses population variance (denominator N), so a single trial always gives 0.
|
|
104
|
+
|
|
105
|
+
Parameters after `*` are keyword-only and have no default values; pass them explicitly.
|
|
106
|
+
|
|
107
|
+
## Notes
|
|
108
|
+
|
|
109
|
+
- `cv_isi` uses the population standard deviation, matching the common `numpy.std` default.
|
|
110
|
+
- `cv2`, `lv`, and `lvr` need at least three spikes; they raise a clear `ValueError` otherwise.
|
|
111
|
+
- `spike_counts` uses `floor(duration / bin_width)` equal-width bins, so every bin has the same
|
|
112
|
+
width; any remainder of the duration and any spikes outside the binned window are ignored.
|
|
113
|
+
- `binned_spike_counts` uses `int(duration / bin_width)` bins (same count). All time-resolved
|
|
114
|
+
functions use the half-open interval `[0, duration)`: a spike at `t == duration` is excluded.
|
|
115
|
+
- `time_resolved_fano` uses population variance (denominator N). With a single trial, variance
|
|
116
|
+
is 0 for every bin; use multiple trials to get meaningful Fano estimates. Bins where the
|
|
117
|
+
mean count is 0 across all trials are returned as `float('nan')`.
|
|
118
|
+
- PyPI publish is queued behind the new-project-creation quota (currently returning 429 for new
|
|
119
|
+
packages). The dist is twine-verified and ready; upload will proceed once the quota resets.
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
`spikestats` is a pure computation library with no runtime dependencies, no network access,
|
|
6
|
+
and no file system access. The attack surface is limited to incorrect results from
|
|
7
|
+
malformed input, which the library guards against with explicit validation.
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
If you find a security issue, please email amaar2cool@gmail.com with details and steps to
|
|
12
|
+
reproduce. Please do not open a public issue for security reports. You can expect an
|
|
13
|
+
initial response within a few days.
|
|
14
|
+
|
|
15
|
+
## Supported versions
|
|
16
|
+
|
|
17
|
+
The latest published minor version receives fixes. Pre-1.0 releases may introduce breaking
|
|
18
|
+
changes in minor versions, as allowed by semantic versioning.
|
|
Binary file
|