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.
Files changed (47) hide show
  1. py_mea_flow-0.5.0/LICENSE +21 -0
  2. py_mea_flow-0.5.0/PKG-INFO +340 -0
  3. py_mea_flow-0.5.0/README.md +309 -0
  4. py_mea_flow-0.5.0/py_mea_flow/__init__.py +6 -0
  5. py_mea_flow-0.5.0/py_mea_flow/burst/__init__.py +1 -0
  6. py_mea_flow-0.5.0/py_mea_flow/burst/detection.py +367 -0
  7. py_mea_flow-0.5.0/py_mea_flow/burst/metrics.py +359 -0
  8. py_mea_flow-0.5.0/py_mea_flow/cli.py +2429 -0
  9. py_mea_flow-0.5.0/py_mea_flow/io/__init__.py +1 -0
  10. py_mea_flow-0.5.0/py_mea_flow/io/metadata.py +182 -0
  11. py_mea_flow-0.5.0/py_mea_flow/io/spk_reader.py +611 -0
  12. py_mea_flow-0.5.0/py_mea_flow/network/__init__.py +1 -0
  13. py_mea_flow-0.5.0/py_mea_flow/network/detection.py +367 -0
  14. py_mea_flow-0.5.0/py_mea_flow/network/metrics.py +184 -0
  15. py_mea_flow-0.5.0/py_mea_flow/network/synchrony.py +279 -0
  16. py_mea_flow-0.5.0/py_mea_flow/pipeline.py +1039 -0
  17. py_mea_flow-0.5.0/py_mea_flow/spike/__init__.py +1 -0
  18. py_mea_flow-0.5.0/py_mea_flow/spike/metrics.py +282 -0
  19. py_mea_flow-0.5.0/py_mea_flow/stats/__init__.py +19 -0
  20. py_mea_flow-0.5.0/py_mea_flow/stats/compare.py +752 -0
  21. py_mea_flow-0.5.0/py_mea_flow/viz/__init__.py +1 -0
  22. py_mea_flow-0.5.0/py_mea_flow/viz/burst_charts.py +280 -0
  23. py_mea_flow-0.5.0/py_mea_flow/viz/comparison.py +371 -0
  24. py_mea_flow-0.5.0/py_mea_flow/viz/heatmap.py +174 -0
  25. py_mea_flow-0.5.0/py_mea_flow/viz/network_plots.py +198 -0
  26. py_mea_flow-0.5.0/py_mea_flow/viz/pca.py +372 -0
  27. py_mea_flow-0.5.0/py_mea_flow/viz/plate.py +168 -0
  28. py_mea_flow-0.5.0/py_mea_flow/viz/trajectory.py +226 -0
  29. py_mea_flow-0.5.0/py_mea_flow.egg-info/PKG-INFO +340 -0
  30. py_mea_flow-0.5.0/py_mea_flow.egg-info/SOURCES.txt +45 -0
  31. py_mea_flow-0.5.0/py_mea_flow.egg-info/dependency_links.txt +1 -0
  32. py_mea_flow-0.5.0/py_mea_flow.egg-info/entry_points.txt +2 -0
  33. py_mea_flow-0.5.0/py_mea_flow.egg-info/requires.txt +18 -0
  34. py_mea_flow-0.5.0/py_mea_flow.egg-info/top_level.txt +1 -0
  35. py_mea_flow-0.5.0/pyproject.toml +46 -0
  36. py_mea_flow-0.5.0/setup.cfg +4 -0
  37. py_mea_flow-0.5.0/tests/test_burst_detection.py +308 -0
  38. py_mea_flow-0.5.0/tests/test_burst_metrics.py +237 -0
  39. py_mea_flow-0.5.0/tests/test_cli.py +1548 -0
  40. py_mea_flow-0.5.0/tests/test_metadata.py +210 -0
  41. py_mea_flow-0.5.0/tests/test_network_detection.py +294 -0
  42. py_mea_flow-0.5.0/tests/test_pipeline.py +383 -0
  43. py_mea_flow-0.5.0/tests/test_spike_metrics.py +267 -0
  44. py_mea_flow-0.5.0/tests/test_spk_reader.py +393 -0
  45. py_mea_flow-0.5.0/tests/test_stats.py +537 -0
  46. py_mea_flow-0.5.0/tests/test_synchrony.py +217 -0
  47. 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
+ [![PyPI version](https://img.shields.io/pypi/v/py-mea-flow.svg)](https://pypi.org/project/py-mea-flow/)
35
+ [![Python](https://img.shields.io/pypi/pyversions/py-mea-flow.svg)](https://pypi.org/project/py-mea-flow/)
36
+ [![GitHub](https://img.shields.io/badge/GitHub-py--mea--flow-blue?logo=github)](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
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19350375.svg)](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
+ [![PyPI version](https://img.shields.io/pypi/v/py-mea-flow.svg)](https://pypi.org/project/py-mea-flow/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/py-mea-flow.svg)](https://pypi.org/project/py-mea-flow/)
5
+ [![GitHub](https://img.shields.io/badge/GitHub-py--mea--flow-blue?logo=github)](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
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19350375.svg)](https://doi.org/10.5281/zenodo.19350375)
304
+
305
+ ---
306
+
307
+ ## License
308
+
309
+ MIT, see [LICENSE](LICENSE).
@@ -0,0 +1,6 @@
1
+ """py_mea_flow — end-to-end MEA data analysis for Axion Biosystems instruments."""
2
+
3
+ from py_mea_flow.pipeline import MEAExperiment
4
+
5
+ __version__ = "0.5.0"
6
+ __all__ = ["MEAExperiment"]
@@ -0,0 +1 @@
1
+ """Burst detection and burst-level metrics."""