py-mea-flow 0.5.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.
- py_mea_flow-0.5.0/LICENSE +21 -0
- py_mea_flow-0.5.0/PKG-INFO +340 -0
- py_mea_flow-0.5.0/README.md +309 -0
- py_mea_flow-0.5.0/py_mea_flow/__init__.py +6 -0
- py_mea_flow-0.5.0/py_mea_flow/burst/__init__.py +1 -0
- py_mea_flow-0.5.0/py_mea_flow/burst/detection.py +367 -0
- py_mea_flow-0.5.0/py_mea_flow/burst/metrics.py +359 -0
- py_mea_flow-0.5.0/py_mea_flow/cli.py +2429 -0
- py_mea_flow-0.5.0/py_mea_flow/io/__init__.py +1 -0
- py_mea_flow-0.5.0/py_mea_flow/io/metadata.py +182 -0
- py_mea_flow-0.5.0/py_mea_flow/io/spk_reader.py +611 -0
- py_mea_flow-0.5.0/py_mea_flow/network/__init__.py +1 -0
- py_mea_flow-0.5.0/py_mea_flow/network/detection.py +367 -0
- py_mea_flow-0.5.0/py_mea_flow/network/metrics.py +184 -0
- py_mea_flow-0.5.0/py_mea_flow/network/synchrony.py +279 -0
- py_mea_flow-0.5.0/py_mea_flow/pipeline.py +1039 -0
- py_mea_flow-0.5.0/py_mea_flow/spike/__init__.py +1 -0
- py_mea_flow-0.5.0/py_mea_flow/spike/metrics.py +282 -0
- py_mea_flow-0.5.0/py_mea_flow/stats/__init__.py +19 -0
- py_mea_flow-0.5.0/py_mea_flow/stats/compare.py +752 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/__init__.py +1 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/burst_charts.py +280 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/comparison.py +371 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/heatmap.py +174 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/network_plots.py +198 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/pca.py +372 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/plate.py +168 -0
- py_mea_flow-0.5.0/py_mea_flow/viz/trajectory.py +226 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/PKG-INFO +340 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/SOURCES.txt +45 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/dependency_links.txt +1 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/entry_points.txt +2 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/requires.txt +18 -0
- py_mea_flow-0.5.0/py_mea_flow.egg-info/top_level.txt +1 -0
- py_mea_flow-0.5.0/pyproject.toml +46 -0
- py_mea_flow-0.5.0/setup.cfg +4 -0
- py_mea_flow-0.5.0/tests/test_burst_detection.py +308 -0
- py_mea_flow-0.5.0/tests/test_burst_metrics.py +237 -0
- py_mea_flow-0.5.0/tests/test_cli.py +1548 -0
- py_mea_flow-0.5.0/tests/test_metadata.py +210 -0
- py_mea_flow-0.5.0/tests/test_network_detection.py +294 -0
- py_mea_flow-0.5.0/tests/test_pipeline.py +383 -0
- py_mea_flow-0.5.0/tests/test_spike_metrics.py +267 -0
- py_mea_flow-0.5.0/tests/test_spk_reader.py +393 -0
- py_mea_flow-0.5.0/tests/test_stats.py +537 -0
- py_mea_flow-0.5.0/tests/test_synchrony.py +217 -0
- py_mea_flow-0.5.0/tests/test_viz.py +1225 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Molecularbiologyworld
|
|
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,340 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: py-mea-flow
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: End-to-end MEA data analysis for Axion Biosystems instruments
|
|
5
|
+
Author: George (Zhuang) Han
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: MEA,electrophysiology,Axion,spike,burst,neuroscience
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy>=1.26
|
|
17
|
+
Requires-Dist: scipy>=1.11
|
|
18
|
+
Requires-Dist: pandas>=2.1
|
|
19
|
+
Requires-Dist: matplotlib>=3.8
|
|
20
|
+
Requires-Dist: seaborn>=0.13
|
|
21
|
+
Requires-Dist: pingouin>=0.5.4
|
|
22
|
+
Requires-Dist: statsmodels>=0.14
|
|
23
|
+
Provides-Extra: interactive
|
|
24
|
+
Requires-Dist: plotly>=5.18; extra == "interactive"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-cov>=4.1; extra == "dev"
|
|
28
|
+
Provides-Extra: docs
|
|
29
|
+
Requires-Dist: sphinx>=7.2; extra == "docs"
|
|
30
|
+
Requires-Dist: nbsphinx>=0.9; extra == "docs"
|
|
31
|
+
|
|
32
|
+
# py-mea-flow
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/py-mea-flow/)
|
|
35
|
+
[](https://pypi.org/project/py-mea-flow/)
|
|
36
|
+
[](https://github.com/Molecularbiologyworld/py-mea-flow)
|
|
37
|
+
|
|
38
|
+
Welcome to our MEA Python package!
|
|
39
|
+
|
|
40
|
+
> **Renamed:** this package was called `py-mea-axion` up to version 0.4.0. Install `py-mea-flow`, import `py_mea_flow`, and run the `mea-flow` command.
|
|
41
|
+
|
|
42
|
+
End-to-end analysis of multi-electrode array (MEA) recordings from **Axion Biosystems** instruments, in Python.
|
|
43
|
+
|
|
44
|
+
`py-mea-flow` reads raw `.spk` binary files and carries the analysis through spike metrics, burst detection, network-burst detection, and synchrony measurement, all the way to statistical comparisons and publication-ready figures, **driven entirely from the command line**.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
conda create -n mea python=3.11
|
|
52
|
+
conda activate mea
|
|
53
|
+
pip install py-mea-flow
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For development against a local clone:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/Molecularbiologyworld/py-mea-flow.git
|
|
60
|
+
cd py-mea-flow
|
|
61
|
+
pip install -e .
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
To install the latest commit on `master` directly from GitHub:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install git+https://github.com/Molecularbiologyworld/py-mea-flow.git
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Requirements:** Python ≥ 3.10, numpy, scipy, pandas, matplotlib, pingouin, statsmodels.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Workflow at a glance
|
|
75
|
+
|
|
76
|
+
The CLI is organised around four phases:
|
|
77
|
+
|
|
78
|
+
1. `mea-flow build` processes a folder of `.spk` files into a single labelled master CSV.
|
|
79
|
+
2. `mea-flow plot <subcommand>` generates figures from the master CSV.
|
|
80
|
+
3. `mea-flow stats` writes a long-format CSV of pairwise condition-comparison results, using the same statistical dispatcher that drives the violin brackets.
|
|
81
|
+
4. `mea-flow show-layout` prints the well-to-condition map encoded in any master CSV.
|
|
82
|
+
|
|
83
|
+
There are also `mea-flow run` (single recording, CSVs and figures) and `mea-flow summary` (single recording, stdout table) for one-off analyses.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Filename convention
|
|
88
|
+
|
|
89
|
+
`build` requires every `.spk` file to carry **plate** and **DIV** in its name:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
<anything>_Plate<N>_DIV<N>.spk
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Detection regex (case-insensitive): `Plate(\d+)_DIV(\d+)`. Anything before or after that block is ignored. Files in the input folder that do not match are skipped with a warning.
|
|
96
|
+
|
|
97
|
+
| Filename | Plate | DIV |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `Plate1_DIV14.spk` | 1 | 14 |
|
|
100
|
+
| `20251002_Plate2_DIV26.spk` | 2 | 26 |
|
|
101
|
+
| `LGI2KD_Plate3_DIV7_recording2.spk` | 3 | 7 |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Build a master CSV
|
|
106
|
+
|
|
107
|
+
You specify the well-to-condition layout once, on the command line:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
mea-flow build "data/" --fs-override 12500 \
|
|
111
|
+
--well 1_A1=SCRM,B1,T1,Batch1 \
|
|
112
|
+
--well 1_A2=KD,B1,T1,Batch1 \
|
|
113
|
+
--well 1_B1=SCRM,B1,T2,Batch1 \
|
|
114
|
+
--well 1_B2=KD,B1,T2,Batch1 \
|
|
115
|
+
... \
|
|
116
|
+
--out master.csv
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Each `--well` entry follows the form `<plate>_<well>=<condition>[,B<bio>,T<tech>,<batch>]`.
|
|
120
|
+
|
|
121
|
+
- `B<n>` (biological replicate) and `T<n>` (technical replicate) are optional.
|
|
122
|
+
- The 4th comma-separated value is the batch label (free-form, e.g. `Batch1`, `Plate2`).
|
|
123
|
+
- Bio rep auto-derives from `(plate, well)` if not specified.
|
|
124
|
+
|
|
125
|
+
**Output**: `master.csv` (one row per well per DIV, with metric columns plus condition / bio_rep / tech_rep / batch columns) and a sibling `master.build.sh` containing the command for re-runs.
|
|
126
|
+
|
|
127
|
+
### Re-using a layout
|
|
128
|
+
|
|
129
|
+
Three ways to avoid retyping the layout for a follow-up build:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Option 1: re-run the auto-saved script.
|
|
133
|
+
bash master.build.sh
|
|
134
|
+
|
|
135
|
+
# Option 2: pull the layout from an existing master CSV.
|
|
136
|
+
mea-flow build "data_v2/" --fs-override 12500 --layout-from master.csv --out master_v2.csv
|
|
137
|
+
|
|
138
|
+
# Option 3: print the equivalent --well flags to stdout.
|
|
139
|
+
mea-flow show-layout master.csv
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Plot subcommands
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
mea-flow plot heatmap master.csv --metric mean_mfr_active_hz --div 21 --out figs/
|
|
148
|
+
mea-flow plot trajectory master.csv --metric mean_mfr_active_hz --out figs/
|
|
149
|
+
mea-flow plot timepoint master.csv --metric mean_mfr_active_hz --div 21 26 33 --out figs/
|
|
150
|
+
mea-flow plot pca master.csv --out figs/
|
|
151
|
+
mea-flow plot raster "recording.spk" --fs-override 12500 --wells A1 --out figs/
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
| Subcommand | Input | What it produces |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `heatmap` | master CSV | 4×6 plate grid, one panel per plate, coloured by metric. One PNG per (metric, DIV). |
|
|
157
|
+
| `trajectory` | master CSV | Mean ± SEM error-bars per condition across DIVs. One PNG per metric. |
|
|
158
|
+
| `timepoint` | master CSV | Violin and jitter per condition at one DIV, with user-selectable significance brackets. One PNG per (metric, DIV). |
|
|
159
|
+
| `pca` | master CSV | PCA scatter coloured by condition. One pooled PNG, or one per `--div`. Optional loadings figure. |
|
|
160
|
+
| `raster` | `.spk` file | Burst raster and ASDR histogram for each well. |
|
|
161
|
+
|
|
162
|
+
### Common plot flags
|
|
163
|
+
|
|
164
|
+
| Flag | Effect |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `--metric COL [COL ...]` | One or more metric columns. Omit to plot all numeric columns. |
|
|
167
|
+
| `--div N [N ...]` | Specific time points (timepoint, pca, heatmap). |
|
|
168
|
+
| `--div-min N --div-max N` | Filter the time range (trajectory, pca). |
|
|
169
|
+
| `--filter COL=VAL[,VAL...]` | Restrict the input to specific column values. Repeatable; multiple flags AND together. Example: `--filter condition=SCRM --filter DIV=14,28`. |
|
|
170
|
+
| `--group-order GROUP [GROUP ...]` | Explicit condition order (default: alphabetical). Listing a subset excludes other groups from the plot. |
|
|
171
|
+
| `--color GROUP=#HEX` | Colour per condition. Repeatable. Hex codes or matplotlib named colours both work. |
|
|
172
|
+
| `--pool` | Flatten bio/tech replicate hierarchy and treat every well as independent. Default is hierarchical (collapse tech reps within bio rep before stats). |
|
|
173
|
+
| `--figsize W H` | Figure size in inches. Default depends on the plot type. |
|
|
174
|
+
| `--out DIR` | Output directory (auto-created). |
|
|
175
|
+
|
|
176
|
+
### Flags specific to `plot timepoint` (violins)
|
|
177
|
+
|
|
178
|
+
| Flag | Effect |
|
|
179
|
+
|---|---|
|
|
180
|
+
| `--test {tukey,mannwhitney,kruskal}` | Statistical test for the significance brackets. Default `tukey` (parametric all-pairs Tukey HSD). `mannwhitney` runs pairwise Mann-Whitney U with Bonferroni correction. `kruskal` runs Kruskal-Wallis omnibus followed by Dunn's pairwise post-hoc. The choice is yours; the package does not auto-select. |
|
|
181
|
+
| `--compare GROUP_A GROUP_B` | Restrict significance brackets to specific pairs. Repeatable. |
|
|
182
|
+
| `--point-hue COL` | Colour individual jitter points by another column (e.g. `batch`). |
|
|
183
|
+
| `--point-color VALUE=#HEX` | Per-value colour palette for `--point-hue`. Repeatable. |
|
|
184
|
+
| `--point-shape COL` | Use marker shape (in addition to or instead of colour) for individual jitter points. Default markers cycle circle, square, triangle, diamond, etc. |
|
|
185
|
+
| `--point-shape-map VALUE=MARKER` | Per-value marker for `--point-shape`. Repeatable. Markers can be matplotlib codes (`o`, `s`, `^`, ...) or aliases (`circle`, `square`, `triangle`, ...). |
|
|
186
|
+
| `--point-size N` | Marker area for jitter points. Default 40. |
|
|
187
|
+
| `--show-point-legend` | Show a legend mapping point colours to `--point-hue` values. Default hidden. |
|
|
188
|
+
|
|
189
|
+
### Flags specific to `plot raster`
|
|
190
|
+
|
|
191
|
+
| Flag | Effect |
|
|
192
|
+
|---|---|
|
|
193
|
+
| `--asdr-bin S` | ASDR histogram bin width in seconds. Default 0.2. |
|
|
194
|
+
| `--time-start S --time-end S` | Restrict to a time window in seconds within the recording. Displayed times keep the original timestamps. |
|
|
195
|
+
| `--max-isi S --min-spikes N` | Burst-detection thresholds for the orange overlay rectangles. |
|
|
196
|
+
|
|
197
|
+
### Flags specific to `plot pca`
|
|
198
|
+
|
|
199
|
+
| Flag | Effect |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `--loadings` | Also save a per-feature PC loadings CSV and a horizontal bar chart of the top contributors to PC1 and PC2. |
|
|
202
|
+
| `--top N` | Number of top features to show in the loadings figure. Default 10. |
|
|
203
|
+
| `--point-shape COL --point-shape-map VALUE=MARKER` | Same as for `timepoint`, useful for indicating biological replicates by marker shape. |
|
|
204
|
+
|
|
205
|
+
Run `mea-flow plot <subcommand> --help` for the full per-subcommand option list.
|
|
206
|
+
|
|
207
|
+
### Example: a complete violin command
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
mea-flow plot timepoint master.csv \
|
|
211
|
+
--metric mean_mfr_active_hz burst_freq_avg network_burst_freq mean_sttc \
|
|
212
|
+
--div 21 26 33 \
|
|
213
|
+
--group-order SCRM LGI2_KD4 LGI2_KD5 \
|
|
214
|
+
--color SCRM=green --color LGI2_KD4=lightcoral --color LGI2_KD5=red \
|
|
215
|
+
--point-shape batch --point-shape-map Batch1=circle --point-shape-map Batch2=square --point-shape-map Batch3=triangle \
|
|
216
|
+
--compare LGI2_KD4 SCRM --compare LGI2_KD5 SCRM \
|
|
217
|
+
--test tukey \
|
|
218
|
+
--pool \
|
|
219
|
+
--out figs/timepoint
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Pretty axis labels
|
|
223
|
+
|
|
224
|
+
Axis labels and colour-bar titles render human-readable names (`Mean firing rate (Hz)` rather than `mean_mfr_active_hz`). The CLI flag values still use raw column names, which are easier to type.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Statistical analyses (`mea-flow stats`)
|
|
229
|
+
|
|
230
|
+
Beyond the brackets shown on violin plots, `mea-flow stats` writes a long-format CSV of pairwise condition-comparison results. Same data, same dispatcher as the violin brackets, just persisted as a tidy table for supplementary materials.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
mea-flow stats master.csv \
|
|
234
|
+
--metric mean_mfr_active_hz burst_freq_avg network_burst_freq mean_sttc \
|
|
235
|
+
--div 28 41 \
|
|
236
|
+
--compare LGI2_KD4 SCRM --compare LGI2_KD5 SCRM \
|
|
237
|
+
--test tukey \
|
|
238
|
+
--pool \
|
|
239
|
+
--out stats_summary.csv
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The output CSV has one row per (metric, time-point, pair) combination, with columns `metric`, `DIV`, `test`, `group_a`, `group_b`, `mean_diff`, `p_adj`, `significance`, `n_a`, `n_b`. Sort by metric and DIV in Excel for a clean supplementary table.
|
|
243
|
+
|
|
244
|
+
The same `--test` choice (`tukey`, `mannwhitney`, `kruskal`) applies. Significance labels (`*`, `**`, `***`, `ns`) match those used in the figures.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Single-recording commands
|
|
249
|
+
|
|
250
|
+
For ad-hoc inspection of one `.spk` file without going through `build`:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Quick per-well summary printed to the terminal (no files written)
|
|
254
|
+
mea-flow summary recording.spk --fs-override 12500
|
|
255
|
+
|
|
256
|
+
# Full pipeline: writes CSVs and figures to results/
|
|
257
|
+
mea-flow run recording.spk --out results/ --fs-override 12500
|
|
258
|
+
|
|
259
|
+
# Restrict to specific wells
|
|
260
|
+
mea-flow summary recording.spk --wells A1 B1 C1 --fs-override 12500
|
|
261
|
+
|
|
262
|
+
# Analyse only a time window
|
|
263
|
+
mea-flow run recording.spk --time-start 300 --time-end 600 --out results/ --fs-override 12500
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Python API
|
|
269
|
+
|
|
270
|
+
For programmatic use:
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from py_mea_flow import MEAExperiment
|
|
274
|
+
|
|
275
|
+
exp = MEAExperiment(
|
|
276
|
+
"recording.spk",
|
|
277
|
+
metadata="plate_map.csv", # optional CSV with well_id, condition, DIV, replicate_id
|
|
278
|
+
fs_override=12500,
|
|
279
|
+
).run()
|
|
280
|
+
|
|
281
|
+
exp.spike_metrics # per-electrode metrics
|
|
282
|
+
exp.burst_table # one row per detected burst
|
|
283
|
+
exp.well_summary # per-well aggregate (27 metrics)
|
|
284
|
+
exp.to_csv("results.csv")
|
|
285
|
+
|
|
286
|
+
exp.plot_heatmap("A1")
|
|
287
|
+
exp.plot_raster("A1")
|
|
288
|
+
exp.plot_trajectory("mean_mfr_active_hz")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The `py_mea_flow.stats` module exposes the same statistical functions used by the CLI:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from py_mea_flow.stats import (
|
|
295
|
+
pairwise_test, # unified dispatcher: tukey / mannwhitney / kruskal
|
|
296
|
+
tukey_hsd_pairwise, # Tukey HSD only
|
|
297
|
+
compare_conditions, # auto-dispatch MW (2 groups) or KW (3+ groups)
|
|
298
|
+
longitudinal_model, # linear mixed-effects with time x group interaction
|
|
299
|
+
compute_icc, # intraclass correlation
|
|
300
|
+
)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Note on Axion `.spk` files
|
|
306
|
+
|
|
307
|
+
Some recordings lack a `BlockVectorHeader` (firmware-dependent). When that happens, sampling-rate detection may guess wrong; pass `--fs-override` explicitly:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
mea-flow run recording.spk --fs-override 12500
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
12500 Hz is the standard rate for Axion CytoView 24-well plates.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Running the tests
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
pip install -e ".[dev]"
|
|
321
|
+
pytest
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
649 tests covering every module: binary parser, burst detection, network-burst detection, synchrony, statistical tests, every viz function, and every CLI subcommand.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Citing
|
|
329
|
+
|
|
330
|
+
If you use `py-mea-flow` in your research, please cite:
|
|
331
|
+
|
|
332
|
+
> [manuscript in preparation]
|
|
333
|
+
|
|
334
|
+
[](https://doi.org/10.5281/zenodo.19350375)
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
MIT, see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# py-mea-flow
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/py-mea-flow/)
|
|
4
|
+
[](https://pypi.org/project/py-mea-flow/)
|
|
5
|
+
[](https://github.com/Molecularbiologyworld/py-mea-flow)
|
|
6
|
+
|
|
7
|
+
Welcome to our MEA Python package!
|
|
8
|
+
|
|
9
|
+
> **Renamed:** this package was called `py-mea-axion` up to version 0.4.0. Install `py-mea-flow`, import `py_mea_flow`, and run the `mea-flow` command.
|
|
10
|
+
|
|
11
|
+
End-to-end analysis of multi-electrode array (MEA) recordings from **Axion Biosystems** instruments, in Python.
|
|
12
|
+
|
|
13
|
+
`py-mea-flow` reads raw `.spk` binary files and carries the analysis through spike metrics, burst detection, network-burst detection, and synchrony measurement, all the way to statistical comparisons and publication-ready figures, **driven entirely from the command line**.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
conda create -n mea python=3.11
|
|
21
|
+
conda activate mea
|
|
22
|
+
pip install py-mea-flow
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For development against a local clone:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/Molecularbiologyworld/py-mea-flow.git
|
|
29
|
+
cd py-mea-flow
|
|
30
|
+
pip install -e .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To install the latest commit on `master` directly from GitHub:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install git+https://github.com/Molecularbiologyworld/py-mea-flow.git
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Requirements:** Python ≥ 3.10, numpy, scipy, pandas, matplotlib, pingouin, statsmodels.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Workflow at a glance
|
|
44
|
+
|
|
45
|
+
The CLI is organised around four phases:
|
|
46
|
+
|
|
47
|
+
1. `mea-flow build` processes a folder of `.spk` files into a single labelled master CSV.
|
|
48
|
+
2. `mea-flow plot <subcommand>` generates figures from the master CSV.
|
|
49
|
+
3. `mea-flow stats` writes a long-format CSV of pairwise condition-comparison results, using the same statistical dispatcher that drives the violin brackets.
|
|
50
|
+
4. `mea-flow show-layout` prints the well-to-condition map encoded in any master CSV.
|
|
51
|
+
|
|
52
|
+
There are also `mea-flow run` (single recording, CSVs and figures) and `mea-flow summary` (single recording, stdout table) for one-off analyses.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Filename convention
|
|
57
|
+
|
|
58
|
+
`build` requires every `.spk` file to carry **plate** and **DIV** in its name:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
<anything>_Plate<N>_DIV<N>.spk
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Detection regex (case-insensitive): `Plate(\d+)_DIV(\d+)`. Anything before or after that block is ignored. Files in the input folder that do not match are skipped with a warning.
|
|
65
|
+
|
|
66
|
+
| Filename | Plate | DIV |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `Plate1_DIV14.spk` | 1 | 14 |
|
|
69
|
+
| `20251002_Plate2_DIV26.spk` | 2 | 26 |
|
|
70
|
+
| `LGI2KD_Plate3_DIV7_recording2.spk` | 3 | 7 |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Build a master CSV
|
|
75
|
+
|
|
76
|
+
You specify the well-to-condition layout once, on the command line:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
mea-flow build "data/" --fs-override 12500 \
|
|
80
|
+
--well 1_A1=SCRM,B1,T1,Batch1 \
|
|
81
|
+
--well 1_A2=KD,B1,T1,Batch1 \
|
|
82
|
+
--well 1_B1=SCRM,B1,T2,Batch1 \
|
|
83
|
+
--well 1_B2=KD,B1,T2,Batch1 \
|
|
84
|
+
... \
|
|
85
|
+
--out master.csv
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each `--well` entry follows the form `<plate>_<well>=<condition>[,B<bio>,T<tech>,<batch>]`.
|
|
89
|
+
|
|
90
|
+
- `B<n>` (biological replicate) and `T<n>` (technical replicate) are optional.
|
|
91
|
+
- The 4th comma-separated value is the batch label (free-form, e.g. `Batch1`, `Plate2`).
|
|
92
|
+
- Bio rep auto-derives from `(plate, well)` if not specified.
|
|
93
|
+
|
|
94
|
+
**Output**: `master.csv` (one row per well per DIV, with metric columns plus condition / bio_rep / tech_rep / batch columns) and a sibling `master.build.sh` containing the command for re-runs.
|
|
95
|
+
|
|
96
|
+
### Re-using a layout
|
|
97
|
+
|
|
98
|
+
Three ways to avoid retyping the layout for a follow-up build:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Option 1: re-run the auto-saved script.
|
|
102
|
+
bash master.build.sh
|
|
103
|
+
|
|
104
|
+
# Option 2: pull the layout from an existing master CSV.
|
|
105
|
+
mea-flow build "data_v2/" --fs-override 12500 --layout-from master.csv --out master_v2.csv
|
|
106
|
+
|
|
107
|
+
# Option 3: print the equivalent --well flags to stdout.
|
|
108
|
+
mea-flow show-layout master.csv
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Plot subcommands
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
mea-flow plot heatmap master.csv --metric mean_mfr_active_hz --div 21 --out figs/
|
|
117
|
+
mea-flow plot trajectory master.csv --metric mean_mfr_active_hz --out figs/
|
|
118
|
+
mea-flow plot timepoint master.csv --metric mean_mfr_active_hz --div 21 26 33 --out figs/
|
|
119
|
+
mea-flow plot pca master.csv --out figs/
|
|
120
|
+
mea-flow plot raster "recording.spk" --fs-override 12500 --wells A1 --out figs/
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Subcommand | Input | What it produces |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `heatmap` | master CSV | 4×6 plate grid, one panel per plate, coloured by metric. One PNG per (metric, DIV). |
|
|
126
|
+
| `trajectory` | master CSV | Mean ± SEM error-bars per condition across DIVs. One PNG per metric. |
|
|
127
|
+
| `timepoint` | master CSV | Violin and jitter per condition at one DIV, with user-selectable significance brackets. One PNG per (metric, DIV). |
|
|
128
|
+
| `pca` | master CSV | PCA scatter coloured by condition. One pooled PNG, or one per `--div`. Optional loadings figure. |
|
|
129
|
+
| `raster` | `.spk` file | Burst raster and ASDR histogram for each well. |
|
|
130
|
+
|
|
131
|
+
### Common plot flags
|
|
132
|
+
|
|
133
|
+
| Flag | Effect |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `--metric COL [COL ...]` | One or more metric columns. Omit to plot all numeric columns. |
|
|
136
|
+
| `--div N [N ...]` | Specific time points (timepoint, pca, heatmap). |
|
|
137
|
+
| `--div-min N --div-max N` | Filter the time range (trajectory, pca). |
|
|
138
|
+
| `--filter COL=VAL[,VAL...]` | Restrict the input to specific column values. Repeatable; multiple flags AND together. Example: `--filter condition=SCRM --filter DIV=14,28`. |
|
|
139
|
+
| `--group-order GROUP [GROUP ...]` | Explicit condition order (default: alphabetical). Listing a subset excludes other groups from the plot. |
|
|
140
|
+
| `--color GROUP=#HEX` | Colour per condition. Repeatable. Hex codes or matplotlib named colours both work. |
|
|
141
|
+
| `--pool` | Flatten bio/tech replicate hierarchy and treat every well as independent. Default is hierarchical (collapse tech reps within bio rep before stats). |
|
|
142
|
+
| `--figsize W H` | Figure size in inches. Default depends on the plot type. |
|
|
143
|
+
| `--out DIR` | Output directory (auto-created). |
|
|
144
|
+
|
|
145
|
+
### Flags specific to `plot timepoint` (violins)
|
|
146
|
+
|
|
147
|
+
| Flag | Effect |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `--test {tukey,mannwhitney,kruskal}` | Statistical test for the significance brackets. Default `tukey` (parametric all-pairs Tukey HSD). `mannwhitney` runs pairwise Mann-Whitney U with Bonferroni correction. `kruskal` runs Kruskal-Wallis omnibus followed by Dunn's pairwise post-hoc. The choice is yours; the package does not auto-select. |
|
|
150
|
+
| `--compare GROUP_A GROUP_B` | Restrict significance brackets to specific pairs. Repeatable. |
|
|
151
|
+
| `--point-hue COL` | Colour individual jitter points by another column (e.g. `batch`). |
|
|
152
|
+
| `--point-color VALUE=#HEX` | Per-value colour palette for `--point-hue`. Repeatable. |
|
|
153
|
+
| `--point-shape COL` | Use marker shape (in addition to or instead of colour) for individual jitter points. Default markers cycle circle, square, triangle, diamond, etc. |
|
|
154
|
+
| `--point-shape-map VALUE=MARKER` | Per-value marker for `--point-shape`. Repeatable. Markers can be matplotlib codes (`o`, `s`, `^`, ...) or aliases (`circle`, `square`, `triangle`, ...). |
|
|
155
|
+
| `--point-size N` | Marker area for jitter points. Default 40. |
|
|
156
|
+
| `--show-point-legend` | Show a legend mapping point colours to `--point-hue` values. Default hidden. |
|
|
157
|
+
|
|
158
|
+
### Flags specific to `plot raster`
|
|
159
|
+
|
|
160
|
+
| Flag | Effect |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `--asdr-bin S` | ASDR histogram bin width in seconds. Default 0.2. |
|
|
163
|
+
| `--time-start S --time-end S` | Restrict to a time window in seconds within the recording. Displayed times keep the original timestamps. |
|
|
164
|
+
| `--max-isi S --min-spikes N` | Burst-detection thresholds for the orange overlay rectangles. |
|
|
165
|
+
|
|
166
|
+
### Flags specific to `plot pca`
|
|
167
|
+
|
|
168
|
+
| Flag | Effect |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `--loadings` | Also save a per-feature PC loadings CSV and a horizontal bar chart of the top contributors to PC1 and PC2. |
|
|
171
|
+
| `--top N` | Number of top features to show in the loadings figure. Default 10. |
|
|
172
|
+
| `--point-shape COL --point-shape-map VALUE=MARKER` | Same as for `timepoint`, useful for indicating biological replicates by marker shape. |
|
|
173
|
+
|
|
174
|
+
Run `mea-flow plot <subcommand> --help` for the full per-subcommand option list.
|
|
175
|
+
|
|
176
|
+
### Example: a complete violin command
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
mea-flow plot timepoint master.csv \
|
|
180
|
+
--metric mean_mfr_active_hz burst_freq_avg network_burst_freq mean_sttc \
|
|
181
|
+
--div 21 26 33 \
|
|
182
|
+
--group-order SCRM LGI2_KD4 LGI2_KD5 \
|
|
183
|
+
--color SCRM=green --color LGI2_KD4=lightcoral --color LGI2_KD5=red \
|
|
184
|
+
--point-shape batch --point-shape-map Batch1=circle --point-shape-map Batch2=square --point-shape-map Batch3=triangle \
|
|
185
|
+
--compare LGI2_KD4 SCRM --compare LGI2_KD5 SCRM \
|
|
186
|
+
--test tukey \
|
|
187
|
+
--pool \
|
|
188
|
+
--out figs/timepoint
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Pretty axis labels
|
|
192
|
+
|
|
193
|
+
Axis labels and colour-bar titles render human-readable names (`Mean firing rate (Hz)` rather than `mean_mfr_active_hz`). The CLI flag values still use raw column names, which are easier to type.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Statistical analyses (`mea-flow stats`)
|
|
198
|
+
|
|
199
|
+
Beyond the brackets shown on violin plots, `mea-flow stats` writes a long-format CSV of pairwise condition-comparison results. Same data, same dispatcher as the violin brackets, just persisted as a tidy table for supplementary materials.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
mea-flow stats master.csv \
|
|
203
|
+
--metric mean_mfr_active_hz burst_freq_avg network_burst_freq mean_sttc \
|
|
204
|
+
--div 28 41 \
|
|
205
|
+
--compare LGI2_KD4 SCRM --compare LGI2_KD5 SCRM \
|
|
206
|
+
--test tukey \
|
|
207
|
+
--pool \
|
|
208
|
+
--out stats_summary.csv
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The output CSV has one row per (metric, time-point, pair) combination, with columns `metric`, `DIV`, `test`, `group_a`, `group_b`, `mean_diff`, `p_adj`, `significance`, `n_a`, `n_b`. Sort by metric and DIV in Excel for a clean supplementary table.
|
|
212
|
+
|
|
213
|
+
The same `--test` choice (`tukey`, `mannwhitney`, `kruskal`) applies. Significance labels (`*`, `**`, `***`, `ns`) match those used in the figures.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Single-recording commands
|
|
218
|
+
|
|
219
|
+
For ad-hoc inspection of one `.spk` file without going through `build`:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Quick per-well summary printed to the terminal (no files written)
|
|
223
|
+
mea-flow summary recording.spk --fs-override 12500
|
|
224
|
+
|
|
225
|
+
# Full pipeline: writes CSVs and figures to results/
|
|
226
|
+
mea-flow run recording.spk --out results/ --fs-override 12500
|
|
227
|
+
|
|
228
|
+
# Restrict to specific wells
|
|
229
|
+
mea-flow summary recording.spk --wells A1 B1 C1 --fs-override 12500
|
|
230
|
+
|
|
231
|
+
# Analyse only a time window
|
|
232
|
+
mea-flow run recording.spk --time-start 300 --time-end 600 --out results/ --fs-override 12500
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Python API
|
|
238
|
+
|
|
239
|
+
For programmatic use:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from py_mea_flow import MEAExperiment
|
|
243
|
+
|
|
244
|
+
exp = MEAExperiment(
|
|
245
|
+
"recording.spk",
|
|
246
|
+
metadata="plate_map.csv", # optional CSV with well_id, condition, DIV, replicate_id
|
|
247
|
+
fs_override=12500,
|
|
248
|
+
).run()
|
|
249
|
+
|
|
250
|
+
exp.spike_metrics # per-electrode metrics
|
|
251
|
+
exp.burst_table # one row per detected burst
|
|
252
|
+
exp.well_summary # per-well aggregate (27 metrics)
|
|
253
|
+
exp.to_csv("results.csv")
|
|
254
|
+
|
|
255
|
+
exp.plot_heatmap("A1")
|
|
256
|
+
exp.plot_raster("A1")
|
|
257
|
+
exp.plot_trajectory("mean_mfr_active_hz")
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The `py_mea_flow.stats` module exposes the same statistical functions used by the CLI:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from py_mea_flow.stats import (
|
|
264
|
+
pairwise_test, # unified dispatcher: tukey / mannwhitney / kruskal
|
|
265
|
+
tukey_hsd_pairwise, # Tukey HSD only
|
|
266
|
+
compare_conditions, # auto-dispatch MW (2 groups) or KW (3+ groups)
|
|
267
|
+
longitudinal_model, # linear mixed-effects with time x group interaction
|
|
268
|
+
compute_icc, # intraclass correlation
|
|
269
|
+
)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Note on Axion `.spk` files
|
|
275
|
+
|
|
276
|
+
Some recordings lack a `BlockVectorHeader` (firmware-dependent). When that happens, sampling-rate detection may guess wrong; pass `--fs-override` explicitly:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
mea-flow run recording.spk --fs-override 12500
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
12500 Hz is the standard rate for Axion CytoView 24-well plates.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Running the tests
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
pip install -e ".[dev]"
|
|
290
|
+
pytest
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
649 tests covering every module: binary parser, burst detection, network-burst detection, synchrony, statistical tests, every viz function, and every CLI subcommand.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Citing
|
|
298
|
+
|
|
299
|
+
If you use `py-mea-flow` in your research, please cite:
|
|
300
|
+
|
|
301
|
+
> [manuscript in preparation]
|
|
302
|
+
|
|
303
|
+
[](https://doi.org/10.5281/zenodo.19350375)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT, see [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Burst detection and burst-level metrics."""
|