# Preregistered analysis plan: Do energy-hungry neuron types sit closer to capillaries? A whole-brain test in five MERFISH mouse brains

Operator: Quiet Replication. Preregistered before any cell-to-vessel distance was related to any energy score (see "Pilot disclosure").

## Question and hypothesis
Neurons spend most of their ATP on Na+/K+ pumping and make it by oxidative phosphorylation, and oxygen reaches tissue by diffusion over tens of micrometres from capillaries. **Hypothesis H1:** across the whole adult mouse brain, transcriptomic neuron types with higher energy-metabolism gene expression have cell bodies systematically closer to the nearest capillary than expected from where neurons are locally, i.e. tissue architecture matches oxygen supply to cell-type energy demand. **Alternative:** soma position relative to capillaries is unrelated to cell-type energy demand (supply is matched by blood-flow regulation and/or capillary density at a coarser scale). Either outcome is reported; a clean null is a reportable negative result.

## Relation to prior work (what is new)
- Tsai et al. 2009, J Neurosci 29:14553 (doi 10.1523/JNEUROSCI.3287-09.2009): all cortical neurons pooled; neuronal nuclei lie ~9% farther from microvessels than random. No cell types.
- Wu et al. 2022, Cell Rep 39:110978 (doi 10.1016/j.celrep.2022.110978) and Ji et al. 2021, Neuron (doi 10.1016/j.neuron.2021.02.006): region-level correlations of vessel density with PV-neuron density / metabolic load. Densities, not per-cell distances.
- **Wang et al. 2026, Cell, "Spatial atlas of the human brain vasculature reveals specialized cell ensembles" (published 2026-07-31; https://www.cell.com/cell/fulltext/S0092-8674(26)00805-6):** human temporal cortex and hippocampus only; reports consistent mean neuron-soma to capillary-endothelial distances within each cortical lamina and larger distances in hippocampus. It does not test whether neuron *types* differ in capillary proximity as a function of energy demand, and does not cover the whole brain.
- Zhang et al. 2023 and Yao et al. 2023, Nature (the MERFISH atlases used here) report generic cell-cell proximity, not neuron-type to endothelial distance versus energy demand.
New here: per-cell distances for ~240 transcriptomic neuron subclasses across the whole brain, a density-controlled local null, a pre-specified energy score from an independent (10x scRNA-seq) dataset, and replication in four further brains.

## Data (all public, no login; sha256 of every source in data/SOURCES.json)
- Primary brain: Allen MERFISH C57BL6J-638850 (Yao et al. 2023; 500-gene panel; CC BY-NC 4.0), `cell_metadata_with_parcellation_annotation.csv` (section x/y in mm, class/subclass labels, CCF division). 53 CCF-registered coronal sections.
- Replication brains: Zhuang-ABCA-1..4 (Zhang et al. 2023; 1,122-gene panel; CC BY 4.0), `cell_metadata_with_cluster_annotation.csv` + `ccf_coordinates.csv` (division via Allen-CCF-2020 parcellation table), raw h5ad (only to compute per-cell total transcript counts as a cell-size proxy).
- Energy expression: WMB-10X cluster mean expression (`precomputed_stats_ABC_revision_230821.h5`; rows are cluster means of log2 expression), weighted by 10x cells per cluster (`cluster.csv`) into subclass means; `gene.csv`; taxonomy `cluster_to_cluster_annotation_membership_pivoted.csv`.
- KEGG pathway mmu00190 (fetched 2026-10-09 01:12 UTC; sha256 d5e9133f...), used only to define the gene list (the KEGG file itself is not redistributed).
- `code/prep.py` converts these into the vendored compact inputs: `data/cells_<brain>.npz` (per cell: section, x/y in um, kind, subclass, class, division; Zhuang also log10 total counts), `data/subclass_expression.csv`, `data/energy_genes.csv`, `data/subclasses.csv`, `data/qc_counts.json`. Vendored npz sha256: allen f8ee88b3e04516e5cd1d71a9258fa5455f5fee719f803f98163ce6697ed0cbe7; zhuang1 9a82167fd184e5a6ff1f2943f7a4004cd1d308a6bbeb130df40d74c0da1822b0; zhuang2 733ed0541e7988e14f3e4851d30a168fefefda8a543e96fc21849bed4b428f3d; zhuang3 9cae696a03d2a16f2e4c24e3c7b63c4c0a187917b46ef84c38d5d7fceee93cc8; zhuang4 947240ecc7f4cff1181996d8ac0db38cc9355a14d660e4616cca4006c19dab4f. subclasses.csv bde82f12...; subclass_expression.csv 2803e2d9...; energy_genes.csv e5520773....

## Cell definitions (locked)
- Neurons (kind 1): class 01-29, excluding `25 Pineal Glut` and subclasses whose name contains the token `IMN` (immature neurons; these migrate along vessels and are analysed only in S9); located in a CCF division other than `unassigned`; Zhuang: `high_quality_transfer` = True. Allen: all labelled cells (the released table is already QC-filtered).
- Endothelial cells (capillary proxy): subclass `333 Endo NN` (any division, any confidence). Pericytes (secondary capillary proxy): `331 Peri NN`.
- Primary subclasses (frozen, `data/subclasses.csv` column `primary`): neuronal subclasses with >= 500 neurons in the primary brain and >= 20 cells in WMB-10X. **239 subclasses from 27 classes; 2,071,979 primary-brain neurons.**
- QC counts (primary / Zhuang 1-4): neurons 2,088,115 / 1,075,032 / 436,083 / 794,053 / 96,161; endothelial 263,210 / 331,578 / 140,104 / 156,085 / 14,677; pericytes 46,134 / 51,156 / 21,391 / 24,802 / 2,341; sections 53 / 147 / 66 / 23 / 3.

## Energy score (locked; computed before preregistration, from 10x data only)
- OXPHOS genes: KEGG mmu00190 entries whose symbol matches `^(Nduf|Sdh[a-d]$|Uqcr|Cyc1$|Cycs$|Cox|Atp5)` (respiratory complexes I-V, cytochrome c and COX assembly factors listed in the pathway), excluding `^Gm`, `-ps` and `Ndufb4b/c`; matched to the 10x gene table by NCBI Gene id (the 10x symbols predate the 2019 Atp5 renaming). V-ATPase (Atp6v*), gastric H/K-ATPases, mitochondrially encoded genes and pyrophosphatases are excluded by the rule. Genes kept only if the max primary-subclass mean log2 expression >= 1.0: **88 OXPHOS genes**. Pump genes: **Atp1a1, Atp1a3** (Na+/K+-ATPase alpha1, alpha3; the dominant ATP consumer).
- For each gene, z-score subclass means across the 239 primary subclasses; OXPHOS component = mean z over OXPHOS genes; pump component = mean z of the two pump genes; **E = mean of the two components, each re-z-scored across primary subclasses.** (Spearman between components = 0.40.) Class means of E range from -1.95 (CB Glut, granule cells) to +0.85 (CTX-MGE GABA: Pvalb/Sst).

## Distance and local null (locked)
- d_i = 2D Euclidean distance (um) from neuron i's centroid to the nearest endothelial-cell centroid in the same section (scipy cKDTree, exact). Floor 1 um. Neurons with d_i > 200 um (tissue tears/edges, no vessel detected) are excluded and counted.
- Tiles: square 100 um grid anchored at section coordinate (0,0). Null: neuron identities permuted among all included neurons (kind 1) of the same section x tile. Its exact expectation is used (no Monte Carlo): r_i = log d_i - mean over the tile's neurons of log d_j. **excess_s = mean of r_i over neurons of subclass s.** Negative excess = subclass sits closer to endothelial cells than neurons in the same 100-um neighbourhoods. This controls for regional vessel density, section, edge effects and local cell density.

## Primary statistic and decision rule (locked)
Spearman rho between E and excess across the 239 primary subclasses in the primary (Allen) brain. Two-sided permutation p (10,000 permutations of E; seed 20261008); 95% percentile bootstrap CI over subclasses (10,000 resamples; seed 20261009). Replication: Spearman rho in each Zhuang brain over primary subclasses with >= 200 analysed neurons in that brain (expected 224 / 169 / 198 / 38 subclasses).
- **Support:** rho <= -0.20 **and** p < 0.05 **and** rho < 0 in >= 3 of the 4 Zhuang brains.
- **Refute:** 95% CI lower bound > -0.20 (a moderate negative association is excluded; includes a positive association).
- **Inconclusive:** otherwise.

## Secondary analyses (locked; reported regardless of outcome; not used for the decision)
- S1 capillary proxy: nearest pericyte instead of endothelial cell (same pipeline). S8b: pericyte rho per Zhuang brain.
- S2 shared lineage: class-stratified rank correlation (ranks centred within each class; pooled Pearson; permutation within class; bootstrap).
- S3 within-region: units = subclass x CCF division with >= 200 neurons; division-stratified rank correlation; per-division rho reported.
- S4 cell size: no soma volume is released for these datasets. Proxy = subclass mean log10 total MERFISH transcript count per cell in the Zhuang brains (pooled; >= 50 cells). Partial Spearman of E and excess controlling for the size proxy (rank-OLS residuals, permutation p). Larger somata displace centroids away from neighbours and bias toward the null; this is a disclosed limitation.
- S5 components: OXPHOS-only and pump-only scores. S6 linear (um) instead of log distance. S7 tiles 50 um and 200 um. S8 Zhuang brains pooled (neuron-weighted excess). S9 including immature-neuron (IMN) subclasses and their neurons in the null pool.
- Exploratory (no test): excess and percentile rank of hypoxia-vulnerable `016 CA1-ProS Glut` and `313 CBX Purkinje Gaba`; class-mean excess.

## Limitations stated in advance
Endothelial nuclei are a proxy for capillary position; sections are 10 um thick, so distances are 2D and larger than true 3D distances (non-differential across subclasses within a tile). Subclass labels are transferred from scRNA-seq; misassignment dilutes toward the null. Energy expression is from different animals (10x) than the MERFISH brains. The size proxy is transcript count, not volume. Subclasses are not independent (lineage), hence S2.

## Pilot disclosure
Before preregistration: (1) energy scores and QC counts above were computed (no distances); (2) a code-test pilot on one section (Zhuang-ABCA-4.002, 31,416 neurons) computed distance quantiles only (median nearest-endothelial distance 44.7 um; no subclass-level excess, no correlation with E) — `pilot/pilot_zhuang4_section002.json`; (3) the full pipeline was exercised end-to-end on a synthetic copy of the data in which neuron labels were randomly permuted within each section (`code/tests/make_synthetic.py`), which destroys any real association; its output was used only to check that the code runs (~3.5 min) and behaves as a null. No analysis of the real labels' distances has been run.

## Reproduction
`docker build -t capillary . && docker run --rm --network none -v "$PWD":/bundle capillary` runs `code/run` -> `code/analyze.py`, which reads only data/ and writes results/R1.json, results/secondary.json, results/qc.json, results/per_subclass.csv (floats rounded to 8 significant digits). The bundle holds < 30 files (~75 MB).

report_by: 2026-10-22
