Chartrand et al. (2023): human against mouse L1 cells¶
Paper. Chartrand et al. (2023), Science 382, eadf0805,
doi:10.1126/science.adf0805; see
reproduce_chartrand_2023.ipynb for the text read, the human data and the table of all claims.
Data. Human cells from DANDI:000630 version 0.230915.2257, the dataset under test. Mouse cells from DANDI:000020 version 0.210913.1639, the outside input the claims file names (with that version) for the mouse comparison; it is the only published version of 000020. Mouse labels (t-type, layer, structure) and the mouse features the files do not give come from the paper's code at commit 7777857c1b89b19735e45fd9c9bd7493cc1d805c. Only the files of the paper's 272 strict mouse L1 cells are read.
The claims here use outside data (data: with_inputs) and are counted apart from the claims on
the dandiset alone. Features follow the claims file's O1 as in the human notebook: (a) computed
here where they agree with the paper's tables for both species (38 features), the paper's values
otherwise; (b) the paper's values. Two variants of (a) are run as in the human notebook: (a'), the
features extracted without the Methods' 500 ms rms noise criterion, and for fig3g (a, ratios),
with the adaptation ratios computed here.
| Claim | Status |
|---|---|
| mouse-cell-link (added link claim) | tested |
| fig3d-ephys-species | tested |
| fig3g-variability-dimensions | tested |
| fig4d-mouse-no-rosehip-ephys | tested |
| fig5d-mouse-pax6-doublets | tested |
| fig3e-tea-validation, fig3f-a-type-conductance, fig1e-subclass-proportions | blocked; what the mouse data hold for each is shown at the end |
import time
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf
from scipy import stats
from statsmodels.stats.anova import anova_lm
from statsmodels.stats.multitest import multipletests
import l1ephys as L
pd.set_option("display.width", 220)
pd.set_option("display.max_columns", 40)
pd.set_option("display.max_rows", 200)
warnings.filterwarnings("ignore")
started = time.time()
# Human cells (dandiset 000630), as in reproduce_chartrand_2023.ipynb
h_assets = L.list_assets()
h_feats = L.all_cell_features(h_assets, workers=12, slow_noise_variant=True)
labels = L.load_labels()
paper_h = L.load_paper_features()
print(f"human: dandiset {L.DANDISET_ID} version {L.DANDISET_VERSION}, {len(h_feats)} files read "
f"in {time.time() - started:.0f} s")
# Mouse cells (dandiset 000020), only the files of the paper's mouse L1 cells
mlabels = L.load_mouse_labels()
paper_m = L.load_mouse_paper_features()
m_meta = L.version_metadata(L.MOUSE_DANDISET_ID, L.MOUSE_DANDISET_VERSION)
m_assets_all = L.list_assets(L.MOUSE_DANDISET_ID, L.MOUSE_DANDISET_VERSION)
m_assets_all["session_id"] = pd.to_numeric(m_assets_all.path.str.extract(r"ses-(\d+)")[0])
wanted = mlabels[mlabels.in_strict_set].ephys_roi_id
m_assets = m_assets_all[m_assets_all.session_id.isin(wanted)]
print(f"mouse: dandiset {L.MOUSE_DANDISET_ID} version {L.MOUSE_DANDISET_VERSION} ({m_meta['name']!r}), "
f"{len(m_assets_all)} assets; files of the {len(wanted)} strict mouse L1 cells found: {len(m_assets)}")
t1 = time.time()
m_feats = L.all_cell_features(m_assets, workers=12, slow_noise_variant=True)
print(f"mouse features from {len(m_feats)} files in {time.time() - t1:.0f} s")
human: dandiset 000630 version 0.230915.2257, 210 files read in 441 s
mouse: dandiset 000020 version 0.210913.1639 ('Patch-seq recordings from mouse visual cortex'), 4435 assets; files of the 272 strict mouse L1 cells found: 250
mouse features from 250 files in 258 s
Data check¶
print("Mouse files read:", len(m_feats), "| errors:", int(m_feats.get("error", pd.Series(dtype=str)).notna().sum()))
print("Species:", m_feats.species.value_counts().to_dict(), "| institution:", m_feats.institution.value_counts().to_dict())
print("Subjects:", m_feats.subject_id.nunique(), "| sessions:", m_feats.session_id.nunique())
print("Sweeps used per file:", m_feats.n_sweeps_used.describe()[["min", "50%", "max"]].to_dict(),
"| zero-padded sweeps left out:", int(m_feats.n_sweeps_zero_padded.sum()))
print("Stimulus onset (s):", m_feats.stim_start_s.value_counts().to_dict(), "| duration (s):",
m_feats.stim_dur_s.round(3).value_counts().to_dict())
print("Clock check, median voltage change at the true onset and 0.3 s early (mV):",
round(m_feats.clock_dv_true_mv.median(), 2), round(m_feats.clock_dv_shifted_mv.median(), 2))
print("Strict mouse L1 cells in the paper's table:", int(mlabels.in_strict_set.sum()),
"| by structure:", mlabels[mlabels.in_strict_set].structure.str.extract(r"^([A-Za-z]+)")[0].value_counts().to_dict())
Mouse files read: 250 | errors: 0
Species: {'Mus musculus': 250} | institution: {'Allen Institute for Brain Science': 250}
Subjects: 141 | sessions: 250
Sweeps used per file: {'min': 6.0, '50%': 10.0, 'max': 44.0} | zero-padded sweeps left out: 276
Stimulus onset (s): {0.6: 131, 1.02: 119} | duration (s): {1.0: 250}
Clock check, median voltage change at the true onset and 0.3 s early (mV): -12.03 -0.01
Strict mouse L1 cells in the paper's table: 272 | by structure: {'VISp': 223, 'VISpm': 25, 'VISl': 15, 'VISpor': 3, 'VISli': 3, 'VISal': 2, 'VISpl': 1}
Mouse cells against the paper's mouse table (link claim mouse-cell-link)¶
The files of DANDI 000020 can be matched one to one to the paper's mouse L1 cells (mouse_l1_dataset_2023_02_06.csv), and the matched records agree on what both describe.
m_feats["session_id_int"] = m_feats.session_id.astype("int64")
by_roi = mlabels[mlabels.in_strict_set].reset_index().dropna(subset=["ephys_roi_id"]).astype({"ephys_roi_id": "int64"}).set_index("ephys_roi_id")
mlinked = m_feats.join(by_roi, on="session_id_int", rsuffix="_table")
print("Mouse files matched by session id:", int(mlinked.spec_id.notna().sum()), "of", len(mlinked),
"| distinct cells:", mlinked.spec_id.nunique())
print("Cell name in the file equal to the table's cell_name:", int((mlinked.cell_name == mlinked.cell_name_table).sum()))
missing = mlabels[mlabels.in_strict_set & ~mlabels.ephys_roi_id.isin(m_feats.session_id_int)]
print("Strict mouse cells without a file in 000020:", len(missing), missing.structure.value_counts().to_dict())
print(missing[["cell_name", "structure", "t-type", "ephys_roi_id"]].join(paper_m[["failed_qc"]]).to_string())
mcomputed = L.with_adapt_order(mlinked.set_index("spec_id"))
fcols = L.feature_columns(paper_m)
rows = []
for c in [c for c in fcols if c in mcomputed.columns]:
a, b = mcomputed[c].astype(float), paper_m[c].reindex(mcomputed.index).astype(float)
ok = a.notna() & b.notna()
rows.append({"feature": c, "n_both": int(ok.sum()),
"within_1pct": round((np.abs(a[ok] - b[ok]) <= 0.01 * np.abs(b[ok]) + 1e-9).mean(), 3)})
mcmp = pd.DataFrame(rows).set_index("feature")
print(mcmp.sort_values("within_1pct").to_string())
Mouse files matched by session id: 250 of 250 | distinct cells: 250
Cell name in the file equal to the table's cell_name: 250
Strict mouse cells without a file in 000020: 22 {'VISp1': 20, 'VISp2/3': 1, 'VISpl2/3': 1}
cell_name structure t-type ephys_roi_id failed_qc
spec_id
710346584 Slc32a1-IRES-Cre;Ai14-393924.04.02.01 VISp1 Lamp5 Krt73 710346512.0 False
650476171 Gad2-IRES-Cre;Ai14-362153.04.01.01 VISp2/3 Lamp5 Fam19a1 Pax6 650476141.0 False
730829986 Htr3a-Cre_NO152;Ai14-407127.03.01.03 VISp1 Lamp5 Ntn1 Npy2r 730829820.0 False
667492404 Ndnf-IRES2-dgCre;Ai14-377310.05.01.01 VISp1 Lamp5 Ntn1 Npy2r 667492389.0 False
867015583 Ndnf-IRES2-dgCre;Slc32a1-IRES2-FlpO;Ai65-461933.03.01.02 VISp1 Lamp5 Ntn1 Npy2r 867015537.0 True
680904066 Ndnf-IRES2-dgCre;Slc32a1-IRES2-FlpO;Ai65-381812.03.01.01 VISp1 Lamp5 Ntn1 Npy2r 680903817.0 True
668242473 Ndnf-IRES2-dgCre;Ai14-377316.03.01.01 VISp1 Lamp5 Plch2 Dock5 668242314.0 False
652958618 Ndnf-IRES2-dgCre;Ai14-363973.03.02.02 VISp1 Lamp5 Plch2 Dock5 652958600.0 False
667300994 Ndnf-IRES2-dgCre;Ai14-377309.06.02.01 VISp1 Lamp5 Plch2 Dock5 667300956.0 False
668423181 Ndnf-IRES2-dgCre;Ai14-377316.05.01.01 VISp1 Lamp5 Plch2 Dock5 668422888.0 False
659678793 Htr3a-Cre_NO152;Ai14-372795.04.01.01 VISp1 Lamp5 Plch2 Dock5 659678740.0 False
642488015 Gad2-IRES-Cre;Ai14-352686.05.02.02 VISp1 Lamp5 Lsp1 642487957.0 False
925444752 Sncg-IRES2-FlpO-neo;Ai65F-481162.04.01.01 VISp1 Sncg Vip Nptx2 925444519.0 False
992421687 Sncg-IRES2-FlpO-neo;Ai65F-499190.04.02.01 VISp1 Vip Col15a1 Pde1a 992421669.0 False
644857312 Ndnf-IRES2-dgCre;Ai14-355222.03.01.02 VISp1 Lamp5 Plch2 Dock5 644857295.0 False
652959132 Ndnf-IRES2-dgCre;Ai14-363973.03.02.03 VISp1 Lamp5 Plch2 Dock5 652959107.0 False
644976625 Ndnf-IRES2-dgCre;Ai14-355224.04.01.01 VISp1 Lamp5 Plch2 Dock5 644976497.0 False
653203017 Ndnf-IRES2-dgCre;Ai14-363969.04.02.02 VISp1 Lamp5 Plch2 Dock5 653203002.0 False
669522853 Ndnf-IRES2-dgCre;Slc32a1-IRES2-FlpO;Ai65-378110.04.02.02 VISp1 Lamp5 Plch2 Dock5 669522749.0 False
644935848 Ndnf-IRES2-dgCre;Ai14-355230.04.01.02 VISpl2/3 Lamp5 Lsp1 644935833.0 False
668426472 Ndnf-IRES2-dgCre;Ai14-377316.06.02.01 VISp1 Lamp5 Plch2 Dock5 668426447.0 False
671927927 Ndnf-IRES2-dgCre;Ai14-379873.03.02.01 VISp1 Lamp5 Plch2 Dock5 671927726.0 False
n_both within_1pct
feature
isi_adapt_ratio 244 0.041
width_adapt_ratio 244 0.102
downstroke_adapt_ratio 244 0.119
upstroke_adapt_ratio 244 0.148
threshold_v_adapt_ratio 244 0.168
peak_v_adapt_ratio 244 0.209
fi_fit_slope 250 0.580
input_resistance 250 0.876
tau 249 0.876
median_isi_hero 244 0.910
isi_cv_hero 244 0.910
adapt_hero 238 0.912
latency_hero 250 0.912
first_isi_inv_hero 244 0.914
mean_isi_hero 244 0.914
fast_trough_deltav_hero 250 0.916
upstroke_downstroke_ratio_hero 250 0.920
peak_v_hero 250 0.920
avg_rate_hero 250 0.920
downstroke_hero 250 0.920
upstroke_hero 250 0.920
trough_v_hero 250 0.928
width_hero 250 0.940
peak_deltav_hero 250 0.944
threshold_v_hero 250 0.944
latency_rheo 250 0.948
upstroke_downstroke_ratio_rheo 250 0.948
fast_trough_v_hero 250 0.948
fast_trough_deltav_rheo 250 0.948
upstroke_rheo 250 0.948
threshold_v_rheo 250 0.952
avg_rate_rheo 250 0.952
width_rheo 250 0.952
peak_v_rheo 250 0.952
peak_deltav_rheo 250 0.952
trough_v_rheo 250 0.956
downstroke_rheo 250 0.956
vm_for_sag 250 0.956
rheobase_i 250 0.956
sag 250 0.956
fast_trough_v_rheo 250 0.960
first_isi_inv_rheo 160 0.975
mean_isi_rheo 160 0.981
v_baseline 250 0.996
# The human tables, built as in reproduce_chartrand_2023.ipynb
h_feats["session_id_int"] = h_feats.session_id.astype("int64")
hl = h_feats.join(labels.reset_index().dropna(subset=["ephys_roi_id"]).astype({"ephys_roi_id": "int64"}).set_index("ephys_roi_id"), on="session_id_int", rsuffix="_table")
hcomputed = L.with_adapt_order(hl.set_index("spec_id"))
def agree(comp, pap):
out = []
for c in [c for c in fcols if c in comp.columns]:
a, b = comp[c].astype(float), pap[c].reindex(comp.index).astype(float)
ok = a.notna() & b.notna()
if ok.sum() and (np.abs(a[ok] - b[ok]) <= 0.01 * np.abs(b[ok]) + 1e-9).mean() >= 0.5:
out.append(c)
return out
H_COMP, M_COMP = agree(hcomputed, paper_h), agree(mcomputed, paper_m)
COMPUTED = sorted(set(H_COMP) & set(M_COMP))
RATIOS = [c for c in fcols if c.endswith("_adapt_ratio") and c not in COMPUTED and c in hcomputed and c in mcomputed]
print("Features computed here and used for both species:", len(COMPUTED), "| the others from the paper's tables")
print("Adaptation ratios computed here but not used in reading (a), used in the variant (a, ratios):", RATIOS)
# Variant (a'): the same features extracted without the Methods' 500 ms rms noise criterion
# (reproduce_chartrand_2023.ipynb, fig2c).
def no_slow(df):
return L.with_adapt_order(df[[c for c in df.columns if c.startswith("noslow__")]].rename(columns=lambda c: c[len("noslow__"):]))
hcomputed_ns, mcomputed_ns = no_slow(hl.set_index("spec_id")), no_slow(mlinked.set_index("spec_id"))
def build(kind):
if kind == "b":
hf, mf = L.apply_code_filters(paper_h), L.apply_code_filters(paper_m)
else:
hc, mc = (hcomputed_ns, mcomputed_ns) if kind == "a'" else (hcomputed, mcomputed)
cols = COMPUTED + RATIOS if kind == "a, ratios" else COMPUTED
hf = L.apply_code_filters(L.hybrid_table(hc, paper_h, cols))
mf = L.apply_code_filters(L.hybrid_table(mc, paper_m, cols))
H = hl.set_index("spec_id").drop(columns=[c for c in fcols if c in hl.columns]).join(hf[fcols])
H["homology_type"] = H["t-type"].map(L.HOMOLOGY)
H["failed_fx_long_squares"] = paper_h["failed_fx_long_squares"].reindex(H.index)
H["layer_depth_table"] = H.layer
H["layer"] = H.layer.fillna(H.layer_lims.astype("string").str.replace(".0", "", regex=False))
H["species"] = "human"
M = mlinked.set_index("spec_id").drop(columns=[c for c in fcols if c in mlinked.columns]).join(mf[fcols])
M["failed_qc"] = paper_m["failed_qc"].reindex(M.index)
M["vis"] = M.structure.str.contains("VIS")
M["visp"] = M.structure.str.match(r"^VISp(?!m)") # VISp, not VISpm
M["species"] = "mouse"
return H, M
HA, MA = build("a")
HB, MB = build("b")
HA2, MA2 = build("a'")
HAR, MAR = build("a, ratios")
# Variant of reading (b): all 272 strict mouse cells with the paper's values, the 22 without a
# file in 000020 included (labels and features from the paper's tables only).
MB272 = mlabels[mlabels.in_strict_set].drop(columns=[c for c in fcols if c in mlabels.columns]).join(L.apply_code_filters(paper_m)[fcols])
MB272["failed_qc"] = paper_m["failed_qc"].reindex(MB272.index)
MB272["vis"] = MB272.structure.str.contains("VIS")
MB272["visp"] = MB272.structure.str.match(r"^VISp(?!m)")
MB272["species"] = "mouse"
MB272["has_file"] = MB272.index.isin(MB.index)
print("Reading (b) over all strict mouse cells:", len(MB272), "| with a file:", int(MB272.has_file.sum()))
print("Human cells:", len(HA), "| mouse cells:", len(MA), "| mouse VIS with failed_qc False:",
int((MA.vis & (MA.failed_qc == False)).sum()))
print("Mouse cells by subclass (VIS, QC passed):", MA[MA.vis & (MA.failed_qc == False)].homology_type.value_counts().to_dict())
print("Mouse cells by subclass and layer_ccf:"); print(pd.crosstab(MA.homology_type.fillna("none"), MA.layer_ccf.fillna("NA")).to_string())
print("Mouse cells by area:", MA.structure.str.extract(r"^([A-Za-z]+)")[0].value_counts().to_dict())
Features computed here and used for both species:
38 | the others from the paper's tables Adaptation ratios computed here but not used in reading (a), used in the variant (a, ratios): ['isi_adapt_ratio', 'width_adapt_ratio', 'upstroke_adapt_ratio', 'downstroke_adapt_ratio', 'threshold_v_adapt_ratio', 'peak_v_adapt_ratio']
Reading (b) over all strict mouse cells: 272 | with a file: 250
Human cells: 210 | mouse cells: 250 | mouse VIS with failed_qc False: 235
Mouse cells by subclass (VIS, QC passed): {'LAMP5': 171, 'L1 VIP': 41, 'MC4R': 20, 'PAX6': 3}
Mouse cells by subclass and layer_ccf:
layer_ccf 1 2/3
homology_type
L1 VIP 19 22
LAMP5 157 27
MC4R 19 3
PAX6 2 1
Mouse cells by area: {'VISp': 202, 'VISpm': 25, 'VISl': 15, 'VISli': 3, 'VISpor': 3, 'VISal': 2}
Result: partially reproduced. All 250 files of 000020 that belong to the paper's strict mouse L1 cells match one cell each, by session id and by cell name, and their features agree with the paper's mouse table within 1% for 88 to 100% of cells for most features (the adaptation ratios and f-I slope agree less). 22 of the 272 strict mouse cells, 20 of them in VISp layer 1, have no file in this version of 000020 (listed above), so the mouse claims below use 250 cells, 235 of them passing QC; fig3d, fig4d and fig5d also show reading (b) over all 272 cells as a variant.
fig3d-ephys-species¶
Mouse L1 cells have less sag, lower spike amplitude and higher rheobase than human, across subclasses and within at least 2 of the 4 matched subclasses.
As l1_cross_species.ipynb cells 5, 25 and 38: human AIBS cells with long square features and
soma in L1 (the depth table's layer, filled from the LIMS layer where missing, as that notebook's
cell 5 does), mouse VISp cells with layer_ccf 1 and failed_qc False, as the claims file says
(the code's cell 5 takes every visual area, VIS, shown as a variant with the human layer not
filled), both in the four core subclasses; features more than 80% non-missing; a
two-way ANOVA of species and subclass with interaction, species entered first; Benjamini-Hochberg
across features; for features with an interaction at FDR p < 0.05, two-sided Mann-Whitney within
each subclass. O2 readings: (a) ranks, Type II, HC3; (b) raw values, Type I, as the code calls
anova_lm (the HC3 fit does not change anova_lm without its robust option). AP height at the
ramp (peak_deltav_ramp) is not computed here and comes from the paper's tables.
def species_stats(H, M, rank, typ, robust, area="visp", fill_layer=True):
layer = H.layer if fill_layer else H.layer_depth_table
comb = pd.concat([H[(H.collaborator == "AIBS") & (H.failed_fx_long_squares == False) & (layer == "1")],
M[M[area] & (M.layer_ccf == "1") & (M.failed_qc == False)]], sort=False)
comb = comb[comb.homology_type.isin(L.SUBCLASSES)].copy()
data = comb[comb[fcols].notna().sum(axis=1) > 0]
feats80 = [c for c in fcols if data[c].notna().mean() > 0.8]
recs = []
for f in feats80:
# A subclass with fewer than 2 cells of either species with a value is left out for that
# feature (with VISp alone the one mouse PAX6 cell makes the HC3 errors undefined).
d = data.dropna(subset=[f])
n_sp = d.groupby(["homology_type", "species"]).size().unstack().reindex(columns=["human", "mouse"]).fillna(0)
keep = n_sp.index[(n_sp >= 2).all(axis=1)]
d = d[d.homology_type.isin(keep)].copy()
if rank:
d[f] = d[f].rank()
fit = smf.ols(f"{f} ~ species * homology_type", data=d).fit(cov_type="HC3")
tab = anova_lm(fit, typ=typ, robust=("hc3" if robust else None))
recs.append({"feature": f, "p_species": tab.loc["species", "PR(>F)"],
"p_inter": tab.loc["species:homology_type", "PR(>F)"], "subclasses": len(keep)})
res = pd.DataFrame(recs).set_index("feature")
res["p_species_fdr"] = multipletests(res.p_species.fillna(1), method="fdr_bh")[1]
res["p_inter_fdr"] = multipletests(res.p_inter.fillna(1), method="fdr_bh")[1]
return comb, res
target = {"sag": "lower", "peak_deltav_ramp": "lower", "rheobase_i": "higher"}
for kind, H, M in [("a", HA, MA), ("a'", HA2, MA2), ("b", HB, MB)]:
for name, rank, typ, robust in [("O2 (a): ranks, Type II, HC3", True, 2, True), ("O2 (b): raw, Type I", False, 1, False)]:
comb, res = species_stats(H, M, rank, typ, robust)
print(f"features ({kind}), {name}: features with a subclass left out {int((res.subclasses < 4).sum())}; n human {int((comb.species == 'human').sum())}, mouse {int((comb.species == 'mouse').sum())}, "
f"{len(res)} features, species FDR p < 1e-38 for {int((res.p_species_fdr < 1e-38).sum())}")
for f, direction in target.items():
med = comb.groupby("species")[f].median()
sub = {}
for g in L.SUBCLASSES:
d = comb[comb.homology_type == g].dropna(subset=[f])
x, y = d[d.species == "mouse"][f], d[d.species == "human"][f]
if len(x) and len(y):
p = stats.mannwhitneyu(x, y).pvalue
ok = (x.median() < y.median()) if direction == "lower" else (x.median() > y.median())
sub[g] = f"{p:.2g}{'' if ok else ' (wrong way)'}"
print(f" {f}: mouse median {med['mouse']:.3g} vs human {med['human']:.3g} (mouse {direction}: "
f"{(med['mouse'] < med['human']) if direction == 'lower' else (med['mouse'] > med['human'])}); "
f"species FDR p {res.loc[f, 'p_species_fdr']:.2g}; interaction FDR p {res.loc[f, 'p_inter_fdr']:.2g}; "
f"within-subclass MW p {sub}")
print("Cells by species and subclass:"); print(pd.crosstab(comb.homology_type, comb.species).to_string())
print("\nVariants: species FDR p of the three features, and whether each is in the stated direction")
for area, fill, mouse_sets in [("vis", True, None), ("visp", False, None), ("vis", False, None), ("visp", True, "272"), ("vis", True, "272")]:
for kind, H, M in ([("a", HA, MA), ("b", HB, MB)] if mouse_sets is None else [("b, all 272 strict mouse cells", HB, MB272)]):
for name, rank, typ, robust in [("O2 (a)", True, 2, True), ("O2 (b)", False, 1, False)]:
comb, res = species_stats(H, M, rank, typ, robust, area, fill)
med = comb.groupby("species")[list(target)].median()
dirs = all((med.loc["mouse", f] < med.loc["human", f]) if d == "lower" else (med.loc["mouse", f] > med.loc["human", f]) for f, d in target.items())
print(f" mouse {area.upper()}, human layer {'filled' if fill else 'not filled'}, features ({kind}), {name}: n human "
f"{int((comb.species == 'human').sum())}, mouse {int((comb.species == 'mouse').sum())}; "
+ ", ".join(f"{f} {res.loc[f, 'p_species_fdr']:.2g}" for f in target) + f"; directions hold: {dirs}")
features (a), O2 (a): ranks, Type II, HC3: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 5
sag: mouse median 0.0477 vs human 0.136 (mouse lower: True); species FDR p 9.5e-36; interaction FDR p 0.74; within-subclass MW p {'LAMP5': '2.4e-23', 'MC4R': '1.9e-06', 'PAX6': '0.85 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.4e-33; interaction FDR p 0.0031; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 2e-69; interaction FDR p 3.3e-09; within-subclass MW p {'LAMP5': '7.5e-34', 'MC4R': '1e-07', 'PAX6': '0.092', 'L1 VIP': '7.5e-05'}
features (a), O2 (b): raw, Type I: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 5
sag: mouse median 0.0477 vs human 0.136 (mouse lower: True); species FDR p 4.1e-48; interaction FDR p 5e-09; within-subclass MW p {'LAMP5': '2.4e-23', 'MC4R': '1.9e-06', 'PAX6': '0.85 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.3e-34; interaction FDR p 0.0015; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 8.1e-67; interaction FDR p 2.5e-11; within-subclass MW p {'LAMP5': '7.5e-34', 'MC4R': '1e-07', 'PAX6': '0.092', 'L1 VIP': '7.5e-05'}
features (a'), O2 (a): ranks, Type II, HC3: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 5
sag: mouse median 0.0477 vs human 0.134 (mouse lower: True); species FDR p 3.1e-36; interaction FDR p 0.78; within-subclass MW p {'LAMP5': '1.3e-23', 'MC4R': '1.6e-06', 'PAX6': '0.79 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.4e-33; interaction FDR p 0.0031; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 1.6e-70; interaction FDR p 4.5e-09; within-subclass MW p {'LAMP5': '3.8e-34', 'MC4R': '1e-07', 'PAX6': '0.09', 'L1 VIP': '7.5e-05'}
features (a'), O2 (b): raw, Type I: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 5
sag: mouse median 0.0477 vs human 0.134 (mouse lower: True); species FDR p 1.8e-48; interaction FDR p 6e-09; within-subclass MW p {'LAMP5': '1.3e-23', 'MC4R': '1.6e-06', 'PAX6': '0.79 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.3e-34; interaction FDR p 0.0015; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 1.4e-67; interaction FDR p 2e-11; within-subclass MW p {'LAMP5': '3.8e-34', 'MC4R': '1e-07', 'PAX6': '0.09', 'L1 VIP': '7.5e-05'}
features (b), O2 (a): ranks, Type II, HC3: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 5
sag: mouse median 0.0475 vs human 0.131 (mouse lower: True); species FDR p 7.6e-37; interaction FDR p 0.79; within-subclass MW p {'LAMP5': '1.4e-23', 'MC4R': '8e-07', 'PAX6': '0.85 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.4e-33; interaction FDR p 0.0031; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 1.5e-70; interaction FDR p 5.6e-08; within-subclass MW p {'LAMP5': '3.4e-34', 'MC4R': '1e-07', 'PAX6': '0.09', 'L1 VIP': '7.5e-05'}
features (b), O2 (b): raw, Type I: features with a subclass left out 80; n human 176, mouse 150, 80 features, species FDR p < 1e-38 for 6
sag: mouse median 0.0475 vs human 0.131 (mouse lower: True); species FDR p 5.4e-50; interaction FDR p 1e-10; within-subclass MW p {'LAMP5': '1.4e-23', 'MC4R': '8e-07', 'PAX6': '0.85 (wrong way)', 'L1 VIP': '6e-05'}
peak_deltav_ramp: mouse median 53.8 vs human 76.1 (mouse lower: True); species FDR p 3.3e-34; interaction FDR p 0.0015; within-subclass MW p {'LAMP5': '3.2e-23', 'MC4R': '0.0012', 'PAX6': '0.12', 'L1 VIP': '0.055'}
rheobase_i: mouse median 140 vs human 30 (mouse higher: True); species FDR p 7e-68; interaction FDR p 5.9e-11; within-subclass MW p {'LAMP5': '3.4e-34', 'MC4R': '1e-07', 'PAX6': '0.09', 'L1 VIP': '7.5e-05'}
Cells by species and subclass:
species human mouse
homology_type
L1 VIP 15 16
LAMP5 95 120
MC4R 34 13
PAX6 32 1
Variants: species FDR p of the three features, and whether each is in the stated direction
mouse VIS, human layer filled, features (a), O2 (a): n human 176, mouse 185; sag 3.7e-39, peak_deltav_ramp 2.6e-38, rheobase_i 1e-78; directions hold: True
mouse VIS, human layer filled, features (a), O2 (b): n human 176, mouse 185; sag 9.5e-45, peak_deltav_ramp 1.4e-43, rheobase_i 2.6e-83; directions hold: True
mouse VIS, human layer filled, features (b), O2 (a): n human 176, mouse 185; sag 3.2e-40, peak_deltav_ramp 2.6e-38, rheobase_i 2.4e-80; directions hold: True
mouse VIS, human layer filled, features (b), O2 (b): n human 176, mouse 185; sag 2.5e-46, peak_deltav_ramp 1.4e-43, rheobase_i 1.5e-85; directions hold: True
mouse VISP, human layer not filled, features (a), O2 (a): n human 164, mouse 150; sag 5.7e-35, peak_deltav_ramp 9.3e-32, rheobase_i 3.4e-67; directions hold: True
mouse VISP, human layer not filled, features (a), O2 (b): n human 164, mouse 150; sag 9.1e-49, peak_deltav_ramp 3.7e-33, rheobase_i 5.7e-64; directions hold: True
mouse VISP, human layer not filled, features (b), O2 (a): n human 164, mouse 150; sag 1.3e-36, peak_deltav_ramp 9.3e-32, rheobase_i 1.7e-68; directions hold: True
mouse VISP, human layer not filled, features (b), O2 (b): n human 164, mouse 150; sag 2.7e-50, peak_deltav_ramp 3.7e-33, rheobase_i 5.2e-65; directions hold: True
mouse VIS, human layer not filled, features (a), O2 (a): n human 164, mouse 185; sag 2.1e-38, peak_deltav_ramp 1.1e-36, rheobase_i 1.6e-76; directions hold: True
mouse VIS, human layer not filled, features (a), O2 (b): n human 164, mouse 185; sag 2e-44, peak_deltav_ramp 1.3e-42, rheobase_i 1.6e-80; directions hold: True
mouse VIS, human layer not filled, features (b), O2 (a): n human 164, mouse 185; sag 3.7e-40, peak_deltav_ramp 1.1e-36, rheobase_i 2.5e-78; directions hold: True
mouse VIS, human layer not filled, features (b), O2 (b): n human 164, mouse 185; sag 5.9e-46, peak_deltav_ramp 1.3e-42, rheobase_i 9.9e-83; directions hold: True
mouse VISP, human layer filled, features (b, all 272 strict mouse cells), O2 (a): n human 176, mouse 168; sag 2.7e-36, peak_deltav_ramp 4.6e-43, rheobase_i 4.7e-79; directions hold: True
mouse VISP, human layer filled, features (b, all 272 strict mouse cells), O2 (b): n human 176, mouse 168; sag 3e-43, peak_deltav_ramp 1.9e-39, rheobase_i 3.1e-82; directions hold: True
mouse VIS, human layer filled, features (b, all 272 strict mouse cells), O2 (a): n human 176, mouse 203; sag 3.1e-38, peak_deltav_ramp 3.1e-38, rheobase_i 1.5e-83; directions hold: True
mouse VIS, human layer filled, features (b, all 272 strict mouse cells), O2 (b): n human 176, mouse 203; sag 2.7e-47, peak_deltav_ramp 6.1e-44, rheobase_i 2e-86; directions hold: True
Result: partially reproduced. On the cells the claims file names (mouse VISp, 150 cells; human, 176 cells) all three features are in the stated direction (mouse sag 0.048 against 0.136 in human, AP height at the ramp 54 against 76 mV, rheobase 140 against 30 pA), and for each feature with an interaction at least 2 of the 4 subclasses differ at p < 0.05 the same way (LAMP5 and MC4R for all three, L1 VIP for sag and rheobase). AP height has species FDR p 3.4e-33 under O2 reading (a) and 3.3e-34 under (b), above 1e-38 under both, and sag 9.5e-36 under (a); so the two readings agree on partially reproduced. The one mouse PAX6 cell in VISp leaves PAX6 out of the ANOVA. Under the code's choice of every visual area (VIS, 185 mouse cells) the readings disagree as in the first run (AP height 2.6e-38 under (a), 1.4e-43 under (b)), and with the 22 cells missing from 000020 added from the paper's table (168 VISp cells) they also disagree (sag 2.7e-36 under (a), all three below 1e-38 under (b)). The missing cells lower the power of the test here. Variant (a') gives the same as (a) on VISp (AP height 3.4e-33 and 3.3e-34, sag 3.1e-36 under O2 (a)).
fig3g-variability-dimensions¶
Human and mouse L1 subclasses have a similar amount of morpho-electric variability but along different features; sag and spike shape adaptation vary in human but little in mouse, while ISI adaptation and AHP vary in mouse.
As l1_subclass_distinctness.ipynb cells 10 and 37: human, the set of fig2c-subclass-ephys-differences; mouse, VISp cells of the strict mouse set with a subclass, as the claims file says (every visual area, VIS, as the code's mouse set has it, is a variant), features more than 40% non-missing; Kruskal-Wallis per feature, epsilon2 = H/(n-1), Benjamini-Hochberg.
isi_f = ["isi_adapt_ratio", "adapt_mean", "adapt_hero"]
ahp_f = ["fast_trough_deltav_rheo", "fast_trough_deltav_hero", "trough_slowdeltav_rheo", "trough_slowdeltav_hero", "ahp_delay_ratio_hero"]
for kind, H, M, area in [("a", HA, MA, "visp"), ("a'", HA2, MA2, "visp"), ("a, ratios", HAR, MAR, "visp"), ("b", HB, MB, "visp"), ("a", HA, MA, "vis"), ("b", HB, MB, "vis")]:
hP = H[H.in_strict_set & (H.collaborator == "AIBS") & (H.failed_fx_long_squares == False)]
h40 = [c for c in fcols if hP[hP.homology_type.notna()][c].notna().mean() > 0.4]
hs = hP[hP.homology_type.isin(L.SUBCLASSES)].copy()
hs["homology_type"] = pd.Categorical(hs.homology_type, categories=L.SUBCLASSES)
hres, _ = L.run_kw_dunn(hs, h40, "homology_type", posthoc=None)
mv = M[M[area] & (M[fcols].notna().sum(axis=1) > 0)]
m40 = [c for c in fcols if mv[c].notna().mean() > 0.4]
ms = mv[mv.homology_type.notna()].copy()
ms["homology_type"] = pd.Categorical(ms.homology_type, categories=L.SUBCLASSES)
mres, _ = L.run_kw_dunn(ms, m40, "homology_type", posthoc=None)
both = hres[["epsilon2", "pval_fdr"]].join(mres[["epsilon2", "pval_fdr"]], lsuffix="_human", rsuffix="_mouse", how="outer")
print(f"features ({kind}), mouse {area.upper()}: human {len(hs)} cells, {len(h40)} features; mouse {len(ms)} cells {ms.homology_type.value_counts(sort=False).to_dict()}, {len(m40)} features")
print(both.loc[[f for f in ["sag", "upstroke_adapt_ratio"] + isi_f + ahp_f if f in both.index]].round(4).to_string())
i = all(both.loc[f, "pval_fdr_human"] < 0.05 and both.loc[f, "epsilon2_mouse"] < both.loc[f, "epsilon2_human"] for f in ["sag", "upstroke_adapt_ratio"])
def mouse_more(fs):
return [f for f in fs if f in both.index and both.loc[f, "pval_fdr_mouse"] < 0.05 and both.loc[f, "epsilon2_mouse"] > both.loc[f, "epsilon2_human"]]
print(f" (i) sag and upstroke adaptation vary in human and less in mouse: {i}")
print(f" (ii) ISI adaptation features varying more in mouse: {mouse_more(isi_f)}; AHP features: {mouse_more(ahp_f)}")
nh, nm = int((hres.pval_fdr < 0.05).sum()), int((mres.pval_fdr < 0.05).sum())
eh, em = hres.loc[hres.pval_fdr < 0.05, "epsilon2"].mean(), mres.loc[mres.pval_fdr < 0.05, "epsilon2"].mean()
print(f" amount (reported, not part of the outcome): FDR-significant features human {nh}, mouse {nm}; their mean epsilon2 human {eh:.3f}, mouse {em:.3f}")
features (a), mouse VISP: human 179 cells, 92 features; mouse 205 cells {'LAMP5': 151, 'MC4R': 18, 'PAX6': 1, 'L1 VIP': 35}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5706 0.0000 0.2202 0.0000
upstroke_adapt_ratio 0.4584 0.0000 0.1703 0.0000
isi_adapt_ratio 0.0495 0.0539 0.3915 0.0000
adapt_mean 0.0287 0.1989 0.4058 0.0000
adapt_hero 0.0450 0.0721 0.3925 0.0000
fast_trough_deltav_rheo 0.1706 0.0000 0.3346 0.0000
fast_trough_deltav_hero 0.2524 0.0000 0.3307 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0393 0.0505
trough_slowdeltav_hero 0.0510 0.0474 0.3981 0.0000
ahp_delay_ratio_hero 0.0529 0.0440 0.0230 0.1062
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 56, mouse 73; their mean epsilon2 human 0.171, mouse 0.219
features (a'), mouse VISP: human 179 cells, 92 features; mouse 205 cells {'LAMP5': 151, 'MC4R': 18, 'PAX6': 1, 'L1 VIP': 35}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5785 0.0000 0.2191 0.0000
upstroke_adapt_ratio 0.4584 0.0000 0.1703 0.0000
isi_adapt_ratio 0.0495 0.0539 0.3915 0.0000
adapt_mean 0.0287 0.1989 0.4058 0.0000
adapt_hero 0.0338 0.1459 0.3925 0.0000
fast_trough_deltav_rheo 0.1652 0.0000 0.3346 0.0000
fast_trough_deltav_hero 0.2618 0.0000 0.3307 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0393 0.0505
trough_slowdeltav_hero 0.0510 0.0483 0.3981 0.0000
ahp_delay_ratio_hero 0.0529 0.0448 0.0230 0.1062
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 56, mouse 73; their mean epsilon2 human 0.176, mouse 0.219
features (a, ratios), mouse VISP: human 179 cells, 92 features; mouse 205 cells {'LAMP5': 151, 'MC4R': 18, 'PAX6': 1, 'L1 VIP': 35}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5706 0.0000 0.2202 0.0000
upstroke_adapt_ratio 0.4252 0.0000 0.1811 0.0000
isi_adapt_ratio 0.0646 0.0189 0.3780 0.0000
adapt_mean 0.0287 0.1989 0.4058 0.0000
adapt_hero 0.0450 0.0721 0.3925 0.0000
fast_trough_deltav_rheo 0.1706 0.0000 0.3346 0.0000
fast_trough_deltav_hero 0.2524 0.0000 0.3307 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0393 0.0499
trough_slowdeltav_hero 0.0510 0.0466 0.3981 0.0000
ahp_delay_ratio_hero 0.0529 0.0431 0.0230 0.1048
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 57, mouse 75; their mean epsilon2 human 0.168, mouse 0.215
features (b), mouse VISP: human 179 cells, 92 features; mouse 205 cells {'LAMP5': 151, 'MC4R': 18, 'PAX6': 1, 'L1 VIP': 35}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5758 0.0000 0.2215 0.0000
upstroke_adapt_ratio 0.4584 0.0000 0.1703 0.0000
isi_adapt_ratio 0.0495 0.0539 0.3915 0.0000
adapt_mean 0.0287 0.1989 0.4058 0.0000
adapt_hero 0.0221 0.3166 0.3821 0.0000
fast_trough_deltav_rheo 0.1638 0.0000 0.3326 0.0000
fast_trough_deltav_hero 0.2703 0.0000 0.3124 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0393 0.0505
trough_slowdeltav_hero 0.0510 0.0474 0.3981 0.0000
ahp_delay_ratio_hero 0.0529 0.0431 0.0230 0.1075
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 56, mouse 73; their mean epsilon2 human 0.173, mouse 0.220
features (a), mouse VIS: human 179 cells, 92 features; mouse 250 cells {'LAMP5': 184, 'MC4R': 22, 'PAX6': 3, 'L1 VIP': 41}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5706 0.0000 0.2426 0.0000
upstroke_adapt_ratio 0.4584 0.0000 0.1646 0.0000
isi_adapt_ratio 0.0495 0.0539 0.3847 0.0000
adapt_mean 0.0287 0.1989 0.4043 0.0000
adapt_hero 0.0450 0.0721 0.3890 0.0000
fast_trough_deltav_rheo 0.1706 0.0000 0.3470 0.0000
fast_trough_deltav_hero 0.2524 0.0000 0.3576 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0599 0.0022
trough_slowdeltav_hero 0.0510 0.0474 0.3796 0.0000
ahp_delay_ratio_hero 0.0529 0.0440 0.0136 0.3461
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 56, mouse 77; their mean epsilon2 human 0.171, mouse 0.208
features (b), mouse VIS: human 179 cells, 92 features; mouse 250 cells {'LAMP5': 184, 'MC4R': 22, 'PAX6': 3, 'L1 VIP': 41}, 82 features
epsilon2_human pval_fdr_human epsilon2_mouse pval_fdr_mouse
feature
sag 0.5758 0.0000 0.2430 0.0000
upstroke_adapt_ratio 0.4584 0.0000 0.1646 0.0000
isi_adapt_ratio 0.0495 0.0539 0.3847 0.0000
adapt_mean 0.0287 0.1989 0.4043 0.0000
adapt_hero 0.0221 0.3166 0.3786 0.0000
fast_trough_deltav_rheo 0.1638 0.0000 0.3457 0.0000
fast_trough_deltav_hero 0.2703 0.0000 0.3453 0.0000
trough_slowdeltav_rheo 0.0871 0.0031 0.0599 0.0021
trough_slowdeltav_hero 0.0510 0.0474 0.3796 0.0000
ahp_delay_ratio_hero 0.0529 0.0431 0.0136 0.3461
(i) sag and upstroke adaptation vary in human and less in mouse: True
(ii) ISI adaptation features varying more in mouse: ['isi_adapt_ratio', 'adapt_mean', 'adapt_hero']; AHP features: ['fast_trough_deltav_rheo', 'fast_trough_deltav_hero', 'trough_slowdeltav_hero']
amount (reported, not part of the outcome): FDR-significant features human 56, mouse 77; their mean epsilon2 human 0.173, mouse 0.209
Result: reproduced. On mouse VISp (205 cells) and under both feature readings, sag and the upstroke adaptation ratio differ across human subclasses (FDR p < 1e-4) with epsilon2 0.57 and 0.46, against 0.22 and 0.17 in mouse. In mouse the ISI adaptation features (isi_adapt_ratio, adapt_mean, adapt_hero; epsilon2 0.38 to 0.41) and AHP features (fast_trough_deltav_rheo and _hero, trough_slowdeltav_hero; 0.31 to 0.40) differ with FDR p < 1e-4 and larger epsilon2 than in human (0.02 to 0.27). The same holds with every visual area (VIS, 250 cells), in variant (a'), and with the adaptation ratios computed here (upstroke adaptation ratio epsilon2 0.43 in human against 0.18 in mouse). The amount, reported apart, is 56 FDR-significant features in human and 73 in mouse VISp (77 in VIS), with mean epsilon2 0.17 and 0.22.
fig4d-mouse-no-rosehip-ephys¶
The mouse MC4R subclass has moderate sag but no irregular spiking; irregular spiking occurs only in a subset of mouse LAMP5 cells (mainly Lamp5 Ntn1 Npy2r) without other rosehip features.
As l1_rosehip.ipynb cells 4 and 36: mouse cells of the strict set with primary_ephys (VIS,
failed_qc False), sag above 0.5 set missing; Dunn's tests over all subclass pairs; irregular is
ir_late_mean above 0.4 (cells 39 and 42). ir_late_mean comes from the paper's table (O1). Reading (b) over all 272 strict mouse cells,
the 22 without a file included, and cuts of 0.3 and 0.5 are variants.
from itertools import combinations
for kind, M in [("a", MA), ("a'", MA2), ("b", MB), ("b, all 272 strict cells", MB272)]:
m = M[M.vis & (M.failed_qc == False)].copy()
m.loc[m.sag > 0.5, "sag"] = np.nan
m = m[m.homology_type.notna()]
med = m.groupby("homology_type")[["sag", "ir_late_mean"]].median()
print(f"features ({kind}): {len(m)} mouse cells"); print(med.round(3).to_string())
pairs = list(combinations(L.SUBCLASSES, 2))
print(" Dunn FDR p, sag:", {k: f"{v:.2g}" for k, v in L.dunn_pairs(m, "sag", "homology_type", pairs).items()})
irr = m[m.ir_late_mean > 0.4]
mc4r = m[m.homology_type == "MC4R"]
print(f" MC4R cells with ir_late_mean > 0.4: {int((mc4r.ir_late_mean > 0.4).sum())} of {int(mc4r.ir_late_mean.notna().sum())}")
print(" cells with ir_late_mean > 0.4 by subclass:", irr.homology_type.value_counts().to_dict(),
"| by t-type:", irr["t-type"].value_counts().to_dict())
print(f" LAMP5 share of the cells above 0.4: {int((irr.homology_type == 'LAMP5').sum())} of {len(irr)}; "
f"mostly LAMP5 (more than half): {(irr.homology_type == 'LAMP5').mean() > 0.5}")
for cut in [0.3, 0.5]:
irr_c = m[m.ir_late_mean > cut]
print(f" cut {cut}: {len(irr_c)} cells, LAMP5 {int((irr_c.homology_type == 'LAMP5').sum())}, MC4R "
f"{int((irr_c.homology_type == 'MC4R').sum())}, largest t-type {irr_c['t-type'].value_counts().head(2).to_dict()}")
print(f" MC4R median sag above LAMP5: {med.loc['MC4R', 'sag'] > med.loc['LAMP5', 'sag']}")
print(" sag range", round(m.sag.min(), 3), "to", round(m.sag.max(), 3), "| cells set missing for sag > 0.5:",
int((M[M.vis & (M.failed_qc == False)].sag > 0.5).sum()))
features (a): 235 mouse cells
sag ir_late_mean
homology_type
L1 VIP 0.070 0.356
LAMP5 0.042 0.156
MC4R 0.147 0.136
PAX6 0.223 NaN
Dunn FDR p, sag: {'LAMP5 - MC4R': '1.1e-09', 'LAMP5 - PAX6': '0.0076', 'LAMP5 - L1 VIP': '0.00046', 'MC4R - PAX6': '0.84', 'MC4R - L1 VIP': '0.0038', 'PAX6 - L1 VIP': '0.12'}
MC4R cells with ir_late_mean > 0.4: 4 of 18
cells with ir_late_mean > 0.4 by subclass: {'LAMP5': 15, 'L1 VIP': 11, 'MC4R': 4} | by t-type: {'Lamp5 Plch2 Dock5': 8, 'Vip Col15a1 Pde1a': 7, 'Lamp5 Ntn1 Npy2r': 6, 'Lamp5 Fam19a1 Tmem182': 4, 'Sncg Vip Nptx2': 4, 'Lamp5 Lsp1': 1}
LAMP5 share of the cells above 0.4: 15 of 30; mostly LAMP5 (more than half): False
cut 0.3: 55 cells, LAMP5 31, MC4R 4, largest t-type {'Lamp5 Plch2 Dock5': 16, 'Lamp5 Ntn1 Npy2r': 13}
cut 0.5: 20 cells, LAMP5 10, MC4R 2, largest t-type {'Vip Col15a1 Pde1a': 7, 'Lamp5 Plch2 Dock5': 6}
MC4R median sag above LAMP5: True
sag range -0.019 to 0.288 | cells set missing for sag > 0.5: 0
features (a'): 235 mouse cells
sag ir_late_mean
homology_type
L1 VIP 0.070 0.356
LAMP5 0.042 0.156
MC4R 0.147 0.136
PAX6 0.223 NaN
Dunn FDR p, sag: {'LAMP5 - MC4R': '1.3e-09', 'LAMP5 - PAX6': '0.0076', 'LAMP5 - L1 VIP': '0.00045', 'MC4R - PAX6': '0.83', 'MC4R - L1 VIP': '0.0042', 'PAX6 - L1 VIP': '0.12'}
MC4R cells with ir_late_mean > 0.4: 4 of 18
cells with ir_late_mean > 0.4 by subclass: {'LAMP5': 15, 'L1 VIP': 11, 'MC4R': 4} | by t-type: {'Lamp5 Plch2 Dock5': 8, 'Vip Col15a1 Pde1a': 7, 'Lamp5 Ntn1 Npy2r': 6, 'Lamp5 Fam19a1 Tmem182': 4, 'Sncg Vip Nptx2': 4, 'Lamp5 Lsp1': 1}
LAMP5 share of the cells above 0.4: 15 of 30; mostly LAMP5 (more than half): False
cut 0.3: 55 cells, LAMP5 31, MC4R 4, largest t-type {'Lamp5 Plch2 Dock5': 16, 'Lamp5 Ntn1 Npy2r': 13}
cut 0.5: 20 cells, LAMP5 10, MC4R 2, largest t-type {'Vip Col15a1 Pde1a': 7, 'Lamp5 Plch2 Dock5': 6}
MC4R median sag above LAMP5: True
sag range -0.019 to 0.288 | cells set missing for sag > 0.5: 0
features (b): 235 mouse cells
sag ir_late_mean
homology_type
L1 VIP 0.070 0.356
LAMP5 0.041 0.156
MC4R 0.141 0.136
PAX6 0.223 NaN
Dunn FDR p, sag: {'LAMP5 - MC4R': '1.3e-09', 'LAMP5 - PAX6': '0.0072', 'LAMP5 - L1 VIP': '0.00037', 'MC4R - PAX6': '0.82', 'MC4R - L1 VIP': '0.0046', 'PAX6 - L1 VIP': '0.12'}
MC4R cells with ir_late_mean > 0.4: 4 of 18
cells with ir_late_mean > 0.4 by subclass: {'LAMP5': 15, 'L1 VIP': 11, 'MC4R': 4} | by t-type: {'Lamp5 Plch2 Dock5': 8, 'Vip Col15a1 Pde1a': 7, 'Lamp5 Ntn1 Npy2r': 6, 'Lamp5 Fam19a1 Tmem182': 4, 'Sncg Vip Nptx2': 4, 'Lamp5 Lsp1': 1}
LAMP5 share of the cells above 0.4: 15 of 30; mostly LAMP5 (more than half): False
cut 0.3: 55 cells, LAMP5 31, MC4R 4, largest t-type {'Lamp5 Plch2 Dock5': 16, 'Lamp5 Ntn1 Npy2r': 13}
cut 0.5: 20 cells, LAMP5 10, MC4R 2, largest t-type {'Vip Col15a1 Pde1a': 7, 'Lamp5 Plch2 Dock5': 6}
MC4R median sag above LAMP5: True
sag range -0.019 to 0.288 | cells set missing for sag > 0.5: 0
features (b, all 272 strict cells): 255 mouse cells
sag ir_late_mean
homology_type
L1 VIP 0.070 0.361
LAMP5 0.043 0.161
MC4R 0.141 0.136
PAX6 0.212 0.212
Dunn FDR p, sag: {'LAMP5 - MC4R': '2.1e-09', 'LAMP5 - PAX6': '0.0019', 'LAMP5 - L1 VIP': '0.00034', 'MC4R - PAX6': '0.72', 'MC4R - L1 VIP': '0.0036', 'PAX6 - L1 VIP': '0.062'}
MC4R cells with ir_late_mean > 0.4: 4 of 18
cells with ir_late_mean > 0.4 by subclass: {'LAMP5': 18, 'L1 VIP': 12, 'MC4R': 4} | by t-type: {'Lamp5 Plch2 Dock5': 11, 'Vip Col15a1 Pde1a': 7, 'Lamp5 Ntn1 Npy2r': 6, 'Sncg Vip Nptx2': 5, 'Lamp5 Fam19a1 Tmem182': 4, 'Lamp5 Lsp1': 1}
LAMP5 share of the cells above 0.4: 18 of 34; mostly LAMP5 (more than half): True
cut 0.3: 60 cells, LAMP5 34, MC4R 4, largest t-type {'Lamp5 Plch2 Dock5': 19, 'Lamp5 Ntn1 Npy2r': 13}
cut 0.5: 22 cells, LAMP5 12, MC4R 2, largest t-type {'Lamp5 Plch2 Dock5': 8, 'Vip Col15a1 Pde1a': 7}
MC4R median sag above LAMP5: True
sag range -0.019 to 0.288 | cells set missing for sag > 0.5: 0
Result: not reproduced. The mouse MC4R subclass has a median sag of 0.141 to 0.147, above LAMP5's 0.041 to 0.042 (Dunn FDR p about 1e-9). Its irregularity ratio has a median of 0.136, and 4 of its 18 cells are above 0.4: a minority (reading (b) holds) but not none (reading (a) fails). Of the 30 mouse cells above 0.4, 15 are LAMP5, 11 L1 VIP and 4 MC4R, so irregular cells are not mostly LAMP5, and the largest t-type among them is Lamp5 Plch2 Dock5 (8 cells), not Lamp5 Ntn1 Npy2r (6). Both fail under both readings of "no irregular spiking", and the criterion names no partial level. With all 272 strict cells from the paper's table, 18 of 34 irregular cells are LAMP5 (a majority), but the largest t-type is still Lamp5 Plch2 Dock5 (11) and 4 MC4R cells are still above 0.4, so the outcome is the same. Variant (a') gives the same counts. The moderate sag holds.
fig5d-mouse-pax6-doublets¶
Mouse PAX6 subclass cells (Lamp5 Krt73) fire doublets at stimulus onset and show a depolarizing hump just below rheobase, marking them as alpha7 cells.
As l1_tnfaip.ipynb cells 20 and 23: mouse cells with primary_ephys by subclass; the initial firing
rate at rheobase + 40 pA (computed here under (a)) and the depolarizing sag ratio (sag_depol,
from the paper's table, O1). Reading (b) over all 272 strict mouse cells is a variant.
for kind, M in [("a", MA), ("a'", MA2), ("b", MB), ("b, all 272 strict cells", MB272)]:
m = M[M.vis & (M.failed_qc == False) & M.homology_type.notna()]
med = m.groupby("homology_type")[["first_isi_inv_hero", "sag_depol"]].median()
n = m.groupby("homology_type")[["first_isi_inv_hero", "sag_depol"]].count()
print(f"features ({kind}): medians (n)"); print(med.round(3).astype(str).add(" (").add(n.astype(str)).add(")").to_string())
krt = m[m["t-type"] == "Lamp5 Krt73"]
print(" Lamp5 Krt73 cells:"); print(krt[[c for c in ["first_isi_inv_hero", "sag_depol", "n_spikes_hero", "structure"] if c in krt]].round(3).to_string())
others = med.drop(index="PAX6")
print(" all Lamp5 Krt73 cells of the paper's mouse table:", mlabels[mlabels["t-type"] == "Lamp5 Krt73"][["structure", "in_strict_set"]].assign(
failed_qc=paper_m["failed_qc"], has_file=lambda d: d.index.isin(MA.index)).to_dict("index"))
print(f" PAX6 (Lamp5 Krt73) median above every other subclass: first_isi_inv_hero "
f"{med.loc['PAX6', 'first_isi_inv_hero'] > others.first_isi_inv_hero.max()}, sag_depol {med.loc['PAX6', 'sag_depol'] > others.sag_depol.max()}")
for f in ["first_isi_inv_hero", "sag_depol"]:
print(f" {f}: KW p {stats.kruskal(*[g[f].dropna() for _, g in m.groupby('homology_type')]).pvalue:.2g}")
features (a): medians (n)
first_isi_inv_hero sag_depol
homology_type
L1 VIP 171.233 (41) 0.082 (38)
LAMP5 20.129 (168) 0.035 (142)
MC4R 25.606 (18) 0.132 (19)
PAX6 97.684 (2) 0.273 (3)
Lamp5 Krt73 cells:
first_isi_inv_hero sag_depol n_spikes_hero structure
spec_id
855275163 58.005 0.273 2 VISl2/3
935084855 137.363 0.304 2 VISl1
987138425 NaN 0.257 1 VISp1
all Lamp5 Krt73 cells of the paper's mouse table: {855275163: {'structure': 'VISl2/3', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 935084855: {'structure': 'VISl1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 710346584: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': False}, 987138425: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 1131310191: {'structure': 'VIS1', 'in_strict_set': False, 'failed_qc': False, 'has_file': False}}
PAX6 (Lamp5 Krt73) median above every other subclass: first_isi_inv_hero False, sag_depol True
first_isi_inv_hero: KW p 1.8e-21
sag_depol: KW p 4.2e-09
features (a'): medians (n)
first_isi_inv_hero sag_depol
homology_type
L1 VIP 171.233 (41) 0.082 (38)
LAMP5 20.129 (168) 0.035 (142)
MC4R 25.606 (18) 0.132 (19)
PAX6 97.684 (2) 0.273 (3)
Lamp5 Krt73 cells:
first_isi_inv_hero sag_depol n_spikes_hero structure
spec_id
855275163 58.005 0.273 2 VISl2/3
935084855 137.363 0.304 2 VISl1
987138425 NaN 0.257 1 VISp1
all Lamp5 Krt73 cells of the paper's mouse table: {855275163: {'structure': 'VISl2/3', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 935084855: {'structure': 'VISl1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 710346584: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': False}, 987138425: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 1131310191: {'structure': 'VIS1', 'in_strict_set': False, 'failed_qc': False, 'has_file': False}}
PAX6 (Lamp5 Krt73) median above every other subclass: first_isi_inv_hero False, sag_depol True
first_isi_inv_hero: KW p 1.8e-21
sag_depol: KW p 4.2e-09
features (b): medians (n)
first_isi_inv_hero sag_depol
homology_type
L1 VIP 176.678 (41) 0.082 (38)
LAMP5 20.833 (168) 0.035 (142)
MC4R 25.606 (18) 0.132 (19)
PAX6 97.684 (2) 0.273 (3)
Lamp5 Krt73 cells:
first_isi_inv_hero sag_depol n_spikes_hero structure
spec_id
855275163 58.005 0.273 2 VISl2/3
935084855 137.363 0.304 2 VISl1
987138425 NaN 0.257 1 VISp1
all Lamp5 Krt73 cells of the paper's mouse table: {855275163: {'structure': 'VISl2/3', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 935084855: {'structure': 'VISl1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 710346584: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': False}, 987138425: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 1131310191: {'structure': 'VIS1', 'in_strict_set': False, 'failed_qc': False, 'has_file': False}}
PAX6 (Lamp5 Krt73) median above every other subclass: first_isi_inv_hero False, sag_depol True
first_isi_inv_hero: KW p 1.3e-21
sag_depol: KW p 4.2e-09
features (b, all 272 strict cells): medians (n)
first_isi_inv_hero sag_depol
homology_type
L1 VIP 176.678 (43) 0.085 (40)
LAMP5 20.912 (179) 0.037 (150)
MC4R 25.606 (18) 0.132 (19)
PAX6 97.684 (2) 0.273 (3)
Lamp5 Krt73 cells:
first_isi_inv_hero sag_depol structure
spec_id
855275163 58.005 0.273 VISl2/3
935084855 137.363 0.304 VISl1
710346584 NaN NaN VISp1
987138425 NaN 0.257 VISp1
all Lamp5 Krt73 cells of the paper's mouse table: {855275163: {'structure': 'VISl2/3', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 935084855: {'structure': 'VISl1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 710346584: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': False}, 987138425: {'structure': 'VISp1', 'in_strict_set': True, 'failed_qc': False, 'has_file': True}, 1131310191: {'structure': 'VIS1', 'in_strict_set': False, 'failed_qc': False, 'has_file': False}}
PAX6 (Lamp5 Krt73) median above every other subclass: first_isi_inv_hero False, sag_depol True
first_isi_inv_hero: KW p 1.6e-22
sag_depol: KW p 1.6e-09
Result: not reproduced. Only 3 Lamp5 Krt73 cells are in 000020 (the claims file lists 4; the fourth, specimen 710346584 in VISp1, has no file and no value for either feature in the paper's table), 2 of them with a value at rheobase + 40 pA. Their depolarizing sag ratio (0.257 to 0.304, median 0.273) is above the medians of every other mouse subclass (0.035 to 0.132). Their median initial firing rate, 97.7 Hz (58 and 137 Hz), is above LAMP5 (20 Hz) and MC4R (26 Hz) but below L1 VIP (171 to 177 Hz), so the doublet part of the criterion fails, under both readings and with all 272 cells. Variant (a') gives the same medians. The criterion names no partial level. The paper says only that these cells "tended to fire in doublets at stimulus onset" and does not compare them with L1 VIP cells; whether the criterion's comparison with every other subclass misreads the paper is asked of a reader (questions/000630.yaml). Under the narrower reading, Lamp5 Krt73 above LAMP5 and MC4R, both parts would hold.
Blocked claims that use the mouse data¶
fig3e-tea-validation, fig3f-a-type-conductance and fig1e-subclass-proportions are blocked. The cell below shows what the public mouse data hold for each: the mouse TEa cells and their files, the nucleated-patch voltage clamp sweeps in both datasets, and which t-types the public mouse table holds.
# fig3e: mouse TEa cells in the paper's table and their files in 000020
tea = mlabels[mlabels.structure.str.startswith("TEa", na=False)]
print("Mouse TEa cells in the paper's table:", len(tea), "| in the strict set:", int(tea.in_strict_set.sum()),
"| with a LIMS id:", int(tea.ephys_roi_id.notna().sum()), "| with a file in 000020:",
int(tea.ephys_roi_id.isin(m_assets_all.session_id).sum()))
# fig3f: nucleated-patch voltage clamp sweeps (stimulus codes starting with Nuc)
for name, f in [("human, 000630", h_feats), ("mouse, 000020 (strict L1 files)", m_feats)]:
codes = f.codes.str.split(";").explode().str.split(":").str[0]
nuc = codes[codes.str.startswith("Nuc")]
print(f"{name}: {nuc.index.nunique()} of {len(f)} files hold nucleated-patch sweeps; codes in most files:",
nuc.value_counts().head(4).to_dict())
nuc_m = m_feats.codes.str.contains("Nuc")
print("Mouse files with nucleated-patch sweeps by subclass:",
mlinked[nuc_m.values].set_index("spec_id")["t-type"].map(L.HOMOLOGY_MOUSE).fillna("none").value_counts().to_dict())
# fig1e: the public mouse table and the categories the test needs
print("Mouse table rows:", len(mlabels), "| rows whose t-type has no homology subclass (deeper t-types):",
int(mlabels.homology_type.isna().sum()), "| t-types:", mlabels["t-type"].nunique())
print("Human table rows with soma in L1 (strict_l1):", int((labels.in_strict_set & (labels.layer == "1")).sum()),
"| of which deeper t-types:", int((labels.in_strict_set & (labels.layer == "1") & labels.homology_type.isna()).sum()))
Mouse TEa cells in the paper's table: 15 | in the strict set: 0 | with a LIMS id: 15 | with a file in 000020: 0
human, 000630: 38 of 210 files hold nucleated-patch sweeps; codes in most files: {'NucVCLS0_DA_0': 38, 'NucVCLS1Leak_DA_0': 35, 'NucVCprepulse_DA_0': 29, 'NucVCQCLS_DA_0': 25}
mouse, 000020 (strict L1 files): 25 of 250 files hold nucleated-patch sweeps; codes in most files: {'NucVCLS0_DA_0': 17, 'NucVCLS1Leak_DA_0': 17, 'NucVCSus0_DA_0': 9, 'NucVCSus1Leak_DA_0': 9}
Mouse files with nucleated-patch sweeps by subclass: {'LAMP5': 15, 'L1 VIP': 8, 'MC4R': 2}
Mouse table rows: 547 | rows whose t-type has no homology subclass (deeper t-types): 0 | t-types: 8
Human table rows with soma in L1 (strict_l1): 253 | of which deeper t-types: 22
Result: all three stay blocked. None of the 15 mouse TEa cells of the paper's table has a file in 000020 (fig3e, data missing). Nucleated-patch sweeps are in 38 human and 25 of the 250 mouse files, so the conductances could be computed, but the patch surface areas the densities need were measured from images that are not public (fig3f, data missing; not computed here). The public mouse table holds only cells of the 8 mouse L1 t-types, none of the deeper t-types the code's proportion test counts, so the test cannot be repeated from the public tables (fig1e, metadata insufficient).
Summary¶
| Claim | Outcome |
|---|---|
| mouse-cell-link | partially reproduced |
| fig3d-ephys-species | partially reproduced |
| fig3g-variability-dimensions | reproduced |
| fig4d-mouse-no-rosehip-ephys | not reproduced |
| fig5d-mouse-pax6-doublets | not reproduced |
| fig3e-tea-validation | blocked, data missing |
| fig3f-a-type-conductance | blocked, data missing |
| fig1e-subclass-proportions | blocked, metadata insufficient |
A failure to reproduce here may be a failure of this attempt, not of the paper: see the reasoning and the differences from the paper's method.
How the analysis differs from the paper's: the same feature extraction as the human notebook, applied to the 250 mouse files of 000020; 22 of the paper's 272 strict mouse L1 cells have no file there. fig3d and fig3g use mouse VISp as the claims file says; the code takes every visual area. Every outcome here is the same in variant (a'), the features extracted without the 500 ms noise criterion. What was found: the mouse files link to the paper's table by session id and cell name, and their sweeps that stopped early are also stored with zeros.
print(f"notebook run time {(time.time() - started) / 60:.1f} min")
notebook run time 13.0 min