Remote ARC/ BioInfo Repo Pulls/ MEA-seqX GitHub ↗ Paper (Adv. Sci. 2025) ↗

MEA-seqX

Emery, Hu, Klütsch et al. (Amin Lab, DZNE) — a computational framework pairing high-density microelectrode array (HD-MEA) electrophysiology with 10x Visium spatial transcriptomics on the same mouse hippocampal slices, to relate gene expression to network-wide electrical activity at cellular resolution. This page cross-checks the paper's 6-step pipeline against the vendored source; the code browser lets you read the actual implementation, and the runner executes the authors' own official demo dataset (fetched from their Zenodo records) through the vendored code, essentially unmodified — not a substitute built on other data.

Repo cloned main 1545932 Update README.md Runs the authors' own official demo dataset, unmodified vendored code
Run it → Browse the code → Read the paper →

What it relates

Spatial transcriptomics
10x Visium H&E, mouse hippocampal slice
Electrophysiology
3Brain HD-MEA recording, same slice
Output
Per-region correlation, XGBoost cross-prediction, joint NMF patterns

What the runner actually uses

This is the paper's own demo, not a substitute. An earlier version of this runner worked around missing data by building a stand-in LFP detector and a geometric reference-point placeholder on top of unrelated real recordings from elsewhere in this project. That version is gone. The README points to two Zenodo records; both are real, fetchable, and small enough to actually use once the giant raw FASTQ/voltage files in those records (tens of GB, never read by any MEA-seqX script) are skipped: Fetch with measeqx/bin/fetch_zenodo_sd.sh, build the fixture with measeqx/data/prepare_srt_fixture.py.
Steps 1 and 2 call the vendored methods directly. MEASeqX_Project.gene_expression() and Multiscale_Spatial_Alignment() are called exactly as the authors wrote them — same reference points (data/SD/SRT Reference Points.csv / nEphys Reference Points.csv, the authors' own human-curated landmarks), same cluster assignments (data/SD/Loupe Clusters.csv), same physical calibration constants. No glue code, no placeholder code — except one real algorithmic correction, disclosed in detail below, to the rotation step specifically.
A real bug in the rotation math, found by checking landmarks that should match and didn't. The registration fits a 2-point rigid transform: one landmark ("Distal CA1") pins translation, a second ("Proximal CA3") is meant to pin rotation. A correctly-fit 2-point transform makes both anchors land closely — that's the whole point of using two. The published code computed the rotation angle as the angle between the two landmarks' position vectors from the coordinate origin, not the angle of the line connecting them — those only coincide if the origin happens to sit in a comparable place relative to that line in both frames, which it doesn't. Verified on the real SD data: with the original code, Proximal CA3 — one of only two points the whole transform is fit from — landed 722µm from where it should, instead of near-zero. Fixed by measuring each frame's landmark-to-landmark line direction against a fixed axis instead of against the origin; same underlying angle function, corrected inputs. After the fix, Proximal CA3 lands at 0µm as it should, and the three landmarks never used to fit the transform (a genuine held-out check) mostly improved too. Full numbers and the exact code diff are in vendor/NOTICE.md.
Is this actually the same physical slice? Neither Zenodo record's metadata carries an explicit shared sample/slice ID linking L75027 to Phase_01_LFP_SD.bxr — they're linked only by the shared "SD" condition label. Checked the paper itself (Emery et al. 2025) rather than assume either way: its Experimental Section states n-Ephys recording and SRT processing are done sequentially on the same physical slice — "Immediately following n-Ephys recordings (10 min) and optical imaging (2 min), slices were embedded in..." for SRT — making cross-slice pairing structurally impossible by the authors' own protocol. The paper also states elsewhere that using separate slices per modality "would be suboptimal and fundamentally limited," producing only speculative, not measurable, relationships — i.e. the authors designed the method specifically to rule this out. Combined with Zenodo shipping exactly one SRT sample and one nEphys recording per condition (not a scattered multi-animal cohort), this is real, strong evidence for a matched representative demo pair, though not a metadata-level guarantee. If the electrode-cluster shape and the tissue photo's shape look different when you run it, that's the expected look of a coarse 64×64 electrode-grid mask next to an organic tissue photo, not evidence the two datasets are mismatched.
Six real bugs fixed to get this running on a modern stack. This is 2021-era code (Python 3.7, older numpy/matplotlib) that — going by what actually crashed on first run — had apparently never been executed against real data since: np.histogram(..., normed=False, ...) (removed from numpy), ChsGroups['Name'] never decoded from bytes before a string concatenation, a hardcoded LfpForms = None that crashed the very next line, np.int / plt.cm.get_cmap (both removed from their libraries), and a unit-mismatch bug where the real-tissue-image overlay coordinates subtracted an unscaled pixel offset from a scaled one — confirmed empirically when real spots plotted far outside the real tissue photo instead of on it. All are one-line fixes, documented inline where they're patched and in vendor/NOTICE.md — the underlying logic is untouched, and none of them touch the actual registration math (verified separately, see the run page's disclosure).
What's still ours, not the paper's: the cluster-level correlation plot on the run page. The paper's real Step 3 (SRT_nEphys Network Activity Features.py, ~2950 lines) computes a richer set of features and isn't wired into this runner — the browser is the way to read it. Everything feeding our correlation is still real, real-matched data; it's just a lighter aggregation than the paper's own.

Workflow — paper vs. code

1. Multiscale spatial alignment
Paper says
Automatic overlay of the SRT (10x Visium H&E) and nEphys (HD-MEA) slice images into a shared coordinate space, so each SRT spot can be matched to the nEphys electrode(s) beneath it despite the two being imaged on different microscopes at different resolutions.
Code does
Multiscale Spatial Alignment.py's MEASeqX_Project.read_related_files() loads spaceranger's filtered_feature_bc_matrix.h5 + scalefactors_json.json + tissue_positions_list.csv; a second method reads the .bxr file's 3BUserInfo/ChsGroups and 3BResults/3BInfo/MeaChs2ChIDsVector for electrode positions and cluster labels, then registers the two using hardcoded pixel-per-mm constants and reference-point CSVs.
2. SRT gene expression
Paper says
Preprocess, filter, normalize, and visualize expression for a supplied gene list across the aligned tissue clusters.
Code does
SRT Gene Expression.py wraps the h5 matrix in an AnnData object and calls scanpy.pp.normalize_total / scanpy.tl.dpt; plotting functions map normalized expression back onto the tissue clusters (DG, Hilus, CA3, CA1, EC, PC).
3. nEphys network activity features × gene expression
Paper says
Calculate network activity features (firing rate, LFP amplitude/duration, synchrony, frequency-band power) from the HD-MEA recording per electrode cluster, then correlate each against SRT gene expression in the same cluster.
Code does
SRT_nEphys Network Activity Features.py — the largest file in the repo (~2950 lines) — reads the .bxr recording, runs get_fft() and related feature extractors per cluster, then correlates results against the Step 2 expression values.
4. XGBoost prediction
Paper says
Use gradient-boosted trees to predict each nEphys network activity feature from SRT gene expression alone, testing whether transcription is predictive of function.
Code does
XGBoost Algorithm Prediction.py trains sklearn's GradientBoostingClassifier (despite the module's name, this is scikit-learn's GBM, not the xgboost package) per feature, with a train/test split via sklearn.model_selection.
Note: The paper and repo call this “XGBoost,” but the actual estimator imported is sklearn.ensemble.GradientBoostingClassifier — worth knowing if you go looking for the xgboost package itself in requirements.
5. nEphys network topological metrics × gene expression
Paper says
Build a functional connectivity graph over electrode clusters and compute standard network-topology metrics, again correlated against gene expression.
Code does
SRT_nEphys Network Topological Metrics.py builds a networkx graph from .bxr-derived cluster/channel groupings (get_Groupid_nEphys, get_Groupid_nEphys_hub) and computes degree/centrality/clustering metrics per cluster.
6. Non-negative matrix factorization
Paper says
Joint NMF across the combined SRT and nEphys feature matrices to identify shared spatiotemporal patterns that neither modality reveals alone.
Code does
Non‐Negative Matrix Factorization.py calls sklearn.decomposition.NMF over the concatenated feature set built by the earlier steps.