Reproducing Moore et al. (2025) from dandiset 001699¶
Paper. Moore N, Duszkiewicz AJ, Asiminas A, Dudchenko PA, Peyrache A, Wood ER (2025). Age-dependent alterations in the head-direction signal in a rat model of Fragile X Syndrome. bioRxiv. doi:10.1101/2025.01.09.632139. This attempt used the full text of version 1 (9 January 2025), the version the dandiset links and whose title the target names. A revised version 2 (7 January 2026, "Altered developmental profile of the cortical head-direction signal in a rat model of Fragile X Syndrome") was also read; its Methods are used only where version 1 is silent (the Bayesian decoder, the speed smoothing), and its numbers are compared in the attempt record.
Data. DANDI:001699, version
0.260917.2322, streamed from the archive. The paper cites no version (its Data Availability says the
data will be released at publication). Two versions are published, 0.260917.2313 and
0.260917.2322, nine minutes apart; the data check below shows that their assets are the same files,
and the metadata differ only in the title, description and study target. The most recent published
version is pinned, as the protocol asks when no version is cited and no earlier one matches the paper
better.
Code. The dandiset links the lab's package woodcode
(https://github.com/Wood-Dudchenko-lab/woodcode, read at commit
61ee1784ef8bdeed1befa4d2dd2dd71dc8befd60). It holds general functions (waveform trough-to-peak, Skaggs
information, Rayleigh vector length, a Poisson decoder, loading NWB files) and not the paper's analysis,
which the Methods say was run in Matlab and R. Where the Methods leave a choice open and woodcode
settles it (the channel used for trough-to-peak, positive waveforms, circular smoothing) the helper
module hdfx.py follows woodcode; its docstring lists where each parameter comes from.
| Claim | Paper | Tested |
|---|---|---|
| unit-counts | Results: 406, 372, 543, 507 units in 7, 5, 6, 6 rats | tested |
| units-per-recording | Results: 8 to 83 and 30 to 114 units per recording | tested |
| figs1c-juvenile-behaviour-similar | Fig. S1c | tested |
| figs2c-adult-behaviour-similar | Fig. S2c | tested |
| figs1-juvenile-cell-metrics-similar | Fig. S1f-i | tested |
| figs2-adult-cell-metrics-similar | Fig. S2f-i | tested |
| fig1ef-juvenile-sharper-tuning | Fig. 1e-f | tested |
| fig1g-juvenile-halves-correlation | Fig. 1g | tested |
| fig1h-juvenile-smaller-offset | Fig. 1h | tested |
| fig1j-juvenile-less-drift | Fig. 1i-j | tested |
| figs1j-juvenile-epochs-correlation | Fig. S1j | tested |
| figs1k-juvenile-epoch-drift-similar | Fig. S1k | tested |
| fig2c-juvenile-isomap-wake-correlation | Fig. 2c | tested |
| fig2d-juvenile-isomap-wake-sharper | Fig. 2d | tested |
| fig2g-juvenile-isomap-rem-correlation | Fig. 2e-g | tested |
| fig2h-juvenile-isomap-rem-sharper | Fig. 2h | tested |
| fig3ef-adult-tuning-similar | Fig. 3e-f | tested |
| fig3g-adult-halves-correlation | Fig. 3g | tested |
| fig3h-adult-larger-offset | Fig. 3h | tested |
| fig3j-adult-more-drift | Fig. 3i-j | tested |
| figs2j-adult-epochs-correlation | Fig. S2j | tested |
| figs2k-adult-epoch-drift-larger | Fig. S2k | tested |
| fig4c-adult-isomap-wake-correlation | Fig. 4c | tested |
| fig4d-adult-isomap-wake-similar | Fig. 4d | tested |
| fig4g-adult-isomap-rem-correlation | Fig. 4e-g | tested |
| fig4h-adult-isomap-rem-similar | Fig. 4h | tested |
| figs1d-probe-in-posub | Fig. S1d, S2d (histology) | blocked |
import os
os.environ.setdefault("OMP_NUM_THREADS", "1") # many small fits run in parallel processes
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
os.environ.setdefault("MKL_NUM_THREADS", "1")
import time
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from dandi.dandiapi import DandiAPIClient
from scipy import stats
import hdfx
warnings.filterwarnings("ignore", category=RuntimeWarning)
warnings.filterwarnings("ignore", message=".*converge.*")
warnings.filterwarnings("ignore", message=".*Hessian.*")
warnings.filterwarnings("ignore", message=".*boundary.*")
pd.set_option("display.width", 220)
pd.set_option("display.max_columns", 40)
pd.set_option("display.max_rows", 200)
pd.set_option("display.max_colwidth", 120)
print("dandiset", hdfx.DANDISET_ID, "version", hdfx.DANDISET_VERSION)
dandiset 001699 version 0.260917.2322
started = time.time()
assets = hdfx.list_assets()
results = hdfx.process_all(list(assets.asset_id), workers=4)
meta = pd.DataFrame([r["meta"] for r in results])
print(f"{len(assets)} NWB files streamed and analysed in {time.time() - started:.0f} s")
36 NWB files streamed and analysed in 812 s
Data check¶
Each check of the description against the values is stated under its output.
with DandiAPIClient() as client:
ds = client.get_dandiset(hdfx.DANDISET_ID, hdfx.DANDISET_VERSION)
raw = ds.get_raw_metadata()
summary = raw["assetsSummary"]
print("name:", raw["name"])
print("archive summary: subjects", summary["numberOfSubjects"], "| files", summary["numberOfFiles"],
"| species", [s["name"] for s in summary["species"]],
"| variables", summary["variableMeasured"])
print("related resources:", [(r.get("name"), r.get("relation"), r.get("url")) for r in raw["relatedResource"]])
print("about:", [(a["name"], a["schemaKey"], a["identifier"]) for a in raw.get("about", [])])
versions, asset_age = {}, []
for v in ("0.260917.2313", "0.260917.2322"):
d = client.get_dandiset(hdfx.DANDISET_ID, v)
versions[v] = set()
for a in d.get_assets():
md = a.get_raw_metadata()
versions[v].add((a.path, a.size, md["digest"]["dandi:dandi-etag"]))
if v == hdfx.DANDISET_VERSION and a.path.endswith(".nwb"):
subj = [w for w in md.get("wasAttributedTo", []) if w.get("schemaKey") == "Participant"]
asset_age.append({"path": a.path, "asset_metadata_age": subj[0].get("age", {}).get("value") if subj else None})
print(f"version {v}: {len(versions[v])} assets, title {d.get_raw_metadata()['name']!r}")
print("same assets (path, size, etag) in both published versions:",
versions["0.260917.2313"] == versions["0.260917.2322"])
asset_age = pd.DataFrame(asset_age).sort_values("path")
print("\nage in the archive's asset metadata (derived by the archive from the date of birth):")
print(asset_age.to_string(index=False))
name: Altered developmental profile of the head-direction signal in a rat model of fragile X syndrome
archive summary: subjects 24 | files 98 | species ['Rattus norvegicus - Norway rat'] | variables ['ProcessingModule', 'Position', 'LFP', 'Units', 'SpatialSeries', 'CompassDirection', 'ElectricalSeries']
related resources: [('woodcode', 'dcite:IsCompiledBy', 'https://github.com/Wood-Dudchenko-lab/woodcode'), ('Age-dependent alterations in the head-direction signal in a rat model of Fragile X Syndrome', 'dcite:IsDescribedBy', 'https://www.biorxiv.org/content/10.1101/2025.01.09.632139v1')]
about: [('Fragile X Syndrome', 'Disorder', 'http://id.nlm.nih.gov/mesh/D005600'), ('Fmr1 protein, rat', 'Anatomy', 'http://id.nlm.nih.gov/mesh/D005600')]
version 0.260917.2313: 98 assets, title 'Age-dependent alterations in the head-direction signal in a rat model of Fragile X Syndrome'
version 0.260917.2322: 98 assets, title 'Altered developmental profile of the head-direction signal in a rat model of fragile X syndrome'
same assets (path, size, etag) in both published versions: True
age in the archive's asset metadata (derived by the archive from the date of birth):
path asset_metadata_age
sub-H3001/sub-H3001_ses-200201_behavior+ecephys.nwb P25D
sub-H3001/sub-H3001_ses-200202_behavior+ecephys.nwb P26D
sub-H3003/sub-H3003_ses-200207_behavior+ecephys+image.nwb P26DT69565S
sub-H3003/sub-H3003_ses-200208_behavior+ecephys+image.nwb P27DT54048S
sub-H3006/sub-H3006_ses-200314-1_behavior+ecephys+image.nwb P25DT42701S
sub-H3006/sub-H3006_ses-200314-2_behavior+ecephys+image.nwb P25DT75822S
sub-H3008/sub-H3008_ses-200805_behavior+ecephys+image.nwb P23DT62005S
sub-H3008/sub-H3008_ses-200807_behavior+ecephys+image.nwb P25DT58683S
sub-H3009/sub-H3009_ses-200812_behavior+ecephys+image.nwb P26DT58673S
sub-H3009/sub-H3009_ses-200813_behavior+ecephys+image.nwb P27DT58527S
sub-H3015/sub-H3015_ses-210416-1_behavior+ecephys+image.nwb P25DT48227S
sub-H3015/sub-H3015_ses-210416-2_behavior+ecephys+image.nwb P25DT70156S
sub-H3015/sub-H3015_ses-210417_behavior+ecephys+image.nwb P26DT50767S
sub-H3016/sub-H3016_ses-210422_behavior+ecephys+image.nwb P22DT65724S
sub-H3016/sub-H3016_ses-210423_behavior+ecephys+image.nwb P23DT51235S
sub-H3019/sub-H3019_ses-210617_behavior+ecephys+image.nwb P24DT56019S
sub-H3019/sub-H3019_ses-210618-1_behavior+ecephys+image.nwb P25DT41760S
sub-H3022/sub-H3022_ses-210805_behavior+ecephys+image.nwb P22DT61583S
sub-H3022/sub-H3022_ses-210806_behavior+ecephys+image.nwb P23DT41647S
sub-H3023/sub-H3023_ses-210812_behavior+ecephys+image.nwb P-366DT71052S
sub-H3023/sub-H3023_ses-210813-1_behavior+ecephys+image.nwb P-365DT50184S
sub-H3026/sub-H3026_ses-211003_behavior+ecephys+image.nwb P-345DT79247S
sub-H3026/sub-H3026_ses-211004-2_behavior+ecephys+image.nwb P-344DT66679S
sub-H3029/sub-H3029_ses-230510_behavior+ecephys+image.nwb P97DT40365S
sub-H4813/sub-H4813_ses-220728_behavior+ecephys+image.nwb P65DT65667S
sub-H4815/sub-H4815_ses-220814_behavior+ecephys+image.nwb P82DT73146S
sub-H4817/sub-H4817_ses-220828_behavior+ecephys+image.nwb P57DT58685S
sub-H4819/sub-H4819_ses-220929_behavior+ecephys+image.nwb P78DT79058S
sub-H4820/sub-H4820_ses-221007_behavior+ecephys+image.nwb P86DT68066S
sub-H4822/sub-H4822_ses-221023_behavior+ecephys.nwb P71D
sub-H4823/sub-H4823_ses-221108_behavior+ecephys.nwb P87DT3600S
sub-H4824/sub-H4824_ses-221117_behavior+ecephys+image.nwb P96DT68177S
sub-H4825/sub-H4825_ses-221124_behavior+ecephys+image.nwb P72DT78275S
sub-H4826/sub-H4826_ses-221203_behavior+ecephys+image.nwb P82DT549S
sub-H4827/sub-H4827_ses-221210_behavior+ecephys+image.nwb P88DT72211S
sub-H4830/sub-H4830_ses-230406_behavior+ecephys+image.nwb P63DT65155S
The two published versions hold the same 98 assets (36 NWB files and 62 videos); they differ in title
and description only, so the choice between them does not change the analysis. The archive counts 24
subjects of Rattus norvegicus, as the files do. Its about field lists "Fmr1 protein, rat" as an
anatomy term with the MeSH identifier of Fragile X Syndrome (D005600), a metadata error.
cols = ["subject", "session_id", "archive_genotype", "date_of_birth", "session_start", "age_days",
"age_field", "n_units", "n_spikes", "n_unsorted_units", "n_channels", "unit_columns"]
print(meta[cols].to_string())
print("\nsession descriptions:", meta.session_description.unique())
print("subjects:", meta.subject.nunique(), "| files:", len(meta), "| units in all files:", meta.n_units.sum())
print("files with unsorted spike times:", meta.loc[meta.n_unsorted_units > 0, ["subject", "session_id", "n_unsorted_units"]].values.tolist())
bad_dob = meta[meta.age_days < 0]
print("files whose date of birth is after the recording:", bad_dob[["subject", "session_id", "date_of_birth", "session_start"]].values.tolist())
print("\nhistology images (acquisition/histology_images) per file:")
print(meta[["subject", "session_id", "histology_images"]].to_string())
print("files with at least one histology image:", int((meta.histology_images != "").sum()), "of", len(meta))
subject session_id archive_genotype date_of_birth session_start age_days age_field n_units n_spikes n_unsorted_units n_channels unit_columns 0 H3001 200201 WT 2020-01-07 2020-02-01 25 None 23 1539093 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 1 H3001 200202 WT 2020-01-07 2020-02-02 26 None 16 1145133 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 2 H3003 200207 KO 2020-01-12 2020-02-07 26 None 40 2355251 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 3 H3003 200208 KO 2020-01-12 2020-02-08 27 None 29 1515000 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 4 H3006 200314_1 WT 2020-02-18 2020-03-14 25 None 37 2081499 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 5 H3006 200314_2 WT 2020-02-18 2020-03-14 25 None 26 1110241 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 6 H3008 200805 KO 2020-07-13 2020-08-05 23 None 38 2318166 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 7 H3008 200807 KO 2020-07-13 2020-08-07 25 None 16 1369688 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 8 H3009 200812 WT 2020-07-17 2020-08-12 26 None 37 1560012 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 9 H3009 200813 WT 2020-07-17 2020-08-13 27 None 33 1546335 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 10 H3015 210416_1 WT 2021-03-22 2021-04-16 25 None 34 1029146 0 31 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 11 H3015 210416_2 WT 2021-03-22 2021-04-16 25 None 45 1709157 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 12 H3015 210417 WT 2021-03-22 2021-04-17 26 None 26 1420962 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 13 H3016 210422 KO 2021-03-31 2021-04-22 22 None 27 1396257 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 14 H3016 210423 KO 2021-03-31 2021-04-23 23 None 46 930169 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 15 H3019 210617 KO 2021-05-24 2021-06-17 24 None 17 688938 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 16 H3019 210618_1 KO 2021-05-24 2021-06-18 25 None 8 127027 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 17 H3022 210805 WT 2021-07-14 2021-08-05 22 None 20 556103 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 18 H3022 210806 WT 2021-07-14 2021-08-06 23 None 31 1049748 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 19 H3023 210812 WT 2022-08-13 2021-08-12 -366 None 22 1182429 1 31 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 20 H3023 210813_1 WT 2022-08-13 2021-08-13 -365 None 24 1546703 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 21 H3026 211003 WT 2022-09-13 2021-10-03 -345 None 83 4394695 0 64 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 22 H3026 211004_2 WT 2022-09-13 2021-10-04 -344 None 68 3347010 0 64 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 23 H3029 230510 WT 2023-02-02 2023-05-10 97 None 32 1193655 0 64 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 24 H4813 220728 WT 2022-05-24 2022-07-28 65 None 70 3988829 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 25 H4815 220814 WT 2022-05-24 2022-08-14 82 None 99 6066930 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 26 H4817 220828 KO 2022-07-02 2022-08-28 57 None 105 6307039 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 27 H4819 220929 KO 2022-07-13 2022-09-29 78 None 114 5969234 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 28 H4820 221007 WT 2022-07-13 2022-10-07 86 None 63 5490852 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 29 H4822 221023 KO 2022-08-13 2022-10-23 71 None 55 3075000 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 30 H4823 221108 WT 2022-08-13 2022-11-08 87 None 113 6514735 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 31 H4824 221117 KO 2022-08-13 2022-11-17 96 None 88 5649599 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 32 H4825 221124 KO 2022-09-13 2022-11-24 72 None 88 5649599 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 33 H4826 221203 WT 2022-09-13 2022-12-03 81 None 102 4697377 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 34 H4827 221210 KO 2022-09-13 2022-12-10 88 None 78 3591109 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean 35 H4830 230406 WT 2023-02-02 2023-04-06 63 None 96 6890094 0 32 electrode_group,id,sampling_rate,spike_times,spike_times_index,waveform_mean session descriptions: <StringArray> ['Exploration, sleep and cue rotation '] Length: 1, dtype: str subjects: 24 | files: 36 | units in all files: 1849 files with unsorted spike times: [['H3023', '210812', 1]] files whose date of birth is after the recording: [['H3023', '210812', '2022-08-13', '2021-08-12'], ['H3023', '210813_1', '2022-08-13', '2021-08-13'], ['H3026', '211003', '2022-09-13', '2021-10-03'], ['H3026', '211004_2', '2022-09-13', '2021-10-04']] histology images (acquisition/histology_images) per file: subject session_id histology_images 0 H3001 200201 H3001_D2, H3001_D3 1 H3001 200202 H3001_D2, H3001_D3 2 H3003 200207 H3003_D3, H3003_D4 3 H3003 200208 H3003_D3, H3003_D4 4 H3006 200314_1 H3006_C5, H3006_C6 5 H3006 200314_2 H3006_C5, H3006_C6 6 H3008 200805 H3008_B7 7 H3008 200807 H3008_B7 8 H3009 200812 H3009_C4, H3009_c5 9 H3009 200813 H3009_C4, H3009_c5 10 H3015 210416_1 H3015_C2, H3015_C3, H3015_C4 11 H3015 210416_2 H3015_C2, H3015_C3, H3015_C4 12 H3015 210417 H3015_C2, H3015_C3, H3015_C4 13 H3016 210422 H3016_C5, H3016_C6 14 H3016 210423 H3016_C5, H3016_C6 15 H3019 210617 H3019_4.3(DiI), H3019_4.4(DiI) 16 H3019 210618_1 H3019_4.3(DiI), H3019_4.4(DiI) 17 H3022 210805 H3022(DAPI), H3022_B3, H3022_B4 18 H3022 210806 H3022(DAPI), H3022_B3, H3022_B4 19 H3023 210812 H3023(DAPI), H3023_E2 20 H3023 210813_1 H3023(DAPI), H3023_E2 21 H3026 211003 H3026-D1 22 H3026 211004_2 H3026-D1 23 H3029 230510 H3029_D6, H3029_E1 24 H4813 220728 H4813_C3, H4813_C4, H4813_C5 25 H4815 220814 H4815_D1, H4815_E1, H4815_E2, H4815_E3 26 H4817 220828 H4817_C5, H4817_D1 27 H4819 220929 H4819_C3, H4819_C4, H4819_C5, H4819_C6 28 H4820 221007 H4820_C1, H4820_C6, H4820_D1 29 H4822 221023 H4822_B6, H4822_C2 30 H4823 221108 H4823_D5, H4823_D6 31 H4824 221117 H4824_D3 32 H4825 221124 H4825_B4, H4825_B5 33 H4826 221203 H4826_C6, H4826_D2 34 H4827 221210 H4827_C5, H4827_C6 35 H4830 230406 H4830_D2 files with at least one histology image: 36 of 36
Every file has a units table with only spike_times, waveform_mean, electrode_group and
sampling_rate: no cell type, quality metric or depth, so the paper's cell selection is recomputed from
the waveforms and spike trains. No NWB file sets the subject's age; the archive's asset metadata give an age
derived from the date of birth (printed above). Subjects H3023 and H3026 have dates of birth a year
after their recordings, so the archive gives them negative ages (P-366D to P-344D), a metadata error; their age group is taken from their other
properties below. The session description of every file mentions a cue rotation, which version 1 of the
paper does not describe; most files hold a third tracked session after the second, which is not used. One
unit in H3023 (session 210812) has spike times out of order, a format error; the helper sorts them. Every file holds histology images (acquisition/histology_images, printed above), including the
four whose asset names lack +image; none marks the probe tract or the postsubiculum, so
figs1d-probe-in-posub is blocked.
def counts(df, age_col, geno_col):
g = df.groupby([age_col, geno_col])
return pd.DataFrame({"rats": g.subject.nunique(), "recordings": g.size(), "units": g.n_units.sum(),
"min_units": g.n_units.min(), "max_units": g.n_units.max()})
once = meta[~meta.subject.isin(hdfx.DUPLICATE_OF)]
arch = meta.copy()
arch["archive_age_group"] = arch.archive_age_group.fillna("no valid age")
print("Archive labels (age group from date of birth), every file:")
print(counts(arch, "archive_age_group", "archive_genotype").to_string())
print("\nMain grouping, each recording once (H4825 left out):")
print(counts(once, "age_group", "genotype").to_string())
print("\nSubjects whose main group differs from the archive's:")
diff = meta[(meta.genotype != meta.archive_genotype) | (meta.age_group != meta.archive_age_group)]
print(diff[["subject", "session_id", "archive_genotype", "genotype", "archive_age_group", "age_group", "age_days", "n_units", "n_channels"]].to_string())
Archive labels (age group from date of birth), every file:
rats recordings units min_units max_units
archive_age_group archive_genotype
adult KO 6 6 528 55 114
WT 7 7 575 32 113
juvenile KO 4 8 221 8 46
WT 5 11 328 16 45
no valid age WT 2 4 197 22 83
Main grouping, each recording once (H4825 left out):
rats recordings units min_units max_units
age_group genotype
adult KO 5 5 440 55 114
WT 6 6 543 63 113
juvenile KO 5 10 372 8 83
WT 7 14 406 16 45
Subjects whose main group differs from the archive's:
subject session_id archive_genotype genotype archive_age_group age_group age_days n_units n_channels
19 H3023 210812 WT WT NaN juvenile -366 22 31
20 H3023 210813_1 WT WT NaN juvenile -365 24 32
21 H3026 211003 WT KO NaN juvenile -345 83 64
22 H3026 211004_2 WT KO NaN juvenile -344 68 64
23 H3029 230510 WT WT adult juvenile 97 32 64
With the archive's labels no grouping reproduces the paper's counts (406 units in 7 juvenile WT rats, 372 in 5 juvenile Fmr1-/y, 543 in 6 adult WT, 507 in 6 adult Fmr1-/y). If H3026 is a juvenile Fmr1-/y rat (the archive says WT, and gives it a birth date after its recording) and H3029 a juvenile WT rat (its birth date, the same as H4830's, makes it 97 days old), three of the four groups match the paper exactly in units and rats. H3026's 83 units in one recording is also the top of the paper's range for juveniles. H3026 and H3029 are the only rats recorded with 64-channel probes, which fits their being a later juvenile cohort. This is consistent with the data but not proven by it; the genotype of H3026 cannot be checked from the files. The main grouping uses it, and the claims show the archive's labels as a variant. The archive's genotype labels are recorded as a finding.
key = ["n_units", "n_spikes"]
dup = meta[meta.duplicated(key, keep=False)].sort_values(key)
print("files sharing unit and spike counts:")
print(dup[["subject", "session_id", "archive_genotype", "n_units", "n_spikes", "spike_checksum"]].to_string())
a = results[meta.index[meta.subject == "H4824"][0]]["meta"]
b = results[meta.index[meta.subject == "H4825"][0]]["meta"]
print("first 20 spike times of every unit identical:", np.array_equal(a["first_spikes"], b["first_spikes"]))
print("trough-to-peak of every unit identical:", np.allclose(a["ttp"], b["ttp"], equal_nan=True))
print("per unit, count and sum of spike times before 1248 s identical:", np.allclose(a["early_fingerprint"], b["early_fingerprint"]))
print("spikes at the file's last spike time: H4824", a["spikes_at_last_time"], "| H4825", b["spikes_at_last_time"])
print("H4824 epochs:\n", a["epochs"].round(1).to_string())
print("H4825 epochs:\n", b["epochs"].round(1).to_string())
print("H4825 tracking frames with a repeated timestamp:", b["non_increasing_frames"])
print("H4825 units with contamination above 0.5:", int(np.sum(b["contamination"] > 0.5)), "of", len(b["contamination"]),
"| H4824:", int(np.sum(a["contamination"] > 0.5)))
files sharing unit and spike counts:
subject session_id archive_genotype n_units n_spikes spike_checksum
31 H4824 221117 KO 88 5649599 4.729009e+06
32 H4825 221124 KO 88 5649599 4.715128e+06
first 20 spike times of every unit identical: True
trough-to-peak of every unit identical: True
per unit, count and sum of spike times before 1248 s identical: True
spikes at the file's last spike time: H4824 1 | H4825 131373
H4824 epochs:
start stop tag
0 0.0 1472.0 01
1 1580.9 7100.4 02
2 7140.8 8419.4 03
3 8588.2 9909.8 04
H4825 epochs:
start stop tag
0 0.0 1248.7 01
1 1323.0 6781.6 02
2 6870.4 8142.5 03
3 8271.3 9564.0 04
H4825 tracking frames with a repeated timestamp: 12970
H4825 units with contamination above 0.5: 87 of 88 | H4824: 3
H4825's file holds H4824's recording: the same 88 units with identical waveforms, spike counts and spike times up to 1248 s (the end of H4825's first epoch), after which H4825's spike and tracking times are shifted piece by piece onto H4825's own epoch table and clipped at its end (many spikes then share the last spike time, which makes 87 of 88 units look contaminated). This recording is counted once, as H4824, and H4825 has no data of its own in the dandiset. No other pair of files shares unit and spike counts.
rows = []
for r in results:
m = r["meta"]
rows.append({"subject": m["subject"], "session": m["session_id"],
"epochs (s)": "; ".join(f"{e.tag}:{e.start:.0f}-{e.stop:.0f}" for e in m["epochs"].itertuples()),
"task epochs": m["task_epochs"],
"tracking blocks over 10 min (s)": "; ".join(f"{a:.0f}-{b:.0f}" for a, b in m["blocks"] if b - a >= 600),
"sessions used (s)": "; ".join(f"{a:.0f}-{b:.0f}" for a, b in m["sessions"]),
"repeated frames": m["non_increasing_frames"]})
print(pd.DataFrame(rows).to_string())
subject session epochs (s) task epochs tracking blocks over 10 min (s) sessions used (s) repeated frames
0 H3001 200201 01:24-1687; 02:1726-6451; 03:6494-8021 {'sleep': ['2'], 'wake': ['1', '3']} 24-1687; 6494-8021 24-1224; 6494-7694 1
1 H3001 200202 01:18-5683; 02:5737-7864 {'sleep': ['2'], 'wake': ['1']} 5737-7864 5737-6937 1
2 H3003 200207 01:52-1279; 02:1308-6890; 03:6926-8110 {'sleep': ['2'], 'wake': ['1', '3']} 52-1279; 6926-8110 52-1252; 6926-8110 1
3 H3003 200208 01:49-1252; 02:1305-7412; 03:7451-8653 {'sleep': ['2'], 'wake': ['1', '3']} 49-1252; 7451-8653 49-1249; 7451-8651 1
4 H3006 200314_1 01:4-1276; 02:1313-6769; 03:6808-8320; 04:8594-9403; 05:9404-9405 {'error': ['5'], 'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 4-1276; 6808-8320; 8594-9404 4-1204; 6808-8008 2
5 H3006 200314_2 01:4-1213; 02:1249-6686; 03:6854-6969; 04:6989-8110; 05:8325-9539 {'error': ['3'], 'sleep': ['2'], 'wake': ['1', '4'], 'wake_cue_rot': ['5']} 4-1213; 6989-8110; 8325-9539 4-1204; 6989-8110 2
6 H3008 200805 01:4-1277; 02:1304-6768; 03:6810-8022 {'sleep': ['2'], 'wake': ['1', '3']} 4-1277; 6810-8022 4-1204; 6810-8010 1
7 H3008 200807 01:2-1240; 02:1265-6887; 03:6941-8186; 04:8531-9626 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 2-1240; 6941-8186; 8531-9626 2-1202; 6941-8141 2
8 H3009 200812 01:3-1308; 02:1342-6750; 03:6782-8061; 04:8330-9636 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 3-1308; 6782-8061; 8330-9636 3-1203; 6782-7982 2
9 H3009 200813 01:2-1247; 02:1267-6697; 03:6749-8182; 04:8477-9801 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 2-1247; 6749-8182; 8477-9801 2-1202; 6749-7949 2
10 H3015 210416_1 01:0-1843; 02:1884-7096; 03:7096-8382; 04:8382-9737 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1843; 7096-9737 0-1200; 7096-8296 2
11 H3015 210416_2 01:0-1336; 02:1378-6853; 03:6919-8174; 04:8470-9795 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1336; 6919-8174; 8470-9795 0-1200; 6919-8119 2
12 H3015 210417 01:66-1367; 02:1408-6848; 03:6894-8415; 04:8647-10084 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 66-1367; 1408-6848; 6894-8415; 8647-10084 66-1266; 6894-8094 3
13 H3016 210422 01:0-1264; 02:1306-6819; 03:6862-8097; 04:8401-9891 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1264; 6862-8097; 8401-9891 0-1200; 6862-8062 2
14 H3016 210423 01:43-1278; 02:1311-6738; 03:6866-8400; 04:8648-9947 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 43-1278; 6866-8400; 8648-9947 43-1243; 6866-8066 2
15 H3019 210617 01:0-1230; 02:1264-6684; 03:6715-7978; 04:8301-9628 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1230; 6715-7978; 8301-9628 0-1200; 6715-7915 2
16 H3019 210618_1 01:3-1236; 02:1268-3278 {'sleep': ['2'], 'wake': ['1']} 3-1236 3-1203 0
17 H3022 210805 01:0-1229; 02:1270-6806; 03:6861-8093; 04:8377-9596 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1229; 6861-8093; 8377-9596 0-1200; 6861-8061 2
18 H3022 210806 01:0-1219; 02:1263-6756; 03:6806-8162; 04:8422-9703 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1219; 6806-8162; 8422-9700 0-1200; 6806-8006 2
19 H3023 210812 01:0-1220; 02:1220-6629; 03:6629-9104 {'sleep': ['2'], 'wake': ['1', '3']} 0-1220; 6629-9104 0-1200; 6629-7829 3
20 H3023 210813_1 01:0-1211; 02:1211-7888; 03:7888-9135 {'sleep': ['2'], 'wake': ['1', '3']} 0-1211; 6661-9135 0-1200; 6661-7861 2
21 H3026 211003 01:0-6720; 02:6720-7972; 03:7972-9252 {'sleep': ['2'], 'wake': ['1', '3']} 0-1286; 6720-9252 0-1200; 6720-7920 2
22 H3026 211004_2 01:0-1215; 02:1215-6677; 03:6677-7896; 04:7896-9216 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 0-1215; 6677-9186 0-1200; 6677-7877 2
23 H3029 230510 01:0-1234; 02:1318-6858; 03:6883-8142; 04:8294-9535 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 4-1232; 6886-8140; 8298-9534 4-1204; 6886-8086 0
24 H4813 220728 01:0-1227; 02:1352-6824; 03:6871-8109; 04:8343-9638 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 4-1223; 6879-8106; 8347-9634 4-1204; 6879-8079 0
25 H4815 220814 01:0-1295; 02:1411-7025; 03:7083-8359; 04:8459-9784 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 4-1293; 7087-8356; 8462-9780 4-1204; 7087-8287 0
26 H4817 220828 01:0-1258; 02:1372-6860; 03:6913-8152; 04:8287-9636 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 5-1255; 6921-8149; 8292-9634 5-1205; 6921-8121 0
27 H4819 220929 01:0-1266; 02:1365-6906; 03:6937-8170; 04:8341-9624 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 6-1263; 6943-8167; 8346-9622 6-1206; 6943-8143 0
28 H4820 221007 01:0-1273; 02:1340-6867; 03:6925-8173; 04:8389-9719 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 8-1271; 6929-8171; 8393-9717 8-1208; 6929-8129 0
29 H4822 221023 01:0-1231; 02:1330-6797; 03:6867-8117; 04:8288-9506 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 6-1228; 6871-8116; 8292-9505 6-1206; 6871-8071 0
30 H4823 221108 01:0-9466 {'wake': ['1']} 5-1235; 1242-6836; 6844-8133; 8139-9464 5-1205; 6844-8044 0
31 H4824 221117 01:0-1472; 02:1581-7100; 03:7141-8419; 04:8588-9910 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 6-1471; 7144-8415; 8591-9909 6-1206; 7144-8344 0
32 H4825 221124 01:0-1249; 02:1323-6782; 03:6870-8143; 04:8271-9564 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 6-1249; 7158-8143; 8565-9564 6-1206; 7158-8143 12970
33 H4826 221203 01:0-1293; 02:1410-7091; 03:7134-8410; 04:8573-9877 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 5-1291; 7137-8408; 8576-9875 5-1205; 7137-8337 0
34 H4827 221210 01:0-1253; 02:1367-6849; 03:6881-8104; 04:8210-9551 {'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['4']} 4-1251; 6884-8102; 8213-9550 4-1204; 6884-8084 0
35 H4830 230406 01:0-1286; 02:1365-7715; 03:7762-9071; 04:9202-9726; 05:9841-11252 {'error': ['4'], 'sleep': ['2'], 'wake': ['1', '3'], 'wake_cue_rot': ['5']} 4-1282; 7766-9068 4-1204; 7766-8966 0
The paper describes two 20 min exploration sessions separated by 90 min of sleep. The epochs and
processing/tasks tables do not always say which interval is which: in H3001 (200202) task epoch 1 is
called wake but spans 94 min with no tracking, and tracking starts in epoch 2; in H3026 (211003) epoch
1 spans 112 min, waking and sleep together; H4823 has a single epoch for the whole recording and no
sleep task. The exploration sessions are therefore taken from the tracking itself (helper
exploration_sessions): the first tracking block of at least 10 min, and the first such block starting
at least 60 min later, each cut to its first 20 min, the paper's session length. This gives sessions of
18.7 to 20.0 min (H4825 aside) before and after the sleep in every recording but two, which have one
session: in H3019 210618-1 it is the session before the sleep, and in H3001 200202, where the first
epoch has no tracking, it is the session after the sleep. Juvenile files have one
to three tracking frames whose timestamp does not increase; those frames are dropped.
print(meta[["subject", "session_id", "pos_unit", "px_per_cm", "pos_x_range", "pos_y_range", "hd_range",
"hd_nan_fraction", "pos_nan_frames", "pos_y_zero_frames", "pos_x_zero_frames", "pos_y_zero_in_sessions",
"frame_rate", "same_pos_hd_times"]].round(3).to_string())
cm = meta[meta.px_per_cm.isna()]
print(f"\nfiles in centimetres: {len(cm)}; frames with y exactly 0 per file: {cm.pos_y_zero_frames.min()} to {cm.pos_y_zero_frames.max()}; "
f"with x exactly 0: {cm.pos_x_zero_frames.min()} to {cm.pos_x_zero_frames.max()}")
subject session_id pos_unit px_per_cm pos_x_range pos_y_range hd_range hd_nan_fraction pos_nan_frames pos_y_zero_frames pos_x_zero_frames pos_y_zero_in_sessions frame_rate same_pos_hd_times 0 H3001 200201 centimeters NaN (8.31266532669732, 82.80915102590006) (0.0, 77.67551865990228) (7.14238399568412e-05, 6.28256812966937) 0.021 2695 1 0 1 40.000 True 1 H3001 200202 centimeters NaN (6.22448820083347, 80.97897235802223) (0.0, 77.13461211679251) (0.00010403409831227783, 6.283156330124877) 0.055 4679 1 0 0 40.000 True 2 H3003 200207 centimeters NaN (4.254392715228363, 80.18506162164604) (0.0, 77.45854471385374) (0.0004952033532636957, 6.283165013864346) 0.039 3719 1 0 1 40.000 True 3 H3003 200208 centimeters NaN (3.4855474861168148, 81.0520895575169) (0.0, 78.18793573667719) (4.530233278088325e-05, 6.283160021301904) 0.080 7680 1 0 1 40.000 True 4 H3006 200314_1 centimeters NaN (-39.24912150765691, 34.464865473849684) (0.0, 72.86433259519004) (0.0003887451518203022, 6.283138334831236) 0.106 15161 1 0 1 40.000 True 5 H3006 200314_2 centimeters NaN (14.375590221543582, 89.47698621856365) (0.0, 76.88510371155738) (4.6418587547947254e-05, 6.2831828960513825) 0.043 6124 1 0 1 40.000 True 6 H3008 200805 centimeters NaN (8.774492671201171, 81.8940214232544) (0.0, 72.14764109675988) (5.2320810830508435e-06, 6.2831823010643895) 0.023 2241 1 0 0 40.000 True 7 H3008 200807 centimeters NaN (8.185606118666605, 84.64659002860012) (0.0, 77.97003407569944) (8.043079296626843e-05, 6.283133785275643) 0.028 3981 1 0 1 40.000 True 8 H3009 200812 centimeters NaN (8.650898261755813, 82.89370513959358) (0.0, 73.0496336776173) (0.0, 6.283009891275324) 0.019 2990 1 0 1 40.000 True 9 H3009 200813 centimeters NaN (8.883541202377529, 83.0597001193349) (0.0, 74.17023739575387) (8.186436003931874e-05, 6.283173946419092) 0.008 1342 1 0 1 40.000 True 10 H3015 210416_1 centimeters NaN (8.030519748784684, 83.44728798685426) (0.0, 73.77846052985556) (0.0, 6.283093009314327) 0.076 13577 1 0 1 40.000 True 11 H3015 210416_2 centimeters NaN (9.036820770328164, 83.44904850475226) (0.0, 75.81724615901662) (0.00024195041908914305, 6.283175299725974) 0.077 11996 1 0 1 40.000 True 12 H3015 210417 centimeters 4.144 (34.9044720783133, 337.4283329684605) (20.361810984102, 297.127795725646) (-3.1415833072905026, 3.1415712992061087) 0.400 0 0 0 0 40.000 True 13 H3016 210422 centimeters NaN (11.063705547468544, 82.65281152718646) (0.0, 74.38128255195475) (7.540540872064128e-05, 6.283178568998606) 0.059 9450 1 0 1 40.000 True 14 H3016 210423 centimeters NaN (11.014603461648827, 77.90976770435609) (0.0, 74.17177098557453) (5.6855739115402315e-05, 6.2831503431057385) 0.083 13533 1 0 1 40.000 True 15 H3019 210617 centimeters NaN (15.207432767441558, 88.97083957186678) (0.0, 74.2346535256795) (0.00018347429727438858, 6.283167031810845) 0.045 6902 1 0 0 40.000 True 16 H3019 210618_1 centimeters NaN (15.199594124702942, 88.22278856151468) (0.0, 73.37171874703465) (0.0, 6.282966184644192) 0.087 4275 1 0 1 40.000 True 17 H3022 210805 centimeters NaN (16.329257774411456, 91.68869844884782) (0.0, 76.5807822460626) (8.326341562892026e-07, 6.283154557133571) 0.051 7577 1 0 0 40.000 True 18 H3022 210806 centimeters NaN (15.608237563948148, 89.80491674533724) (0.0, 76.63558213449262) (2.5376911591434848e-05, 6.283092408873632) 0.057 8852 1 0 1 40.000 True 19 H3023 210812 centimeters NaN (15.580864676896242, 90.09896803489272) (0.0, 76.28356322433277) (0.0, 6.2831810265596975) 0.165 24369 1 0 1 40.000 True 20 H3023 210813_1 centimeters NaN (15.013519399429562, 86.36415505380924) (0.0, 72.77644916894586) (2.5739709484939866e-05, 6.283100295276176) 0.138 20359 1 0 1 40.000 True 21 H3026 211003 centimeters NaN (14.50247578673125, 89.05060015278693) (0.0, 75.10842865591968) (0.0, 6.283152070535207) 0.034 5136 1 0 0 40.000 True 22 H3026 211004_2 centimeters NaN (14.784907409236112, 88.9363062579343) (0.0, 75.62380581247196) (3.241062445513698e-05, 6.283160213749489) 0.024 3573 1 0 1 40.000 True 23 H3029 230510 centimeters NaN (5.122948046622813, 78.29719986784227) (0.0, 74.39847056399377) (3.873059906389642e-05, 6.283173743036758) 0.000 32 1 0 0 40.733 True 24 H4813 220728 centimeters NaN (6.046657060012205, 79.91873106190369) (0.0, 74.4253538132477) (9.923120590205059e-05, 6.2830049797350025) 0.004 635 1 0 1 40.706 True 25 H4815 220814 centimeters NaN (6.666092483478095, 83.13545425127765) (0.0, 76.60529243018408) (0.00015325334848093064, 6.2828868044871164) 0.013 2086 1 0 0 40.706 True 26 H4817 220828 centimeters NaN (1.0059734506068396, 81.6526271159901) (0.0, 77.5628218112984) (2.5906918790674638e-05, 6.283127166518011) 0.007 1163 1 0 0 40.706 True 27 H4819 220929 centimeters NaN (3.0620936113660484, 83.48591111438068) (0.0, 76.41338159827286) (0.0001326068079805509, 6.283169816615555) 0.003 478 1 0 1 40.706 True 28 H4820 221007 centimeters NaN (7.16658143094117, 82.86227728119539) (0.0, 76.0333930137787) (8.740303703280716e-05, 6.28318106950539) 0.012 1824 1 0 0 40.706 True 29 H4822 221023 centimeters NaN (0.8311122963891096, 78.35830625316574) (0.0, 77.60691008254867) (3.860355501039692e-06, 6.283037484504581) 0.008 1147 1 0 1 40.706 True 30 H4823 221108 centimeters 9.533 (23.9896775, 732.8469500000001) (12.630911999999999, 728.5544500000001) (-3.141577381556706, 3.141592653589793) 0.108 0 0 0 0 40.706 True 31 H4824 221117 centimeters NaN (2.8797536431714095, 77.11583287827546) (0.0, 75.6462314601414) (0.00014613340048708068, 6.2827676285689105) 0.005 793 1 0 1 40.706 True 32 H4825 221124 centimeters NaN (2.8797536431714095, 77.11583287827546) (0.0, 75.6462314601414) (0.00014613340048708068, 6.2827676285689105) 0.005 793 1 0 1 40.761 True 33 H4826 221203 centimeters NaN (2.836154238347099, 82.22102193616637) (0.0, 78.3684660617393) (0.0002152602611076304, 6.283180722652367) 0.010 1549 1 0 1 40.706 True 34 H4827 221210 centimeters NaN (6.39270567950306, 84.57678479771397) (0.0, 76.0392467112476) (3.5914289056471205e-05, 6.283162798192878) 0.003 455 1 0 1 40.706 True 35 H4830 230406 centimeters NaN (2.564488544058552, 78.40980905397977) (0.0, 82.98412602084385) (7.4395905240720595e-06, 6.283174304766208) 0.005 667 1 0 0 40.733 True files in centimetres: 34; frames with y exactly 0 per file: 1 to 1; with x exactly 0: 0 to 0
Position is stated in centimetres, and in 34 files spans about 72 to 83 cm on each axis, consistent with the 73 cm arena seen from above. In each of these files exactly one frame has y equal to 0 and none has x equal to 0, so the y positions were shifted to start at 0; missing tracking is stored as NaN, not as 0. In two files (H3015 210417 and H4823 221108) it spans 300 and 700 units, so it is in pixels although the file says centimetres (a metadata error); their head direction runs from -pi to pi where the other files run from 0 to 2 pi, and they hold tracking through the sleep. For these two files the scale is set so that the x extent of the exploration tracking equals the arena's 73 cm (4.1 and 9.5 pixels per cm). Tracking is at 40 Hz in juveniles and 40.7 Hz in adults, consistent with the Methods' 40 Hz. H3029 is tracked at 40.7 Hz like the adults, so it was recorded on the adult rig.
ttp = np.concatenate([r["meta"]["ttp"] for r in results if r["meta"]["subject"] not in hdfx.DUPLICATE_OF])
cont = np.concatenate([r["meta"]["contamination"] for r in results if r["meta"]["subject"] not in hdfx.DUPLICATE_OF])
edges = np.arange(0, 1.25, 1 / 30)
h, _ = np.histogram(ttp[~np.isnan(ttp)], edges)
print("trough-to-peak (ms), units per bin of one sample (1/30 ms):")
print(" ".join(f"{e:.2f}:{n}" for e, n in zip(edges, h)))
print(f"range {np.nanmin(ttp):.2f} to {np.nanmax(ttp):.2f} ms; positive waveforms (no duration): {int(np.isnan(ttp).sum())} of {len(ttp)}")
for age, thr in hdfx.TTP_THRESHOLD_MS.items():
sel = np.concatenate([r["meta"]["ttp"] for r in results if r["meta"]["age_group"] == age and r["meta"]["subject"] not in hdfx.DUPLICATE_OF])
print(f"{age}: {np.sum(sel > thr)} of {len(sel)} units above {thr} ms")
print(f"contamination score: median {np.nanmedian(cont):.3f}, range {np.nanmin(cont):.3f} to {np.nanmax(cont):.3f}; "
f"above 0.5: {int(np.sum(cont > 0.5))} units; below 0.5: {int(np.sum(cont < 0.5))}")
fig, ax = plt.subplots(1, 2, figsize=(10, 3))
ax[0].hist(ttp[~np.isnan(ttp)], edges, color="0.4")
ax[0].axvline(0.4, ls="--", c="C1", label="adult 0.4 ms")
ax[0].axvline(0.5, ls="--", c="C0", label="juvenile 0.5 ms")
ax[0].set_xlabel("trough-to-peak (ms)")
ax[0].legend()
ax[1].hist(cont, np.linspace(0, 1, 41), color="0.4")
ax[1].set_xlabel("contamination score")
plt.tight_layout()
plt.show()
trough-to-peak (ms), units per bin of one sample (1/30 ms): 0.00:0 0.03:0 0.07:0 0.10:0 0.13:2 0.17:20 0.20:58 0.23:99 0.27:79 0.30:66 0.33:40 0.37:29 0.40:42 0.43:0 0.47:22 0.50:82 0.53:130 0.57:132 0.60:142 0.63:159 0.67:154 0.70:143 0.73:62 0.77:61 0.80:42 0.83:45 0.87:0 0.90:22 0.93:9 0.97:10 1.00:4 1.03:11 1.07:6 1.10:8 1.13:7 1.17:7 1.20:5 range 0.13 to 1.20 ms; positive waveforms (no duration): 63 of 1761 juvenile: 575 of 778 units above 0.5 ms adult: 688 of 983 units above 0.4 ms contamination score: median 0.064, range 0.000 to 1.000; above 0.5: 34 units; below 0.5: 1727
The trough-to-peak durations are bimodal with the trough between 0.40 and 0.47 ms, consistent with the Methods' thresholds (0.5 ms for juveniles, 0.4 ms for adults). The unit totals match the paper's counts of recorded units (see unit-counts), so the files hold all curated units, not only the putative excitatory ones. The Methods say units with a contamination score "below 0.5" were excluded; almost every unit is below 0.5, so this is read as "above 0.5", which removes few units.
# frame_counts on frames that are not contiguous (speed-filtered), on synthetic spikes
rng = np.random.default_rng(1)
t_all = np.arange(0, 600, 0.025)
keep = rng.random(len(t_all)) > 0.3 # frequent one-frame and longer gaps
t_sel = t_all[keep]
sp = np.sort(rng.uniform(0, 600, 20000))
expected = np.histogram(sp, np.r_[t_all - 0.0125, t_all[-1] + 0.0125])[0][keep]
got = hdfx.frame_counts([sp], t_sel, 0.025)[0]
print(f"spikes in the kept frames: expected {expected.sum()}, counted {int(got.sum())}; "
f"frames with a wrong count: {int(np.sum(got != expected))} of {len(t_sel)}")
assert np.array_equal(got, expected)
spikes in the kept frames: expected 13843, counted 13843; frames with a wrong count: 0 of 16746
frame_counts counts each tracking frame on its own window, so frames kept by a speed filter
need not be contiguous; on synthetic spikes it counts every spike of the kept frames. The first round
of this attempt cut frames at gaps and lost or misplaced spikes there.
lag = pd.DataFrame([r["meta"].get("lag_info", [np.nan] * len(hdfx.CLOCK_LAGS)) for r in results],
columns=[f"{x:g}s" for x in hdfx.CLOCK_LAGS])
lag.insert(0, "session", meta.subject + " " + meta.session_id)
values = lag.iloc[:, 1:].to_numpy(float)
lag["peak_lag_s"] = [hdfx.CLOCK_LAGS[int(np.nanargmax(v))] if np.isfinite(v).any() else np.nan for v in values]
lag["zero_over_60s"] = lag["0s"] / lag[["-60s", "60s"]].max(axis=1)
print("median HD information (bits/spike) of the cells of session 1 with spikes shifted by each lag:")
print(lag.round(3).to_string())
ok = lag.dropna(subset=["0s"])
print(f"\npeak within 0.2 s of zero in {np.sum(ok.peak_lag_s.abs() <= 0.2)} of {len(ok)} recordings;"
f" zero-lag information at least 1.5 times that at +-60 s in {np.sum(ok.zero_over_60s >= 1.5)}")
print("recordings where the clock is not established (ratio below 1.5):", ok.loc[ok.zero_over_60s < 1.5, "session"].tolist())
median HD information (bits/spike) of the cells of session 1 with spikes shifted by each lag:
session -60s -2s -1s -0.5s -0.2s -0.1s 0s 0.1s 0.2s 0.5s 1s 2s 60s peak_lag_s zero_over_60s
0 H3001 200201 0.125 0.222 0.245 0.369 0.494 0.505 0.489 0.479 0.484 0.418 0.364 0.260 0.105 -0.1 3.900
1 H3001 200202 0.076 0.142 0.198 0.228 0.263 0.282 0.318 0.336 0.337 0.305 0.192 0.114 0.056 0.2 4.199
2 H3003 200207 0.023 0.046 0.050 0.051 0.055 0.056 0.060 0.061 0.058 0.052 0.046 0.046 0.017 0.1 2.602
3 H3003 200208 0.034 0.215 0.379 0.564 0.820 0.916 0.949 0.899 0.799 0.459 0.275 0.200 0.056 0.0 17.082
4 H3006 200314_1 0.093 0.116 0.078 0.111 0.128 0.113 0.122 0.111 0.099 0.092 0.095 0.096 0.057 -0.2 1.307
5 H3006 200314_2 0.031 0.048 0.058 0.059 0.061 0.061 0.059 0.060 0.063 0.054 0.049 0.062 0.049 0.2 1.205
6 H3008 200805 0.082 0.442 0.647 0.779 0.968 1.040 1.069 1.028 0.942 0.722 0.520 0.320 0.086 0.0 12.492
7 H3008 200807 0.045 0.161 0.223 0.330 0.413 0.432 0.440 0.453 0.385 0.246 0.177 0.132 0.037 0.1 9.703
8 H3009 200812 0.105 0.278 0.336 0.474 0.610 0.639 0.682 0.695 0.658 0.503 0.359 0.251 0.093 0.1 6.507
9 H3009 200813 0.074 0.158 0.262 0.341 0.442 0.506 0.540 0.524 0.487 0.356 0.225 0.135 0.074 0.0 7.304
10 H3015 210416_1 0.083 0.134 0.165 0.201 0.223 0.227 0.213 0.273 0.248 0.194 0.157 0.116 0.106 0.1 2.003
11 H3015 210416_2 0.068 0.089 0.094 0.104 0.113 0.122 0.134 0.127 0.129 0.119 0.113 0.093 0.089 0.0 1.498
12 H3015 210417 0.104 0.110 0.169 0.185 0.200 0.215 0.239 0.242 0.228 0.222 0.201 0.142 0.069 0.1 2.301
13 H3016 210422 0.245 0.488 0.424 0.679 0.897 1.020 1.113 1.156 1.065 0.736 0.432 0.332 0.153 0.1 4.540
14 H3016 210423 0.064 0.111 0.135 0.227 0.267 0.295 0.316 0.311 0.303 0.216 0.135 0.114 0.044 0.0 4.954
15 H3019 210617 0.028 0.144 0.286 0.353 0.439 0.429 0.425 0.412 0.399 0.276 0.207 0.099 0.018 -0.2 15.393
16 H3019 210618_1 0.017 0.018 0.020 0.024 0.034 0.039 0.042 0.045 0.042 0.037 0.026 0.031 0.019 0.1 2.140
17 H3022 210805 0.051 0.173 0.347 0.569 0.718 0.742 0.755 0.747 0.714 0.554 0.326 0.179 0.052 0.0 14.521
18 H3022 210806 0.033 0.092 0.166 0.198 0.241 0.249 0.274 0.255 0.239 0.213 0.137 0.084 0.039 0.0 7.097
19 H3023 210812 0.014 0.019 0.021 0.023 0.022 0.022 0.023 0.023 0.021 0.021 0.020 0.021 0.012 -0.5 1.650
20 H3023 210813_1 0.024 0.033 0.043 0.046 0.046 0.047 0.047 0.044 0.042 0.044 0.039 0.026 0.014 -0.1 1.953
21 H3026 211003 0.085 0.243 0.353 0.474 0.559 0.617 0.678 0.639 0.560 0.424 0.310 0.209 0.081 0.0 7.994
22 H3026 211004_2 0.064 0.133 0.178 0.275 0.379 0.407 0.442 0.438 0.448 0.276 0.199 0.136 0.062 0.2 6.863
23 H3029 230510 0.039 0.059 0.063 0.076 0.081 0.080 0.083 0.082 0.079 0.071 0.061 0.051 0.050 0.0 1.656
24 H4813 220728 0.061 0.174 0.217 0.278 0.365 0.386 0.418 0.425 0.408 0.340 0.229 0.146 0.050 0.1 6.824
25 H4815 220814 0.064 0.158 0.191 0.224 0.254 0.273 0.282 0.300 0.296 0.260 0.207 0.151 0.054 0.1 4.415
26 H4817 220828 0.042 0.067 0.090 0.136 0.137 0.135 0.120 0.116 0.108 0.097 0.093 0.078 0.049 -0.2 2.434
27 H4819 220929 0.060 0.151 0.208 0.282 0.335 0.346 0.346 0.328 0.322 0.276 0.218 0.155 0.054 0.0 5.812
28 H4820 221007 0.013 0.057 0.060 0.065 0.087 0.089 0.081 0.072 0.059 0.046 0.043 0.031 0.013 -0.1 6.053
29 H4822 221023 0.024 0.030 0.039 0.062 0.086 0.097 0.089 0.087 0.074 0.045 0.041 0.030 0.027 -0.1 3.290
30 H4823 221108 0.049 0.170 0.257 0.341 0.467 0.443 0.416 0.386 0.338 0.263 0.208 0.145 0.051 -0.2 8.192
31 H4824 221117 0.046 0.064 0.099 0.118 0.143 0.153 0.158 0.145 0.136 0.105 0.095 0.063 0.041 0.0 3.402
32 H4825 221124 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
33 H4826 221203 0.074 0.209 0.305 0.412 0.522 0.560 0.575 0.553 0.508 0.369 0.268 0.179 0.088 0.0 6.549
34 H4827 221210 0.042 0.162 0.261 0.376 0.514 0.580 0.618 0.569 0.492 0.341 0.225 0.125 0.049 0.0 12.705
35 H4830 230406 0.027 0.069 0.107 0.138 0.166 0.175 0.186 0.175 0.163 0.130 0.093 0.060 0.020 0.0 6.941
peak within 0.2 s of zero in 34 of 35 recordings; zero-lag information at least 1.5 times that at +-60 s in 32
recordings where the clock is not established (ratio below 1.5): ['H3006 200314_1', 'H3006 200314_2', 'H3015 210416_2']
Spikes and tracking share a clock: with the spikes shifted against the head direction, HD information peaks within 0.2 s of zero lag in 34 of 35 recordings and falls towards its floor at 60 s. In H3023 210812 the information is nearly flat (0.019 to 0.023 bits/spike between -2 and 2 s) and peaks at -0.5 s. In three recordings (H3006 200314-1 and 200314-2, H3015 210416-2), whose cells are weakly tuned, the information at zero lag is less than 1.5 times that at 60 s. For these four a shared clock is consistent with the data but not shown.
emg = pd.DataFrame([r["meta"]["emg_median"] for r in results])
emg.insert(0, "session", meta.subject + " " + meta.session_id)
sleep_s = pd.DataFrame([r["meta"]["sleep_s"] for r in results]).add_suffix("_s")
emg = pd.concat([emg, sleep_s], axis=1)
emg["rem_in_exploration"] = [r["meta"]["rem_in_exploration"] for r in results]
print(emg.round(2).to_string())
print(f"\npseudo-EMG median lower in REM than in wake in {np.sum(emg.rem < emg.wake)} of {len(emg)} files; "
f"REM at or below NREM in {np.sum(emg.rem <= emg.nrem + 1e-9)}")
print(f"REM per file: {emg.rem_s.min():.0f} to {emg.rem_s.max():.0f} s")
session wake nrem rem wake_s nrem_s rem_s rem_in_exploration 0 H3001 200201 0.60 0.45 0.36 1416.00 5525.66 983.00 1 1 H3001 200202 0.67 0.32 0.31 1958.83 4083.00 1706.00 0 2 H3003 200207 0.63 0.42 0.36 3620.57 3211.00 1163.00 0 3 H3003 200208 0.82 0.51 0.40 3742.27 3580.00 1192.00 0 4 H3006 200314_1 0.80 0.48 0.40 5436.14 2828.00 1030.00 0 5 H3006 200314_2 0.88 0.44 0.39 5124.94 3635.03 690.00 0 6 H3008 200805 0.78 0.48 0.44 4713.79 2615.04 640.00 0 7 H3008 200807 0.77 0.41 0.38 5598.60 3255.00 630.00 0 8 H3009 200812 0.89 0.47 0.43 4425.28 3842.76 1035.00 0 9 H3009 200813 0.72 0.38 0.31 4338.63 4438.45 906.00 0 10 H3015 210416_1 0.49 0.44 0.46 4924.37 3396.00 1291.00 2 11 H3015 210416_2 0.53 0.41 0.40 6014.31 2569.29 1004.00 4 12 H3015 210417 0.75 0.53 0.54 4187.02 4648.51 1066.00 0 13 H3016 210422 0.57 0.48 0.43 6044.85 3010.00 689.00 0 14 H3016 210423 0.51 0.46 0.45 5266.58 3712.00 764.00 1 15 H3019 210617 0.49 0.32 0.33 6602.68 2326.00 644.00 0 16 H3019 210618_1 0.68 0.50 0.48 1930.56 1051.00 257.00 0 17 H3022 210805 0.67 0.55 0.33 4493.07 3840.65 1178.00 0 18 H3022 210806 0.56 0.34 0.34 5377.78 2823.00 1409.00 0 19 H3023 210812 0.56 0.42 0.42 5530.99 2885.00 593.00 0 20 H3023 210813_1 0.57 0.46 0.48 4340.09 3379.00 1337.00 1 21 H3026 211003 0.68 0.28 0.19 5463.06 2873.00 850.00 0 22 H3026 211004_2 0.75 0.36 0.22 6226.08 2364.00 539.00 0 23 H3029 230510 0.61 0.47 0.38 5133.01 3285.00 1037.00 0 24 H4813 220728 0.57 0.33 0.29 3947.79 4625.37 988.00 0 25 H4815 220814 0.57 0.33 0.20 5835.50 3463.00 406.00 0 26 H4817 220828 0.65 0.49 0.47 3634.99 4989.00 756.00 0 27 H4819 220929 0.50 0.38 0.35 5456.03 3289.00 819.00 0 28 H4820 221007 0.44 0.16 0.10 6043.68 3184.00 408.00 0 29 H4822 221023 0.45 0.47 0.36 4918.22 3989.00 457.38 3 30 H4823 221108 0.51 0.36 0.31 6971.00 2308.00 116.00 0 31 H4824 221117 0.44 0.31 0.30 5934.04 3350.00 518.00 0 32 H4825 221124 0.34 0.26 0.23 5654.89 3323.00 520.00 3 33 H4826 221203 0.39 0.23 0.21 5786.24 3677.00 337.00 0 34 H4827 221210 0.53 0.38 0.38 6250.73 2832.00 391.00 0 35 H4830 230406 0.47 0.35 0.26 5441.99 5560.00 133.00 0 pseudo-EMG median lower in REM than in wake in 36 of 36 files; REM at or below NREM in 31 REM per file: 116 to 1706 s
The sleep stages are consistent with the pseudo-EMG: its median is lower in REM than in wake in all 36 files, and at or below its NREM median in 31. A few REM intervals overlap the tracking blocks of the exploration sessions (counted above, up to 4 in H3015 210416-2 and 3 in H4822). The REM analyses use every REM interval, as the claims' criterion says, and show the result with those intervals left out as a variant.
Tables used by the claims¶
cells has one row per cell (a putative excitatory unit with contamination at most 0.5 and at least 100
spikes in session 1) and recording; recs has one row per recording. H4825 is left out. The archive
grouping variant uses the archive's genotype, and the archive's age group where the birth date gives one
(H3029 is then adult and its cells are selected with the adult threshold).
cell_rows, rec_rows, arch_rows = [], [], []
first_day = meta[~meta.subject.isin(hdfx.DUPLICATE_OF)].sort_values("session_id").groupby("subject").session_id.first()
for r in results:
m = r["meta"]
if r["main"] is None:
continue
base = {"subject": m["subject"], "session": m["session_id"], "age_group": m["age_group"], "genotype": m["genotype"],
"first_day": first_day[m["subject"]] == m["session_id"]}
rec_rows.append({**base, **r["main"]["rec"]})
c = r["main"]["cells"].copy()
for k, v in base.items():
c[k] = v
cell_rows.append(c)
a_res = r["other_age"] if r["other_age"] is not None else r["main"]
ca = a_res["cells"].copy()
for k, v in base.items():
ca[k] = v
ca["genotype"] = m["archive_genotype"]
ca["age_group"] = m["archive_age_group"] or m["age_group"]
arch_rows.append(ca)
cells = pd.concat(cell_rows, ignore_index=True)
cells_arch = pd.concat(arch_rows, ignore_index=True)
recs = pd.DataFrame(rec_rows)
cells["animal"] = cells.subject
cells_arch["animal"] = cells_arch.subject
print("cells per group (main):")
print(cells.groupby(["age_group", "genotype"]).agg(rats=("subject", "nunique"), recordings=("session", "nunique"), cells=("unit", "size")).to_string())
print("\ncells per group (archive labels):")
print(cells_arch.groupby(["age_group", "genotype"]).agg(rats=("subject", "nunique"), recordings=("session", "nunique"), cells=("unit", "size")).to_string())
print("\nper recording:")
print(recs[["subject", "session", "age_group", "genotype", "n_units", "n_exc_ttp", "n_exc", "n_cells", "n_sessions", "rem_s", "n_cells_rem", "rem_in_sessions", "rem_in_sessions_s"]].to_string())
print("\nranges of the cell measures (main):")
print(cells.describe().T[["count", "min", "50%", "max"]].round(3).to_string())
cells per group (main):
rats recordings cells
age_group genotype
adult KO 5 5 282
WT 6 6 395
juvenile KO 5 10 237
WT 7 14 323
cells per group (archive labels):
rats recordings cells
age_group genotype
adult KO 5 5 282
WT 7 7 420
juvenile KO 4 8 145
WT 7 15 393
per recording:
subject session age_group genotype n_units n_exc_ttp n_exc n_cells n_sessions rem_s n_cells_rem rem_in_sessions rem_in_sessions_s
0 H3001 200201 juvenile WT 23 18 18 18 2 983.000000 18.0 1.0 14.000000
1 H3001 200202 juvenile WT 16 13 13 13 1 1706.000000 13.0 0.0 0.000000
2 H3003 200207 juvenile KO 40 33 33 33 2 1163.000000 32.0 0.0 0.000000
3 H3003 200208 juvenile KO 29 20 19 19 2 1192.000000 19.0 0.0 0.000000
4 H3006 200314_1 juvenile WT 37 30 29 28 2 1030.000000 28.0 0.0 0.000000
5 H3006 200314_2 juvenile WT 26 23 23 23 2 690.000000 23.0 0.0 0.000000
6 H3008 200805 juvenile KO 38 25 24 24 2 640.000000 24.0 0.0 0.000000
7 H3008 200807 juvenile KO 16 13 13 13 2 630.000000 13.0 0.0 0.000000
8 H3009 200812 juvenile WT 37 30 30 30 2 1035.000000 30.0 0.0 0.000000
9 H3009 200813 juvenile WT 33 26 26 26 2 906.000000 26.0 0.0 0.000000
10 H3015 210416_1 juvenile WT 34 27 27 27 2 1291.000000 27.0 2.0 21.000000
11 H3015 210416_2 juvenile WT 45 34 33 33 2 1004.000000 33.0 4.0 49.000000
12 H3015 210417 juvenile WT 26 15 15 15 2 1066.000000 15.0 0.0 0.000000
13 H3016 210422 juvenile KO 27 11 11 11 2 689.000000 11.0 0.0 0.000000
14 H3016 210423 juvenile KO 46 36 35 30 2 764.000000 30.0 1.0 13.000000
15 H3019 210617 juvenile KO 17 12 12 10 2 644.000000 10.0 0.0 0.000000
16 H3019 210618_1 juvenile KO 8 5 5 5 1 NaN NaN NaN NaN
17 H3022 210805 juvenile WT 20 18 18 18 2 1178.000000 18.0 0.0 0.000000
18 H3022 210806 juvenile WT 31 29 29 29 2 1409.000000 29.0 0.0 0.000000
19 H3023 210812 juvenile WT 22 19 19 19 2 593.000000 19.0 0.0 0.000000
20 H3023 210813_1 juvenile WT 24 22 22 22 2 1337.000000 22.0 1.0 13.000000
21 H3026 211003 juvenile KO 83 50 49 49 2 850.000000 49.0 0.0 0.000000
22 H3026 211004_2 juvenile KO 68 44 43 43 2 539.000000 43.0 0.0 0.000000
23 H3029 230510 juvenile WT 32 22 22 22 2 1037.000000 22.0 0.0 0.000000
24 H4813 220728 adult WT 70 54 54 54 2 988.000000 54.0 0.0 0.000000
25 H4815 220814 adult WT 99 76 76 76 2 406.000000 76.0 0.0 0.000000
26 H4817 220828 adult KO 105 73 72 72 2 756.000000 72.0 0.0 0.000000
27 H4819 220929 adult KO 114 74 74 71 2 819.000000 70.0 0.0 0.000000
28 H4820 221007 adult WT 63 52 51 51 2 408.000000 51.0 0.0 0.000000
29 H4822 221023 adult KO 55 30 30 30 2 457.380767 29.0 3.0 196.380767
30 H4823 221108 adult WT 113 81 81 80 2 116.000000 63.0 0.0 0.000000
31 H4824 221117 adult KO 88 58 57 57 2 518.000000 57.0 0.0 0.000000
32 H4826 221203 adult WT 102 73 72 72 2 337.000000 72.0 0.0 0.000000
33 H4827 221210 adult KO 78 54 52 52 2 391.000000 52.0 0.0 0.000000
34 H4830 230406 adult WT 96 63 62 62 2 133.000000 62.0 0.0 0.000000
ranges of the cell measures (main):
count min 50% max
unit 1237.0 0.000 26.000 113.000
ttp 1237.0 0.433 0.633 1.200
contamination 1237.0 0.000 0.065 0.487
n_spikes_s1 1237.0 100.000 3087.000 47907.000
mean_rate 1237.0 0.083 2.572 39.922
hd_info 1237.0 0.003 0.277 3.552
hd_info_uniform 1237.0 0.003 0.319 2.617
half_width 1237.0 16.000 66.000 360.000
vector_length 1237.0 0.008 0.288 0.966
peak_rate 1237.0 0.251 8.333 58.560
info_half1 1237.0 0.000 0.320 4.166
info_half2 1237.0 0.004 0.369 4.252
offset_halves 1236.0 0.000 22.000 179.000
n_spikes_s2 1219.0 0.000 2870.000 56477.000
info_s2 1205.0 0.003 0.306 3.554
offset_epochs 1205.0 0.000 32.000 180.000
iso_wake_info 1232.0 0.003 0.312 2.639
real200_info 1232.0 0.001 0.236 3.560
n_spikes_rem 1232.0 0.000 2193.500 32665.000
iso_rem_info 1212.0 0.002 0.313 2.660
iso_rem_info_outside 1212.0 0.002 0.303 2.660
def lme_variants(value, age, higher="KO", log_ok=True, uniform_col=None, extra=None):
'''The LME test and its variants for one cell measure in one age group.'''
d = cells[cells.age_group == age]
rows = []
def add(name, df, col=value, log=False):
coef, p, n = hdfx.lme_lrt(df, col, log=log)
rows.append({"test": name, "n": n, "coef_KO_minus_WT": coef, "p": p})
add("LME (main)", d)
if log_ok:
add("LME on log values", d, log=True)
if not d.first_day.all():
add("LME, first day of each rat", d[d.first_day])
add("LME, archive labels", cells_arch[cells_arch.age_group == age])
if age == "juvenile":
add("LME, H3026 left out", d[d.subject != "H3026"])
if uniform_col:
add("LME, uniform occupancy (v2)", d, col=uniform_col)
if extra is not None:
add(*extra)
ko, wt = d.loc[d.genotype == "KO", value].dropna(), d.loc[d.genotype == "WT", value].dropna()
mw = stats.mannwhitneyu(ko, wt)
rows.append({"test": "Mann-Whitney on cells", "n": len(ko) + len(wt), "coef_KO_minus_WT": ko.median() - wt.median(), "p": mw.pvalue})
am = d.groupby(["animal", "genotype"])[value].mean().reset_index()
tt = stats.ttest_ind(am.loc[am.genotype == "KO", value], am.loc[am.genotype == "WT", value])
rows.append({"test": f"t-test on animal means, t({len(am) - 2}) = {tt.statistic:.2f}", "n": len(am),
"coef_KO_minus_WT": am.loc[am.genotype == "KO", value].mean() - am.loc[am.genotype == "WT", value].mean(), "p": tt.pvalue})
out = pd.DataFrame(rows)
summ = d.groupby("genotype")[value].agg(["count", "median", "mean", "min", "max"])
per_animal = d.groupby(["genotype", "animal"])[value].agg(["count", "median", "mean"])
return out, summ, per_animal
def show(value, age, **kw):
out, summ, per_animal = lme_variants(value, age, **kw)
print(f"{value}, {age}: cells by genotype")
print(summ.round(3).to_string())
print("\nper rat")
print(per_animal.round(3).to_string())
print("\ntests")
print(out.round(4).to_string())
return out
def corr(age, x, y, df=None):
d = (cells if df is None else df)
d = d[d.age_group == age].dropna(subset=[x, y])
rows = []
for g in ("WT", "KO"):
e = d[d.genotype == g]
r, p = stats.pearsonr(e[x], e[y])
f = e[e.first_day]
rows.append({"genotype": g, "cells": len(e), "rats": e.animal.nunique(), "r": r, "p": p,
"spearman": stats.spearmanr(e[x], e[y])[0],
"r_first_day": stats.pearsonr(f[x], f[y])[0], "cells_first_day": len(f),
"x_range": (round(e[x].min(), 3), round(e[x].max(), 3)), "y_range": (round(e[y].min(), 3), round(e[y].max(), 3))})
return pd.DataFrame(rows)
def scatter(age, x, y, xlabel, ylabel):
"""Per-cell scatter of y against x by genotype, cells of later days marked."""
d = cells[cells.age_group == age].dropna(subset=[x, y])
fig, ax = plt.subplots(1, 2, figsize=(9, 4), sharex=True, sharey=True)
for k, g in enumerate(("WT", "KO")):
e = d[d.genotype == g]
for first, mk, lab in ((True, "o", "first day"), (False, "x", "later day")):
f = e[e.first_day == first]
ax[k].scatter(f[x], f[y], s=8, marker=mk, alpha=0.6, label=lab)
hi = max(d[x].max(), d[y].max())
ax[k].plot([0, hi], [0, hi], c="0.6", lw=0.8)
ax[k].set_title(f"{age} {g}")
ax[k].set_xlabel(xlabel)
ax[0].set_ylabel(ylabel)
ax[0].legend()
plt.tight_layout()
plt.show()
print(f"plotted ranges: {x} {d[x].min():.3f} to {d[x].max():.3f}; {y} {d[y].min():.3f} to {d[y].max():.3f} (no point outside the axes)")
e = d.assign(diff=(d[y] - d[x]).abs()).sort_values("diff", ascending=False)
print("the ten cells farthest from the diagonal:")
print(e[["subject", "session", "genotype", "unit", "first_day", x, y, "diff"]].head(10).round(3).to_string())
unit-counts¶
406 units were recorded from 7 juvenile WT rats and 372 from 5 juvenile Fmr1-/y rats; 543 units from 6 adult WT rats and 507 from 6 adult Fmr1-/y rats.
expected = {("juvenile", "WT"): (406, 7), ("juvenile", "KO"): (372, 5), ("adult", "WT"): (543, 6), ("adult", "KO"): (507, 6)}
exc_units = pd.Series({(r["meta"]["subject"], r["meta"]["session_id"]): r["main"]["rec"]["n_exc_ttp"] for r in results if r["main"] is not None})
def table(df, age_col, geno_col, reading):
rows = []
for (age, geno), (eu, er) in expected.items():
d = df[(df[age_col] == age) & (df[geno_col] == geno)]
n = d.n_units.sum() if reading == "a" else sum(exc_units.get((s, ss), 0) for s, ss in zip(d.subject, d.session_id))
rows.append({"group": f"{age} {geno}", "units": n, "paper_units": eu, "units_ok": abs(n - eu) <= 0.1 * eu,
"rats": d.subject.nunique(), "paper_rats": er, "rats_ok": abs(d.subject.nunique() - er) <= 0.1 * er})
t = pd.DataFrame(rows)
t["group_ok"] = t.units_ok & t.rats_ok
return t
for reading in ("a", "b"):
t = table(once, "age_group", "genotype", reading)
print(f"main grouping, reading ({reading}) {'all units' if reading == 'a' else 'putative excitatory units'}:")
print(t.to_string(), "\ngroups matching:", int(t.group_ok.sum()), "of 4\n")
print("variant, archive labels (all units, each file once):")
print(table(arch[~arch.subject.isin(hdfx.DUPLICATE_OF)], "archive_age_group", "archive_genotype", "a").to_string())
print("\nvariant, main grouping counting H4825's file as a recording of its own (all units):")
print(table(meta, "age_group", "genotype", "a").to_string())
main grouping, reading (a) all units:
group units paper_units units_ok rats paper_rats rats_ok group_ok
0 juvenile WT 406 406 True 7 7 True True
1 juvenile KO 372 372 True 5 5 True True
2 adult WT 543 543 True 6 6 True True
3 adult KO 440 507 False 5 6 False False
groups matching: 3 of 4
main grouping, reading (b) putative excitatory units:
group units paper_units units_ok rats paper_rats rats_ok group_ok
0 juvenile WT 326 406 False 7 7 True False
1 juvenile KO 249 372 False 5 5 True False
2 adult WT 399 543 False 6 6 True False
3 adult KO 289 507 False 5 6 False False
groups matching: 0 of 4
variant, archive labels (all units, each file once):
group units paper_units units_ok rats paper_rats rats_ok group_ok
0 juvenile WT 328 406 False 5 7 False False
1 juvenile KO 221 372 False 4 5 False False
2 adult WT 575 543 True 7 6 False False
3 adult KO 440 507 False 5 6 False False
variant, main grouping counting H4825's file as a recording of its own (all units):
group units paper_units units_ok rats paper_rats rats_ok group_ok
0 juvenile WT 406 406 True 7 7 True True
1 juvenile KO 372 372 True 5 5 True True
2 adult WT 543 543 True 6 6 True True
3 adult KO 528 507 True 6 6 True True
Result: partially reproduced. Counting every unit of each recording once, the juvenile WT (406 units, 7 rats), juvenile Fmr1-/y (372, 5) and adult WT (543, 6) groups match the paper exactly, with H3026 taken as Fmr1-/y and H3029 as a juvenile. The adult Fmr1-/y group has 440 units in 5 rats against 507 in 6, because H4825's file holds H4824's recording. Counting H4825's file as a recording of its own gives 528 units in 6 rats, within the tolerance, but it counts one recording twice. As putative excitatory units no group matches, and with the archive's labels no group matches.
units-per-recording¶
Juvenile recordings held 8 to 83 putative excitatory units each, adult recordings 30 to 114.
rr = recs.copy()
rows = []
for reading, col in (("a all units", "n_units"), ("b putative excitatory (trough-to-peak)", "n_exc_ttp"), ("c cells of session 1", "n_cells")):
for age, (lo, hi) in (("juvenile", (8, 83)), ("adult", (30, 114))):
d = rr[rr.age_group == age][col]
rows.append({"reading": reading, "age": age, "min": d.min(), "max": d.max(), "paper": f"{lo} to {hi}",
"min_ok": abs(d.min() - lo) <= 0.1 * lo, "max_ok": abs(d.max() - hi) <= 0.1 * hi})
print(pd.DataFrame(rows).to_string())
print("\nadult recordings sorted by units:", rr[rr.age_group == "adult"].sort_values("n_units")[["subject", "n_units", "n_exc_ttp", "n_cells"]].values.tolist())
reading age min max paper min_ok max_ok 0 a all units juvenile 8 83 8 to 83 True True 1 a all units adult 55 114 30 to 114 False True 2 b putative excitatory (trough-to-peak) juvenile 5 50 8 to 83 False False 3 b putative excitatory (trough-to-peak) adult 30 81 30 to 114 True False 4 c cells of session 1 juvenile 5 49 8 to 83 False False 5 c cells of session 1 adult 30 80 30 to 114 True False adult recordings sorted by units: [['H4822', 55, 30, 30], ['H4820', 63, 52, 51], ['H4813', 70, 54, 54], ['H4827', 78, 54, 52], ['H4824', 88, 58, 57], ['H4830', 96, 63, 62], ['H4815', 99, 76, 76], ['H4826', 102, 73, 72], ['H4817', 105, 73, 72], ['H4823', 113, 81, 80], ['H4819', 114, 74, 71]]
Result: partially reproduced. Counting all units, the juvenile recordings hold 8 to 83, as the paper says, and the adult ones 55 to 114, so the adult minimum differs. As putative excitatory units by trough-to-peak duration, the ranges are 5 to 50 (juvenile) and 30 to 81 (adult). The paper's juvenile range and adult maximum are counts of all units, and its adult minimum is the count of putative excitatory units in H4822, so the reported ranges mix the two readings.
figs1c-juvenile-behaviour-similar and figs2c-adult-behaviour-similar¶
Juvenile (and adult) Fmr1-/y and WT rats do not differ in the time spent inactive, the time spent in the centre of the arena, or the speed while active.
def behaviour(age):
d = recs[recs.age_group == age].groupby(["subject", "genotype"])[["inactive", "centre", "active_speed"]].mean().reset_index()
rows = []
for col in ("inactive", "centre", "active_speed"):
ko, wt = d.loc[d.genotype == "KO", col], d.loc[d.genotype == "WT", col]
t = stats.ttest_ind(ko, wt)
rows.append({"measure": col, "WT_mean": wt.mean(), "KO_mean": ko.mean(), "WT_range": (round(wt.min(), 3), round(wt.max(), 3)),
"KO_range": (round(ko.min(), 3), round(ko.max(), 3)), "df": len(d) - 2, "t": t.statistic, "p": t.pvalue})
return d, pd.DataFrame(rows)
for age in ("juvenile", "adult"):
d, t = behaviour(age)
print(f"{age}: per rat (fractions of tracked time; speed in cm/s)")
print(d.round(3).to_string())
print(t.round(4).to_string(), "\n")
print("variants of the thresholds (rat means): inactive and active at 2 cm/s; centre disc of radius one third of the diameter")
for age in ("juvenile", "adult"):
d = recs[recs.age_group == age].groupby(["subject", "genotype"])[["inactive_2", "centre_third", "active_speed_2"]].mean().reset_index()
for col in ("inactive_2", "centre_third", "active_speed_2"):
tt = stats.ttest_ind(d.loc[d.genotype == "KO", col], d.loc[d.genotype == "WT", col])
print(f" {age} {col}: WT {d.loc[d.genotype == 'WT', col].mean():.3f}, KO {d.loc[d.genotype == 'KO', col].mean():.3f}, t({len(d) - 2}) = {tt.statistic:.2f}, p = {tt.pvalue:.4f}")
print("variants: first day of each rat only")
for age in ("juvenile", "adult"):
keep = recs.first_day
d = recs[keep & (recs.age_group == age)]
for col in ("inactive", "centre", "active_speed"):
tt = stats.ttest_ind(d.loc[d.genotype == "KO", col], d.loc[d.genotype == "WT", col])
print(f" {age} {col}: t({len(d) - 2}) = {tt.statistic:.2f}, p = {tt.pvalue:.4f}")
juvenile: per rat (fractions of tracked time; speed in cm/s)
subject genotype inactive centre active_speed
0 H3001 WT 0.358 0.015 4.778
1 H3003 KO 0.099 0.052 7.359
2 H3006 WT 0.431 0.149 4.149
3 H3008 KO 0.057 0.261 5.714
4 H3009 WT 0.181 0.222 5.038
5 H3015 WT 0.122 0.013 4.485
6 H3016 KO 0.248 0.136 4.866
7 H3019 KO 0.037 0.153 5.158
8 H3022 WT 0.056 0.108 5.219
9 H3023 WT 0.066 0.011 4.972
10 H3026 KO 0.092 0.300 5.621
11 H3029 WT 0.024 0.067 5.504
measure WT_mean KO_mean WT_range KO_range df t p
0 inactive 0.1769 0.1068 (0.024, 0.431) (0.037, 0.248) 10 -0.8951 0.3918
1 centre 0.0836 0.1802 (0.011, 0.222) (0.052, 0.3) 10 1.8562 0.0931
2 active_speed 4.8778 5.7435 (4.149, 5.504) (4.866, 7.359) 10 2.0957 0.0625
adult: per rat (fractions of tracked time; speed in cm/s)
subject genotype inactive centre active_speed
0 H4813 WT 0.118 0.563 6.996
1 H4815 WT 0.089 0.065 6.582
2 H4817 KO 0.144 0.128 6.712
3 H4819 KO 0.121 0.047 6.833
4 H4820 WT 0.108 0.105 8.570
5 H4822 KO 0.110 0.052 8.254
6 H4823 WT 0.245 0.180 6.116
7 H4824 KO 0.223 0.206 7.017
8 H4826 WT 0.276 0.030 7.079
9 H4827 KO 0.145 0.051 9.132
10 H4830 WT 0.021 0.175 8.677
measure WT_mean KO_mean WT_range KO_range df t p
0 inactive 0.1430 0.1484 (0.021, 0.276) (0.11, 0.223) 9 0.1136 0.9120
1 centre 0.1863 0.0967 (0.03, 0.563) (0.047, 0.206) 9 -0.9750 0.3550
2 active_speed 7.3369 7.5898 (6.116, 8.677) (6.712, 9.132) 9 0.3953 0.7018
variants of the thresholds (rat means): inactive and active at 2 cm/s; centre disc of radius one third of the diameter
juvenile inactive_2: WT 0.465, KO 0.370, t(10) = -1.23, p = 0.2456
juvenile centre_third: WT 0.140, KO 0.278, t(10) = 1.76, p = 0.1096
juvenile active_speed_2: WT 6.823, KO 7.560, t(10) = 1.19, p = 0.2601
adult inactive_2: WT 0.345, KO 0.362, t(9) = 0.26, p = 0.8023
adult centre_third: WT 0.273, KO 0.233, t(9) = -0.34, p = 0.7419
adult active_speed_2: WT 9.225, KO 9.678, t(9) = 0.68, p = 0.5127
variants: first day of each rat only
juvenile inactive: t(10) = -0.82, p = 0.4318
juvenile centre: t(10) = 1.56, p = 0.1506
juvenile active_speed: t(10) = 2.45, p = 0.0342
adult inactive: t(9) = 0.11, p = 0.9120
adult centre: t(9) = -0.97, p = 0.3550
adult active_speed: t(9) = 0.40, p = 0.7018
Result: figs1c-juvenile-behaviour-similar reproduced; figs2c-adult-behaviour-similar reproduced. In juveniles no measure differs by t-test on rat means at 0.05: time inactive p = 0.39, time in the centre p = 0.093, speed while active p = 0.063 (Fmr1-/y 5.74 against WT 4.88 cm/s). The active speed differs with the first day of each rat alone (p = 0.034), so the absence of a speed difference is fragile; with thresholds of 2 cm/s and a centre disc of a third of the diameter, p = 0.25, 0.11 and 0.26. In adults none differs (p = 0.91, 0.355 and 0.70).
figs1-juvenile-cell-metrics-similar and figs2-adult-cell-metrics-similar¶
Cluster contamination, mean and peak firing rates, and resultant vector length of PoSub cells do not differ between genotypes (juveniles, Figure S1f-i; adults, Figure S2f-i).
metric_tests = {}
for age in ("juvenile", "adult"):
for col in ("contamination", "mean_rate", "peak_rate", "vector_length"):
print("=" * 100)
metric_tests[(age, col)] = show(col, age, log_ok=col != "contamination")
print("\nmain LME p per measure:")
print(pd.Series({k: v.loc[0, "p"] for k, v in metric_tests.items()}).round(4).to_string())
====================================================================================================
contamination, juvenile: cells by genotype
count median mean min max
genotype
KO 237 0.055 0.080 0.0 0.474
WT 323 0.062 0.083 0.0 0.444
per rat
count median mean
genotype animal
KO H3003 52 0.052 0.063
H3008 37 0.033 0.042
H3016 41 0.091 0.104
H3019 15 0.059 0.098
H3026 92 0.059 0.090
WT H3001 31 0.062 0.061
H3006 51 0.036 0.068
H3009 56 0.016 0.045
H3015 75 0.076 0.095
H3022 47 0.074 0.099
H3023 41 0.101 0.117
H3029 22 0.103 0.108
tests
test n coef_KO_minus_WT p
0 LME (main) 560 -0.0053 0.7092
1 LME, first day of each rat 289 -0.0044 0.8025
2 LME, archive labels 538 -0.0074 0.6283
3 LME, H3026 left out 468 -0.0088 0.5813
4 Mann-Whitney on cells 560 -0.0071 0.4959
5 t-test on animal means, t(10) = -0.33 12 -0.0051 0.7484
====================================================================================================
mean_rate, juvenile: cells by genotype
count median mean min max
genotype
KO 237 1.644 3.092 0.083 22.928
WT 323 2.140 3.358 0.111 18.146
per rat
count median mean
genotype animal
KO H3003 52 2.423 5.574
H3008 37 2.787 4.005
H3016 41 1.169 1.306
H3019 15 2.900 3.149
H3026 92 1.340 2.109
WT H3001 31 3.632 4.031
H3006 51 2.976 3.846
H3009 56 1.299 1.842
H3015 75 1.025 1.648
H3022 47 2.653 3.025
H3023 41 8.230 8.040
H3029 22 2.292 2.953
tests
test n coef_KO_minus_WT p
0 LME (main) 560 -0.3894 0.7154
1 LME on log values 560 -0.2427 0.4237
2 LME, first day of each rat 289 -0.3630 0.7555
3 LME, archive labels 538 0.0383 0.9744
4 LME, H3026 left out 468 -0.0901 0.9388
5 Mann-Whitney on cells 560 -0.4958 0.0377
6 t-test on animal means, t(10) = -0.35 12 -0.3979 0.7368
====================================================================================================
peak_rate, juvenile: cells by genotype
count median mean min max
genotype
KO 237 7.114 9.307 0.265 40.673
WT 323 7.932 9.961 0.493 58.560
per rat
count median mean
genotype animal
KO H3003 52 10.054 11.050
H3008 37 13.471 14.282
H3016 41 5.073 5.994
H3019 15 8.104 7.646
H3026 92 5.983 8.068
WT H3001 31 14.481 16.529
H3006 51 11.970 15.566
H3009 56 6.514 7.588
H3015 75 3.084 4.230
H3022 47 9.074 10.130
H3023 41 13.104 13.255
H3029 22 5.493 6.792
tests
test n coef_KO_minus_WT p
0 LME (main) 560 -1.1304 0.6163
1 LME on log values 560 -0.0970 0.7145
2 LME, first day of each rat 289 -1.4180 0.5996
3 LME, archive labels 538 -0.8947 0.7152
4 LME, H3026 left out 468 -0.7694 0.7593
5 Mann-Whitney on cells 560 -0.8184 0.7102
6 t-test on animal means, t(10) = -0.48 12 -1.1764 0.6407
====================================================================================================
vector_length, juvenile: cells by genotype
count median mean min max
genotype
KO 237 0.425 0.440 0.008 0.966
WT 323 0.265 0.338 0.013 0.947
per rat
count median mean
genotype animal
KO H3003 52 0.400 0.394
H3008 37 0.504 0.549
H3016 41 0.348 0.412
H3019 15 0.170 0.289
H3026 92 0.440 0.460
WT H3001 31 0.409 0.402
H3006 51 0.337 0.344
H3009 56 0.490 0.501
H3015 75 0.256 0.295
H3022 47 0.319 0.393
H3023 41 0.099 0.157
H3029 22 0.161 0.191
tests
test n coef_KO_minus_WT p
0 LME (main) 560 0.0981 0.1116
1 LME on log values 560 0.2295 0.2722
2 LME, first day of each rat 289 0.1016 0.2187
3 LME, archive labels 538 0.0520 0.4205
4 LME, H3026 left out 468 0.0882 0.1978
5 Mann-Whitney on cells 560 0.1596 0.0001
6 t-test on animal means, t(10) = 1.45 12 0.0948 0.1779
====================================================================================================
contamination, adult: cells by genotype
count median mean min max
genotype
KO 282 0.063 0.089 0.0 0.475
WT 395 0.077 0.102 0.0 0.487
per rat
count median mean
genotype animal
KO H4817 72 0.072 0.097
H4819 71 0.061 0.093
H4822 30 0.037 0.069
H4824 57 0.080 0.100
H4827 52 0.044 0.075
WT H4813 54 0.055 0.086
H4815 76 0.058 0.084
H4820 51 0.113 0.132
H4823 80 0.090 0.108
H4826 72 0.072 0.099
H4830 62 0.086 0.110
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -0.0135 0.1110
1 LME, archive labels 702 -0.0147 0.0771
2 Mann-Whitney on cells 677 -0.0141 0.0992
3 t-test on animal means, t(9) = -1.68 11 -0.0166 0.1274
====================================================================================================
mean_rate, adult: cells by genotype
count median mean min max
genotype
KO 282 2.839 3.555 0.172 20.981
WT 395 3.198 4.113 0.108 39.922
per rat
count median mean
genotype animal
KO H4817 72 2.629 3.180
H4819 71 3.065 4.283
H4822 30 2.410 3.375
H4824 57 3.065 3.866
H4827 52 2.363 2.842
WT H4813 54 3.190 3.609
H4815 76 3.297 3.742
H4820 51 6.622 8.058
H4823 80 2.279 3.003
H4826 72 2.326 2.995
H4830 62 3.668 4.493
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -0.7819 0.3408
1 LME on log values 677 -0.1983 0.2879
2 LME, archive labels 702 -0.6084 0.4391
3 Mann-Whitney on cells 677 -0.3592 0.0219
4 t-test on animal means, t(9) = -0.90 11 -0.8074 0.3901
====================================================================================================
peak_rate, adult: cells by genotype
count median mean min max
genotype
KO 282 8.073 9.510 0.575 49.447
WT 395 9.338 11.247 0.251 55.449
per rat
count median mean
genotype animal
KO H4817 72 5.650 7.171
H4819 71 10.624 12.615
H4822 30 5.205 5.852
H4824 57 9.524 9.824
H4827 52 9.410 10.277
WT H4813 54 9.774 11.539
H4815 76 9.455 11.600
H4820 51 12.271 14.588
H4823 80 6.868 8.675
H4826 72 8.864 12.037
H4830 62 8.803 10.212
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -2.1479 0.1006
1 LME on log values 677 -0.2110 0.1643
2 LME, archive labels 702 -1.5943 0.2476
3 Mann-Whitney on cells 677 -1.2642 0.0026
4 t-test on animal means, t(9) = -1.64 11 -2.2940 0.1353
====================================================================================================
vector_length, adult: cells by genotype
count median mean min max
genotype
KO 282 0.244 0.291 0.010 0.936
WT 395 0.293 0.351 0.009 0.946
per rat
count median mean
genotype animal
KO H4817 72 0.175 0.217
H4819 71 0.385 0.376
H4822 30 0.118 0.139
H4824 57 0.216 0.238
H4827 52 0.400 0.426
WT H4813 54 0.294 0.355
H4815 76 0.332 0.375
H4820 51 0.137 0.204
H4823 80 0.307 0.356
H4826 72 0.413 0.444
H4830 62 0.281 0.322
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -0.0619 0.2552
1 LME on log values 677 -0.2112 0.2583
2 LME, archive labels 702 -0.0414 0.4551
3 Mann-Whitney on cells 677 -0.0498 0.0032
4 t-test on animal means, t(9) = -1.06 11 -0.0635 0.3151
main LME p per measure:
juvenile contamination 0.7092
mean_rate 0.7154
peak_rate 0.6163
vector_length 0.1116
adult contamination 0.1110
mean_rate 0.3408
peak_rate 0.1006
vector_length 0.2552
Result: figs1-juvenile-cell-metrics-similar reproduced; figs2-adult-cell-metrics-similar reproduced. No main LME test finds a genotype effect on contamination, mean rate, peak rate or vector length (juveniles p = 0.11 to 0.72; adults p = 0.10 to 0.34). Mann-Whitney tests on cells, which ignore the rat, find differences in juvenile mean rate (p = 0.038) and vector length (p = 0.0001), and in adult mean rate, peak rate and vector length (p = 0.022, 0.0026 and 0.0032).
fig1ef-juvenile-sharper-tuning¶
PoSub cells of juvenile Fmr1-/y rats are more sharply tuned to head direction than those of WT littermates, with higher HD information and narrower tuning curves.
t_info = show("hd_info", "juvenile", uniform_col="hd_info_uniform")
print("=" * 100)
t_hw = show("half_width", "juvenile")
d = cells[cells.age_group == "juvenile"]
print("\nfraction of cells with half-width below 120 degrees:", d.groupby("genotype").half_width.apply(lambda x: np.mean(x < 120)).round(3).to_dict())
print("cells with half-width 360 (never below half maximum):", d.groupby("genotype").half_width.apply(lambda x: int(np.sum(x >= 360))).to_dict())
fig, ax = plt.subplots(1, 2, figsize=(10, 3))
for i, (col, lab) in enumerate((("hd_info", "HD info (bits/spike)"), ("half_width", "half-width (deg)"))):
for g, c in (("WT", "0.5"), ("KO", "C3")):
ax[i].hist(d.loc[d.genotype == g, col], 30, histtype="step", color=c, density=True, label=g)
ax[i].set_xlabel(lab)
ax[0].legend()
plt.tight_layout()
plt.show()
print("plotted ranges: HD info", d.hd_info.min().round(3), "to", d.hd_info.max().round(3), "; half-width", d.half_width.min(), "to", d.half_width.max())
hd_info, juvenile: cells by genotype
count median mean min max
genotype
KO 237 0.596 0.798 0.004 3.552
WT 323 0.189 0.435 0.006 3.176
per rat
count median mean
genotype animal
KO H3003 52 0.443 0.641
H3008 37 0.727 1.055
H3016 41 0.456 0.740
H3019 15 0.201 0.422
H3026 92 0.646 0.869
WT H3001 31 0.381 0.565
H3006 51 0.119 0.304
H3009 56 0.653 0.907
H3015 75 0.161 0.262
H3022 47 0.356 0.590
H3023 41 0.026 0.125
H3029 22 0.083 0.180
tests
test n coef_KO_minus_WT p
0 LME (main) 560 0.3376 0.0303
1 LME on log values 560 0.6512 0.1185
2 LME, first day of each rat 289 0.4728 0.0354
3 LME, archive labels 538 0.2074 0.2311
4 LME, H3026 left out 468 0.3046 0.0722
5 LME, uniform occupancy (v2) 560 0.2705 0.0811
6 Mann-Whitney on cells 560 0.4074 0.0000
7 t-test on animal means, t(10) = 2.11 12 0.3263 0.0610
====================================================================================================
half_width, juvenile: cells by genotype
count median mean min max
genotype
KO 237 50.0 99.451 20.0 360.0
WT 323 62.0 114.272 16.0 360.0
per rat
count median mean
genotype animal
KO H3003 52 105.0 162.462
H3008 37 50.0 92.486
H3016 41 42.0 64.341
H3019 15 72.0 126.133
H3026 92 42.0 77.935
WT H3001 31 66.0 111.613
H3006 51 38.0 93.647
H3009 56 51.0 68.607
H3015 75 58.0 86.107
H3022 47 60.0 93.702
H3023 41 360.0 257.317
H3029 22 133.0 155.455
tests
test n coef_KO_minus_WT p
0 LME (main) 560 -18.8909 0.5371
1 LME on log values 560 -0.1377 0.5739
2 LME, first day of each rat 289 -15.1172 0.7028
3 LME, archive labels 538 -0.9320 0.9779
4 LME, H3026 left out 468 -11.7979 0.7272
5 Mann-Whitney on cells 560 -12.0000 0.1306
6 t-test on animal means, t(10) = -0.58 12 -19.1067 0.5741
fraction of cells with half-width below 120 degrees: {'KO': 0.781, 'WT': 0.734}
cells with half-width 360 (never below half maximum): {'KO': 26, 'WT': 46}
plotted ranges: HD info 0.004 to 3.552 ; half-width 16.0 to 360.0
Result: partially reproduced. HD information is higher in juvenile Fmr1-/y cells than in WT cells (median 0.596 against 0.189 bits/spike; LME p = 0.030), and stays so with the first day of each rat alone (p = 0.035), but not on log values (p = 0.12), with uniform occupancy as in version 2 (p = 0.081), on rat means (t(10) = 2.11, p = 0.061), with H3026 left out (p = 0.072) or with the archive's labels (p = 0.23). The half-width does not differ (median 50 against 62 degrees; LME p = 0.54).
fig1g-juvenile-halves-correlation¶
In juveniles the HD information of a cell is stable between the two halves of an exploration session (WT r = 0.90, Fmr1-/y r = 0.95).
print(corr("juvenile", "info_half1", "info_half2").round(4).to_string())
print("\nvariant, archive labels:")
print(corr("juvenile", "info_half1", "info_half2", cells_arch).round(4).to_string())
print("\nvariant, H3026 left out:")
print(corr("juvenile", "info_half1", "info_half2", cells[cells.subject != "H3026"]).round(4).to_string())
scatter("juvenile", "info_half1", "info_half2", "HD info, first half (bits/spike)", "HD info, second half")
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 323 7 0.8151 0.0 0.8632 0.7393 162 (0.004, 3.331) (0.005, 3.422) 1 KO 237 5 0.8354 0.0 0.9088 0.8984 127 (0.0, 4.166) (0.006, 4.046) variant, archive labels: genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 393 7 0.8264 0.0 0.8883 0.8028 189 (0.004, 4.066) (0.005, 4.046) 1 KO 145 4 0.8685 0.0 0.9178 0.9151 78 (0.0, 4.166) (0.006, 3.506) variant, H3026 left out: genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 323 7 0.8151 0.0 0.8632 0.7393 162 (0.004, 3.331) (0.005, 3.422) 1 KO 145 4 0.8685 0.0 0.9178 0.9151 78 (0.0, 4.166) (0.006, 3.506)
plotted ranges: info_half1 0.000 to 4.166; info_half2 0.005 to 4.046 (no point outside the axes)
the ten cells farthest from the diagonal:
subject session genotype unit first_day info_half1 info_half2 diff
86 H3006 200314_1 WT 6 True 3.125 0.133 2.992
337 H3016 210423 KO 37 False 4.093 1.158 2.935
500 H3026 211004_2 KO 8 False 1.052 3.027 1.975
184 H3009 200812 WT 14 True 2.322 0.447 1.875
142 H3008 200805 KO 10 True 4.125 2.273 1.852
528 H3026 211004_2 KO 47 False 1.333 3.029 1.696
509 H3026 211004_2 KO 17 False 2.293 0.739 1.554
506 H3026 211004_2 KO 14 False 2.660 4.046 1.387
486 H3026 211003 KO 69 True 4.066 2.689 1.377
200 H3009 200812 WT 33 True 2.658 1.293 1.365
Result: not reproduced. With the sessions as the claims file defines them (see the section on the session definition below), HD information of the two halves of session 1 correlates with r = 0.761 over 323 WT cells (paper 0.90, lower bound 0.81) and r = 0.839 over 237 Fmr1-/y cells (paper 0.95, lower bound 0.855), so neither value is within tolerance. With H3026 left out the Fmr1-/y r is 0.869, within tolerance, and WT stays at 0.761; with the first day of each rat alone WT r is 0.650. With the 20 min sessions used in this section, WT r is 0.815, 0.005 above its bound, and Fmr1-/y r 0.835; with the first day alone WT r is 0.739. Spearman correlations with the 20 min sessions are higher (0.863 and 0.909). Five of the ten cells farthest from the diagonal are from H3026, the rat counted as Fmr1-/y against the archive's label. The 20 min cut was adopted after the first round of verification and departs from the claims file, so the outcome follows the claims file's definition.
fig1h-juvenile-smaller-offset¶
Within a session, the tuning curves of juvenile Fmr1-/y cells drift less relative to the room than those of WT cells; the angular offset between the two halves is smaller.
d = cells[cells.age_group == "juvenile"]
t_off = show("offset_halves", "juvenile", log_ok=False,
extra=("LME, cells with half-width below 120 deg", d[d.half_width < 120]))
print("plotted quantity range (deg):", d.offset_halves.min(), "to", d.offset_halves.max())
offset_halves, juvenile: cells by genotype
count median mean min max
genotype
KO 236 7.0 21.983 0.0 176.0
WT 323 26.0 48.672 0.0 179.0
per rat
count median mean
genotype animal
KO H3003 51 7.0 21.686
H3008 37 5.0 10.865
H3016 41 12.0 29.488
H3019 15 11.0 39.667
H3026 92 6.0 20.391
WT H3001 31 13.0 30.161
H3006 51 52.0 68.745
H3009 56 6.0 19.429
H3015 75 47.0 65.987
H3022 47 8.0 22.617
H3023 41 52.0 72.146
H3029 22 27.5 55.545
tests
test n coef_KO_minus_WT p
0 LME (main) 559 -24.1000 0.0353
1 LME, first day of each rat 288 -32.8744 0.0170
2 LME, archive labels 537 -17.9190 0.1690
3 LME, H3026 left out 467 -23.1235 0.0684
4 LME, cells with half-width below 120 deg 421 -20.4668 0.0604
5 Mann-Whitney on cells 559 -19.0000 0.0000
6 t-test on animal means, t(10) = -2.09 12 -23.3850 0.0627
plotted quantity range (deg): 0.0 to 179.0
Result: reproduced. The offset between the two halves' tuning curves is smaller in juvenile Fmr1-/y cells (median 7 against 26 degrees; LME p = 0.035). It holds with the first day alone (p = 0.017), and not for cells with half-width below 120 degrees (p = 0.060), on rat means (t(10) = -2.09, p = 0.063), with H3026 left out (p = 0.068) or with the archive's labels (p = 0.17). With the claims file's session definition p = 0.014.
fig1j-juvenile-less-drift¶
Bayesian decoding shows less drift of the HD signal relative to the room in juvenile Fmr1-/y rats than in WT rats.
MIN_DRIFT_BINS = 300 # 1 min of decoded movement; a choice, shown as a variant
def drift_test(age, col):
d = recs[(recs.age_group == age)].dropna(subset=[col])
am = d.groupby(["subject", "genotype"])[col].mean().reset_index()
ko, wt = am.loc[am.genotype == "KO", col], am.loc[am.genotype == "WT", col]
t = stats.ttest_ind(ko, wt)
return am, {"measure": col, "WT_mean": wt.mean(), "KO_mean": ko.mean(), "rats": f"{len(wt)} WT, {len(ko)} KO",
"t": t.statistic, "df": len(am) - 2, "p": t.pvalue}
def drift_report(age):
d = recs[recs.age_group == age]
print("recordings without decoding (fewer than 6 cells):", d.loc[d.drift_mean.isna(), ["subject", "session", "n_cells"]].values.tolist())
print("second-half bins of 200 ms: all, with valid tracking, with speed above 2 cm/s, and valid with speed above 2 cm/s (decoded and averaged):")
print(d[["subject", "session", "genotype", "n_cells", "drift_bins_all", "drift_bins_valid", "drift_bins_fast", "drift_bins", "drift_mean", "drift_sd", "drift_mean_v2"]].round(2).to_string())
rows = []
for col in ("drift_mean", "drift_sd", "drift_mean_v2", "drift_sd_v2"):
am, r = drift_test(age, col)
rows.append(r)
print("\nper rat (mean over recordings):")
print(drift_test(age, "drift_mean")[0].round(2).to_string())
print("\nt-tests on rat means (degrees):")
print(pd.DataFrame(rows).round(4).to_string())
first = recs[(recs.age_group == age) & recs.first_day].dropna(subset=["drift_mean"])
ko, wt = first.loc[first.genotype == "KO", "drift_mean"], first.loc[first.genotype == "WT", "drift_mean"]
t = stats.ttest_ind(ko, wt)
print(f"variant, first day only: WT {wt.mean():.2f}, KO {ko.mean():.2f}, t({len(first) - 2}) = {t.statistic:.2f}, p = {t.pvalue:.4f}")
arch_g = meta.set_index(["subject", "session_id"]).archive_genotype
dd = d.dropna(subset=["drift_mean"]).copy()
dd["genotype"] = [arch_g[(s, ss)] for s, ss in zip(dd.subject, dd.session)]
am = dd.groupby(["subject", "genotype"]).drift_mean.mean().reset_index()
t = stats.ttest_ind(am.loc[am.genotype == "KO", "drift_mean"], am.loc[am.genotype == "WT", "drift_mean"])
print(f"variant, archive genotypes: t({len(am) - 2}) = {t.statistic:.2f}, p = {t.pvalue:.4f}")
for name, sub in ((f"recordings with at least {MIN_DRIFT_BINS} averaged bins", d[d.drift_bins >= MIN_DRIFT_BINS]),
("H3026 left out", d[d.subject != "H3026"])):
if age == "adult" and name.startswith("H3026"):
continue
sub = sub.dropna(subset=["drift_mean"])
am = sub.groupby(["subject", "genotype"]).drift_mean.mean().reset_index()
ko, wt = am.loc[am.genotype == "KO", "drift_mean"], am.loc[am.genotype == "WT", "drift_mean"]
t = stats.ttest_ind(ko, wt)
print(f"variant, {name}: {len(wt)} WT, {len(ko)} KO rats; WT {wt.mean():.2f}, KO {ko.mean():.2f}, t({len(am) - 2}) = {t.statistic:.2f}, p = {t.pvalue:.4f}")
drift_report("juvenile")
recordings without decoding (fewer than 6 cells): [['H3019', '210618_1', 5]]
second-half bins of 200 ms: all, with valid tracking, with speed above 2 cm/s, and valid with speed above 2 cm/s (decoded and averaged):
subject session genotype n_cells drift_bins_all drift_bins_valid drift_bins_fast drift_bins drift_mean drift_sd drift_mean_v2
0 H3001 200201 WT 18 3000.0 2914.0 330.0 279.0 11.90 14.63 12.21
1 H3001 200202 WT 13 3000.0 2804.0 857.0 709.0 11.52 15.31 16.07
2 H3003 200207 KO 33 3000.0 2705.0 2150.0 1889.0 15.46 21.96 16.19
3 H3003 200208 KO 19 3000.0 2804.0 2047.0 1868.0 9.13 12.96 9.67
4 H3006 200314_1 WT 28 3000.0 2977.0 514.0 491.0 40.96 57.62 46.13
5 H3006 200314_2 WT 23 3000.0 2811.0 1727.0 1612.0 32.28 50.09 32.62
6 H3008 200805 KO 24 3000.0 2765.0 2711.0 2480.0 8.90 13.09 9.19
7 H3008 200807 KO 13 3000.0 2983.0 1476.0 1459.0 16.48 23.67 18.55
8 H3009 200812 WT 30 3000.0 2837.0 1267.0 1122.0 25.18 45.34 40.02
9 H3009 200813 WT 26 3000.0 2969.0 969.0 943.0 16.17 31.28 23.26
10 H3015 210416_1 WT 27 3000.0 2709.0 1385.0 1149.0 60.27 65.64 65.74
11 H3015 210416_2 WT 33 3000.0 2679.0 1412.0 1135.0 62.99 67.80 62.62
12 H3015 210417 WT 15 3000.0 2969.0 1335.0 1333.0 39.17 53.86 39.39
13 H3016 210422 KO 11 3000.0 2968.0 1338.0 1316.0 37.30 58.55 41.89
14 H3016 210423 KO 30 3000.0 2366.0 1776.0 1310.0 24.27 37.86 30.19
15 H3019 210617 KO 10 3000.0 2839.0 2214.0 2073.0 15.48 23.50 16.64
16 H3019 210618_1 KO 5 NaN NaN NaN NaN NaN NaN NaN
17 H3022 210805 WT 18 3000.0 2760.0 2181.0 2038.0 13.30 16.87 14.66
18 H3022 210806 WT 29 3000.0 2709.0 2174.0 1915.0 13.59 22.08 15.16
19 H3023 210812 WT 19 3000.0 2549.0 2068.0 1778.0 69.50 77.79 65.67
20 H3023 210813_1 WT 22 3000.0 1122.0 2188.0 1009.0 41.76 55.12 43.45
21 H3026 211003 KO 49 3000.0 2892.0 2463.0 2360.0 12.75 19.52 13.56
22 H3026 211004_2 KO 43 3000.0 2816.0 2001.0 1841.0 15.15 26.19 15.80
23 H3029 230510 WT 22 3000.0 3000.0 1557.0 1557.0 52.59 50.88 64.81
per rat (mean over recordings):
subject genotype drift_mean
0 H3001 WT 11.71
1 H3003 KO 12.29
2 H3006 WT 36.62
3 H3008 KO 12.69
4 H3009 WT 20.68
5 H3015 WT 54.14
6 H3016 KO 30.79
7 H3019 KO 15.48
8 H3022 WT 13.45
9 H3023 WT 55.63
10 H3026 KO 13.95
11 H3029 WT 52.59
t-tests on rat means (degrees):
measure WT_mean KO_mean rats t df p
0 drift_mean 34.9728 17.0389 7 WT, 5 KO -1.9149 10 0.0845
1 drift_sd 43.7683 26.0811 7 WT, 5 KO -1.7142 10 0.1173
2 drift_mean_v2 39.3350 18.8341 7 WT, 5 KO -2.0835 10 0.0638
3 drift_sd_v2 48.4885 29.4186 7 WT, 5 KO -1.8337 10 0.0966
variant, first day only: WT 39.10, KO 17.98, t(10) = -1.89, p = 0.0884
variant, archive genotypes: t(10) = -1.39, p = 0.1960
variant, recordings with at least 300 averaged bins: 7 WT, 5 KO rats; WT 34.95, KO 17.04, t(10) = -1.91, p = 0.0854
variant, H3026 left out: 7 WT, 4 KO rats; WT 34.97, KO 17.81, t(9) = -1.63, p = 0.1380
Result: not reproduced. Decoder drift is lower in Fmr1-/y rats (rat means 17.0 against 35.0 degrees) but the t-test on rat means is not significant (t(10) = -1.91, p = 0.085). With version 2's 1.5 cm/s threshold p = 0.064, for the SD of drift p = 0.12, with the first day alone p = 0.088, with the archive's labels p = 0.20, with H3026 left out p = 0.14. H3019 (210618-1) is left out with 5 cells. H3001 (200201) is decoded on 279 bins, where the other recordings have 491 to 2480: only 330 of its 3000 second-half bins have a speed above 2 cm/s, though 2914 have valid tracking. Leaving out recordings under 300 bins gives p = 0.085.
figs1j-juvenile-epochs-correlation and figs1k-juvenile-epoch-drift-similar¶
In juveniles HD information is preserved between the two exploration sessions (WT r = 0.85, Fmr1-/y r = 0.85), and the drift of tuning curves between the sessions does not differ between genotypes.
print(corr("juvenile", "hd_info", "info_s2").round(4).to_string())
scatter("juvenile", "hd_info", "info_s2", "HD info, session 1 (bits/spike)", "HD info, session 2")
print()
t_ep = show("offset_epochs", "juvenile", log_ok=False)
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 309 7 0.8534 0.0 0.8694 0.8708 162 (0.006, 3.176) (0.004, 2.464) 1 KO 225 5 0.7533 0.0 0.8102 0.7340 121 (0.004, 3.413) (0.007, 3.554)
plotted ranges: hd_info 0.004 to 3.413; info_s2 0.004 to 3.554 (no point outside the axes)
the ten cells farthest from the diagonal:
subject session genotype unit first_day hd_info info_s2 diff
202 H3009 200813 WT 1 False 2.885 0.502 2.382
36 H3003 200207 KO 6 True 0.015 2.237 2.221
506 H3026 211004_2 KO 14 False 2.996 1.136 1.859
505 H3026 211004_2 KO 13 False 1.760 3.554 1.794
43 H3003 200207 KO 13 True 2.038 0.268 1.770
526 H3026 211004_2 KO 45 False 1.709 0.186 1.523
145 H3008 200805 KO 13 True 1.797 3.251 1.454
206 H3009 200813 WT 6 False 3.176 1.782 1.394
53 H3003 200207 KO 26 True 2.222 0.831 1.391
512 H3026 211004_2 KO 22 False 2.484 1.105 1.379
offset_epochs, juvenile: cells by genotype
count median mean min max
genotype
KO 225 14.0 54.373 0.0 180.0
WT 309 21.0 46.961 0.0 180.0
per rat
count median mean
genotype animal
KO H3003 50 23.5 57.880
H3008 37 6.0 15.135
H3016 37 12.0 28.081
H3019 10 29.5 51.600
H3026 91 28.0 79.396
WT H3001 18 12.5 19.667
H3006 51 77.0 83.569
H3009 56 9.0 23.054
H3015 74 46.5 60.338
H3022 47 11.0 20.362
H3023 41 39.0 50.634
H3029 22 19.0 50.273
tests
test n coef_KO_minus_WT p
0 LME (main) 534 2.3135 0.8659
1 LME, first day of each rat 283 -5.6405 0.7156
2 LME, archive labels 512 -11.6712 0.4406
3 LME, H3026 left out 443 -7.0643 0.6015
4 Mann-Whitney on cells 534 -7.0000 0.2245
5 t-test on animal means, t(10) = 0.17 12 2.4333 0.8694
Result: figs1j-juvenile-epochs-correlation partially reproduced; figs1k-juvenile-epoch-drift-similar reproduced. HD information correlates between the two sessions with r = 0.853 over 309 WT cells (paper 0.85) and 0.753 over 225 Fmr1-/y cells (paper 0.85, tolerance down to 0.765), so one of the two values is within tolerance. The offset between sessions does not differ between genotypes (median 14 against 21 degrees; LME p = 0.87; first day p = 0.72; archive labels p = 0.44).
fig2c-juvenile-isomap-wake-correlation and fig2d-juvenile-isomap-wake-sharper¶
In juveniles the HD information of tuning curves computed against the Isomap angle of waking population activity matches that of real HD tuning curves (WT r = 0.84, Fmr1-/y r = 0.92), and juvenile Fmr1-/y cells are better tuned than WT cells to this internal HD signal.
def iso_report(age):
d = recs[recs.age_group == age]
print("Isomap alignment with real HD (Rayleigh length of the error) per recording; recordings with fewer than 6 cells left out:")
print(d[["subject", "session", "genotype", "n_cells", "iso_alignment", "iso_flipped"]].round(3).to_string())
print(f"alignment range {d.iso_alignment.min():.3f} to {d.iso_alignment.max():.3f}")
c = cells[cells.age_group == age]
for col in ("iso_wake_info", "real200_info"):
top = c.sort_values(col, ascending=False).groupby("genotype").head(3)
print(f"three highest {col} per genotype:")
print(top[["genotype", "subject", "session", "unit", "n_spikes_s1", "iso_wake_info", "real200_info", "hd_info"]].round(4).to_string())
iso_report("juvenile")
print()
print(corr("juvenile", "real200_info", "iso_wake_info").round(4).to_string())
print()
t_iso = show("iso_wake_info", "juvenile")
Isomap alignment with real HD (Rayleigh length of the error) per recording; recordings with fewer than 6 cells left out:
subject session genotype n_cells iso_alignment iso_flipped
0 H3001 200201 WT 18 0.435 False
1 H3001 200202 WT 13 0.468 True
2 H3003 200207 KO 33 0.484 False
3 H3003 200208 KO 19 0.755 False
4 H3006 200314_1 WT 28 0.301 False
5 H3006 200314_2 WT 23 0.284 True
6 H3008 200805 KO 24 0.884 False
7 H3008 200807 KO 13 0.621 True
8 H3009 200812 WT 30 0.823 True
9 H3009 200813 WT 26 0.422 False
10 H3015 210416_1 WT 27 0.381 True
11 H3015 210416_2 WT 33 0.438 False
12 H3015 210417 WT 15 0.235 True
13 H3016 210422 KO 11 0.357 False
14 H3016 210423 KO 30 0.477 False
15 H3019 210617 KO 10 0.492 True
16 H3019 210618_1 KO 5 NaN NaN
17 H3022 210805 WT 18 0.901 True
18 H3022 210806 WT 29 0.465 False
19 H3023 210812 WT 19 0.273 True
20 H3023 210813_1 WT 22 0.402 False
21 H3026 211003 KO 49 0.688 True
22 H3026 211004_2 KO 43 0.459 False
23 H3029 230510 WT 22 0.213 False
alignment range 0.213 to 0.901
three highest iso_wake_info per genotype:
genotype subject session unit n_spikes_s1 iso_wake_info real200_info hd_info
147 KO H3008 200805 15 3344 2.2181 2.0773 2.3404
182 WT H3009 200812 12 443 2.1900 2.2096 2.2445
175 WT H3009 200812 4 463 2.0906 1.9209 1.6418
139 KO H3008 200805 7 1039 2.0871 2.7183 3.1417
486 KO H3026 211003 69 632 2.0658 2.4720 3.2062
191 WT H3009 200812 23 1652 1.8906 2.1934 2.4373
three highest real200_info per genotype:
genotype subject session unit n_spikes_s1 iso_wake_info real200_info hd_info
302 KO H3016 210422 1 131 1.7552 3.5599 3.5519
303 KO H3016 210422 2 497 1.3920 2.9644 2.9878
499 KO H3026 211004_2 7 424 1.2401 2.8223 3.4133
206 WT H3009 200813 6 527 1.1544 2.7007 3.1762
202 WT H3009 200813 1 352 1.4507 2.4486 2.8845
182 WT H3009 200812 12 443 2.1900 2.2096 2.2445
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range
0 WT 323 7 0.8151 0.0 0.8368 0.8213 162 (0.002, 2.701) (0.003, 2.19)
1 KO 232 5 0.9098 0.0 0.9419 0.9162 127 (0.002, 3.56) (0.004, 2.218)
iso_wake_info, juvenile: cells by genotype
count median mean min max
genotype
KO 232 0.416 0.585 0.004 2.218
WT 323 0.243 0.418 0.003 2.190
per rat
count median mean
genotype animal
KO H3003 52 0.319 0.442
H3008 37 0.612 0.845
H3016 41 0.472 0.634
H3019 10 0.319 0.435
H3026 92 0.420 0.555
WT H3001 31 0.318 0.389
H3006 51 0.154 0.258
H3009 56 0.547 0.682
H3015 75 0.390 0.493
H3022 47 0.276 0.476
H3023 41 0.095 0.148
H3029 22 0.199 0.273
tests
test n coef_KO_minus_WT p
0 LME (main) 555 0.1964 0.0556
1 LME on log values 555 0.3637 0.1312
2 LME, first day of each rat 289 0.2513 0.1452
3 LME, archive labels 533 0.1681 0.1377
4 LME, H3026 left out 463 0.2071 0.0747
5 Mann-Whitney on cells 555 0.1735 0.0007
6 t-test on animal means, t(10) = 1.89 12 0.1936 0.0885
# Isomap fitted on at most 3000 bins (as in the first round of this attempt), beside the fit on every bin used in
# the analysis, for the recording with the most cells in each age group
seed_of = {(m["subject"], m["session_id"]): k for k, m in enumerate(meta.to_dict("records"))}
fit_rows = []
for age in ("juvenile", "adult"):
rr_ = recs[recs.age_group == age].sort_values("n_cells").iloc[-1]
k = seed_of[(rr_.subject, rr_.session)]
s_ = hdfx.load_session(assets.asset_id[k])
sub_ = hdfx.analyse(s_, age, seed=k, fit_max=3000)["cells"].set_index("unit")
full_ = cells[(cells.subject == rr_.subject) & (cells.session == rr_.session)].set_index("unit")
for col in ("iso_wake_info", "iso_rem_info"):
b_ = full_[col].dropna()
a_ = sub_[col].reindex(b_.index)
fit_rows.append({"recording": f"{rr_.subject} {rr_.session}", "age": age, "measure": col, "cells": len(b_),
"median_full": b_.median(), "median_3000_bins": a_.median(),
"r_full_vs_3000": stats.pearsonr(a_, b_)[0],
"r_with_real200_full": stats.pearsonr(full_.loc[b_.index, "real200_info"], b_)[0] if col == "iso_wake_info" else np.nan,
"r_with_real200_3000": stats.pearsonr(full_.loc[b_.index, "real200_info"], a_)[0] if col == "iso_wake_info" else np.nan})
del s_
print(pd.DataFrame(fit_rows).round(3).to_string())
recording age measure cells median_full median_3000_bins r_full_vs_3000 r_with_real200_full r_with_real200_3000 0 H3026 211003 juvenile iso_wake_info 49 0.435 0.546 0.987 0.978 0.982 1 H3026 211003 juvenile iso_rem_info 49 0.452 0.477 0.996 NaN NaN 2 H4823 221108 adult iso_wake_info 80 0.360 0.359 0.998 0.978 0.978 3 H4823 221108 adult iso_rem_info 63 0.434 0.434 1.000 NaN NaN
Result: fig2c-juvenile-isomap-wake-correlation reproduced; fig2d-juvenile-isomap-wake-sharper not reproduced. The HD information of Isomap tuning curves correlates with that of real-HD curves with r = 0.815 in WT and 0.910 in Fmr1-/y (paper 0.84 and 0.92). Isomap HD information is higher in Fmr1-/y cells (median 0.416 against 0.243 bits/spike) but the LME test is not significant (p = 0.056); no variant that keeps the rat is below 0.05 (log values p = 0.13, first day p = 0.15, archive labels p = 0.14, H3026 left out p = 0.075, rat means p = 0.089), and only the Mann-Whitney test on cells is (p = 0.0007). The direction matches the paper. The Isomap angle aligned with real HD with Rayleigh lengths of 0.21 to 0.90. Isomap is fitted on every bin; fitting it on 3000 bins, as in the first round of this attempt, raises the median Isomap information of H3026 211003 from 0.435 to 0.546 bits/spike (r = 0.987 across its cells), while in H4823 the two fits agree (0.360 and 0.359).
fig2g-juvenile-isomap-rem-correlation and fig2h-juvenile-isomap-rem-sharper¶
In juveniles the HD information of tuning curves computed against the Isomap angle of REM activity matches that of real HD tuning curves (WT r = 0.73, Fmr1-/y r = 0.90), and juvenile Fmr1-/y cells are better tuned than WT cells to the internally generated signal during REM.
d = recs[recs.age_group == "juvenile"]
print(d[["subject", "session", "genotype", "rem_s", "n_cells_rem", "rem_bins", "rem_in_sessions", "rem_in_sessions_s"]].to_string())
print()
print(corr("juvenile", "real200_info", "iso_rem_info").round(4).to_string())
print()
t_rem = show("iso_rem_info", "juvenile",
extra=("LME, REM inside exploration left out", cells[cells.age_group == "juvenile"], "iso_rem_info_outside"))
print("\nvariant, REM inside exploration left out:")
print(corr("juvenile", "real200_info", "iso_rem_info_outside").round(4).to_string())
subject session genotype rem_s n_cells_rem rem_bins rem_in_sessions rem_in_sessions_s
0 H3001 200201 WT 983.0 18.0 4915.0 1.0 14.0
1 H3001 200202 WT 1706.0 13.0 8530.0 0.0 0.0
2 H3003 200207 KO 1163.0 32.0 5815.0 0.0 0.0
3 H3003 200208 KO 1192.0 19.0 5960.0 0.0 0.0
4 H3006 200314_1 WT 1030.0 28.0 5150.0 0.0 0.0
5 H3006 200314_2 WT 690.0 23.0 3450.0 0.0 0.0
6 H3008 200805 KO 640.0 24.0 3200.0 0.0 0.0
7 H3008 200807 KO 630.0 13.0 3150.0 0.0 0.0
8 H3009 200812 WT 1035.0 30.0 5175.0 0.0 0.0
9 H3009 200813 WT 906.0 26.0 4530.0 0.0 0.0
10 H3015 210416_1 WT 1291.0 27.0 6455.0 2.0 21.0
11 H3015 210416_2 WT 1004.0 33.0 5020.0 4.0 49.0
12 H3015 210417 WT 1066.0 15.0 5330.0 0.0 0.0
13 H3016 210422 KO 689.0 11.0 3445.0 0.0 0.0
14 H3016 210423 KO 764.0 30.0 3820.0 1.0 13.0
15 H3019 210617 KO 644.0 10.0 3220.0 0.0 0.0
16 H3019 210618_1 KO NaN NaN NaN NaN NaN
17 H3022 210805 WT 1178.0 18.0 5890.0 0.0 0.0
18 H3022 210806 WT 1409.0 29.0 7045.0 0.0 0.0
19 H3023 210812 WT 593.0 19.0 2965.0 0.0 0.0
20 H3023 210813_1 WT 1337.0 22.0 6685.0 1.0 13.0
21 H3026 211003 KO 850.0 49.0 4250.0 0.0 0.0
22 H3026 211004_2 KO 539.0 43.0 2695.0 0.0 0.0
23 H3029 230510 WT 1037.0 22.0 5185.0 0.0 0.0
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range
0 WT 323 7 0.8311 0.0 0.7756 0.8269 162 (0.002, 2.701) (0.005, 2.388)
1 KO 231 5 0.8332 0.0 0.8871 0.8651 126 (0.002, 3.56) (0.004, 2.404)
iso_rem_info, juvenile: cells by genotype
count median mean min max
genotype
KO 231 0.401 0.597 0.004 2.404
WT 323 0.169 0.394 0.005 2.388
per rat
count median mean
genotype animal
KO H3003 51 0.359 0.532
H3008 37 0.425 0.681
H3016 41 0.305 0.578
H3019 10 0.240 0.418
H3026 92 0.447 0.628
WT H3001 31 0.310 0.435
H3006 51 0.079 0.303
H3009 56 0.566 0.765
H3015 75 0.221 0.366
H3022 47 0.213 0.406
H3023 41 0.048 0.134
H3029 22 0.078 0.163
tests
test n coef_KO_minus_WT p
0 LME (main) 554 0.2066 0.0451
1 LME on log values 554 0.5431 0.0915
2 LME, first day of each rat 288 0.1997 0.1578
3 LME, archive labels 532 0.1279 0.2527
4 LME, H3026 left out 462 0.1914 0.0949
5 LME, REM inside exploration left out 554 0.2068 0.0450
6 Mann-Whitney on cells 554 0.2318 0.0000
7 t-test on animal means, t(10) = 1.95 12 0.1999 0.0791
variant, REM inside exploration left out:
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range
0 WT 323 7 0.8307 0.0 0.7742 0.8277 162 (0.002, 2.701) (0.004, 2.388)
1 KO 231 5 0.8306 0.0 0.8870 0.8651 126 (0.002, 3.56) (0.004, 2.404)
Result: fig2g-juvenile-isomap-rem-correlation partially reproduced; fig2h-juvenile-isomap-rem-sharper reproduced. The HD information of REM Isomap tuning curves correlates with that of waking real-HD curves with r = 0.833 in Fmr1-/y (paper 0.90, within tolerance) and 0.831 in WT (paper 0.73, above the tolerance of 0.657 to 0.803). REM Isomap HD information is higher in Fmr1-/y cells (median 0.401 against 0.169 bits/spike; LME p = 0.045). The result is at the threshold: on log values p = 0.092, with the first day alone p = 0.16, with the archive's labels p = 0.25, with H3026 left out p = 0.095, on rat means p = 0.079; leaving out the REM intervals inside exploration sessions gives p = 0.045.
fig3ef-adult-tuning-similar¶
In adults HD tuning does not differ between Fmr1-/y and WT rats, in HD information or tuning curve width.
a_info = show("hd_info", "adult", uniform_col="hd_info_uniform")
print("=" * 100)
a_hw = show("half_width", "adult")
hd_info, adult: cells by genotype
count median mean min max
genotype
KO 282 0.193 0.375 0.003 2.466
WT 395 0.318 0.453 0.003 3.066
per rat
count median mean
genotype animal
KO H4817 72 0.120 0.198
H4819 71 0.346 0.479
H4822 30 0.089 0.120
H4824 57 0.158 0.228
H4827 52 0.618 0.784
WT H4813 54 0.418 0.500
H4815 76 0.282 0.455
H4820 51 0.081 0.158
H4823 80 0.412 0.496
H4826 72 0.575 0.701
H4830 62 0.186 0.310
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -0.0738 0.5534
1 LME on log values 677 -0.2601 0.4681
2 LME, archive labels 702 -0.0380 0.7561
3 LME, uniform occupancy (v2) 677 -0.0874 0.4762
4 Mann-Whitney on cells 677 -0.1254 0.0095
5 t-test on animal means, t(9) = -0.54 11 -0.0750 0.5996
====================================================================================================
half_width, adult: cells by genotype
count median mean min max
genotype
KO 282 78.0 123.234 20.0 360.0
WT 395 76.0 131.691 20.0 360.0
per rat
count median mean
genotype animal
KO H4817 72 84.0 134.028
H4819 71 96.0 118.930
H4822 30 100.0 145.200
H4824 57 86.0 134.737
H4827 52 51.0 88.885
WT H4813 54 64.0 111.185
H4815 76 80.0 132.447
H4820 51 164.0 213.765
H4823 80 62.0 121.775
H4826 72 51.0 79.333
H4830 62 104.0 154.710
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -10.9023 0.5903
1 LME on log values 677 -0.1010 0.5267
2 LME, archive labels 702 -15.2640 0.4403
3 Mann-Whitney on cells 677 2.0000 0.2574
4 t-test on animal means, t(9) = -0.50 11 -11.1801 0.6303
Result: reproduced. In adults neither HD information (median 0.193 in Fmr1-/y against 0.318 in WT; LME p = 0.55) nor half-width (78 against 76 degrees; p = 0.59) differs between genotypes. The Mann-Whitney test on cells finds lower HD information in Fmr1-/y cells (p = 0.0095).
fig3g-adult-halves-correlation¶
In adults HD information is stable between the two halves of an exploration session (WT r = 0.94, Fmr1-/y r = 0.94).
print(corr("adult", "info_half1", "info_half2").round(4).to_string())
scatter("adult", "info_half1", "info_half2", "HD info, first half (bits/spike)", "HD info, second half")
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 395 6 0.8038 0.0 0.8623 0.8038 395 (0.005, 3.116) (0.005, 4.252) 1 KO 282 5 0.7477 0.0 0.8184 0.7477 282 (0.003, 2.926) (0.004, 3.878)
plotted ranges: info_half1 0.003 to 3.116; info_half2 0.004 to 4.252 (no point outside the axes)
the ten cells farthest from the diagonal:
subject session genotype unit first_day info_half1 info_half2 diff
633 H4815 220814 WT 26 True 1.517 4.252 2.735
1069 H4826 221203 WT 30 True 1.323 3.707 2.384
677 H4815 220814 WT 83 True 1.918 4.131 2.213
1033 H4824 221117 KO 64 True 1.069 3.194 2.125
1045 H4824 221117 KO 81 True 0.544 2.447 1.903
1129 H4827 221210 KO 9 True 1.543 3.361 1.819
746 H4817 220828 KO 77 True 0.637 2.425 1.788
1142 H4827 221210 KO 31 True 2.194 3.878 1.684
867 H4820 221007 WT 37 True 0.332 1.838 1.506
1046 H4824 221117 KO 82 True 0.387 1.853 1.466
Result: not reproduced. In adults HD information correlates between the two halves of a session with r = 0.804 over 395 WT cells and 0.748 over 282 Fmr1-/y cells, both below the lower bound of 0.846 around the paper's 0.94. Spearman correlations are 0.862 and 0.818. The cells farthest from the diagonal have higher information in the second half and come from several rats of both genotypes.
fig3h-adult-larger-offset¶
Within a session the tuning curves of adult Fmr1-/y cells drift more relative to the room than those of WT cells.
d = cells[cells.age_group == "adult"]
a_off = show("offset_halves", "adult", log_ok=False,
extra=("LME, cells with half-width below 120 deg", d[d.half_width < 120]))
offset_halves, adult: cells by genotype
count median mean min max
genotype
KO 282 60.0 68.340 1.0 175.0
WT 395 20.0 37.754 0.0 176.0
per rat
count median mean
genotype animal
KO H4817 72 104.0 101.083
H4819 71 38.0 44.803
H4822 30 95.0 101.100
H4824 57 82.0 78.877
H4827 52 16.0 24.692
WT H4813 54 12.0 32.556
H4815 76 41.0 56.618
H4820 51 13.0 40.784
H4823 80 13.5 26.638
H4826 72 12.0 28.792
H4830 62 27.0 41.419
tests
test n coef_KO_minus_WT p
0 LME (main) 677 32.0549 0.0298
1 LME, archive labels 702 28.5177 0.0433
2 LME, cells with half-width below 120 deg 466 42.7367 0.0169
3 Mann-Whitney on cells 677 40.0000 0.0000
4 t-test on animal means, t(9) = 2.20 11 32.3100 0.0556
Result: reproduced. The offset between the halves is larger in adult Fmr1-/y cells (median 60 against 20 degrees; LME p = 0.030), with the archive's labels (p = 0.043) and for cells with half-width below 120 degrees (p = 0.017); on rat means it is not significant (t(9) = 2.20, p = 0.056).
fig3j-adult-more-drift¶
Bayesian decoding shows more drift of the HD signal relative to the room in adult Fmr1-/y rats than in WT rats.
drift_report("adult")
recordings without decoding (fewer than 6 cells): []
second-half bins of 200 ms: all, with valid tracking, with speed above 2 cm/s, and valid with speed above 2 cm/s (decoded and averaged):
subject session genotype n_cells drift_bins_all drift_bins_valid drift_bins_fast drift_bins drift_mean drift_sd drift_mean_v2
24 H4813 220728 WT 54 3000.0 2996.0 1888.0 1884.0 17.18 29.44 18.74
25 H4815 220814 WT 76 3000.0 2983.0 1777.0 1760.0 23.01 19.80 23.61
26 H4817 220828 KO 72 3000.0 2945.0 1568.0 1513.0 98.23 52.22 100.90
27 H4819 220929 KO 71 3000.0 2998.0 1322.0 1320.0 32.90 20.92 34.00
28 H4820 221007 WT 51 3000.0 2958.0 1980.0 1939.0 18.76 28.23 19.14
29 H4822 221023 KO 30 3000.0 2919.0 2099.0 2032.0 101.21 110.90 100.96
30 H4823 221108 WT 80 3000.0 3000.0 1019.0 1019.0 11.26 10.14 11.68
31 H4824 221117 KO 57 3000.0 2985.0 1325.0 1310.0 91.40 52.03 80.53
32 H4826 221203 WT 72 3000.0 2980.0 774.0 759.0 13.02 20.90 13.69
33 H4827 221210 KO 52 3000.0 2990.0 1713.0 1703.0 18.34 18.66 22.01
34 H4830 230406 WT 62 3000.0 2995.0 1911.0 1906.0 37.12 27.36 39.30
per rat (mean over recordings):
subject genotype drift_mean
0 H4813 WT 17.18
1 H4815 WT 23.01
2 H4817 KO 98.23
3 H4819 KO 32.90
4 H4820 WT 18.76
5 H4822 KO 101.21
6 H4823 WT 11.26
7 H4824 KO 91.40
8 H4826 WT 13.02
9 H4827 KO 18.34
10 H4830 WT 37.12
t-tests on rat means (degrees):
measure WT_mean KO_mean rats t df p
0 drift_mean 20.0587 68.4162 6 WT, 5 KO 2.9272 9 0.0168
1 drift_sd 22.6472 50.9439 6 WT, 5 KO 1.8395 9 0.0990
2 drift_mean_v2 21.0253 67.6784 6 WT, 5 KO 2.9625 9 0.0159
3 drift_sd_v2 23.7104 55.4434 6 WT, 5 KO 2.1580 9 0.0593
variant, first day only: WT 20.06, KO 68.42, t(9) = 2.93, p = 0.0168
variant, archive genotypes: t(9) = 2.93, p = 0.0168
variant, recordings with at least 300 averaged bins: 6 WT, 5 KO rats; WT 20.06, KO 68.42, t(9) = 2.93, p = 0.0168
Result: reproduced. Decoder drift is higher in adult Fmr1-/y rats (rat means 68.4 against 20.1 degrees; t(9) = 2.93, p = 0.017; with version 2's threshold p = 0.016; for the SD of drift p = 0.099), over 5 Fmr1-/y rats where the paper has 6. Three Fmr1-/y rats drift by 91 to 101 degrees, and two (H4819 at 32.9, H4827 at 18.3) lie within the WT range of 11.3 to 37.1.
figs2j-adult-epochs-correlation and figs2k-adult-epoch-drift-larger¶
In adults HD information is preserved between the two exploration sessions (WT r = 0.90, Fmr1-/y r = 0.76), and Fmr1-/y tuning curves drift more than WT ones between the sessions.
print(corr("adult", "hd_info", "info_s2").round(4).to_string())
scatter("adult", "hd_info", "info_s2", "HD info, session 1 (bits/spike)", "HD info, session 2")
print()
a_ep = show("offset_epochs", "adult", log_ok=False)
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 395 6 0.7866 0.0 0.8879 0.7866 395 (0.003, 3.066) (0.004, 3.401) 1 KO 276 5 0.5617 0.0 0.7144 0.5617 276 (0.003, 2.466) (0.003, 3.21)
plotted ranges: hd_info 0.003 to 3.066; info_s2 0.003 to 3.401 (no point outside the axes)
the ten cells farthest from the diagonal:
subject session genotype unit first_day hd_info info_s2 diff
746 H4817 220828 KO 77 True 0.768 3.210 2.443
895 H4822 221023 KO 26 True 0.131 2.422 2.291
717 H4817 220828 KO 35 True 0.740 2.904 2.164
713 H4817 220828 KO 30 True 0.359 2.325 1.966
934 H4823 221108 WT 31 True 0.568 2.462 1.894
725 H4817 220828 KO 43 True 0.173 1.951 1.777
984 H4823 221108 WT 101 True 1.294 2.963 1.669
723 H4817 220828 KO 41 True 0.674 2.299 1.624
677 H4815 220814 WT 83 True 2.537 1.013 1.524
1021 H4824 221117 KO 47 True 0.200 1.669 1.469
offset_epochs, adult: cells by genotype
count median mean min max
genotype
KO 276 74.0 79.949 0.0 178.0
WT 395 30.0 42.625 0.0 174.0
per rat
count median mean
genotype animal
KO H4817 70 79.0 74.143
H4819 68 50.0 61.397
H4822 29 17.0 41.276
H4824 57 91.0 79.316
H4827 52 151.0 134.288
WT H4813 54 25.0 38.000
H4815 76 33.0 36.816
H4820 51 7.0 16.333
H4823 80 22.5 38.100
H4826 72 77.5 78.625
H4830 62 30.0 39.435
tests
test n coef_KO_minus_WT p
0 LME (main) 671 37.0213 0.0282
1 LME, archive labels 696 35.9699 0.0222
2 Mann-Whitney on cells 671 44.0000 0.0000
3 t-test on animal means, t(9) = 2.20 11 36.8657 0.0550
Result: figs2j-adult-epochs-correlation not reproduced; figs2k-adult-epoch-drift-larger reproduced. HD information correlates between the sessions with r = 0.787 over 395 WT cells and 0.562 over 276 Fmr1-/y cells, both below the lower bounds (0.81 and 0.684), though lower in Fmr1-/y as in the paper (0.90 and 0.76). Spearman correlations are 0.888 and 0.714; five of the ten cells farthest from the diagonal are from H4817, whose cells gain information in session 2. The offset between the sessions is larger in Fmr1-/y cells (median 74 against 30 degrees; LME p = 0.028; archive labels p = 0.022; rat means p = 0.055).
fig4c-adult-isomap-wake-correlation and fig4d-adult-isomap-wake-similar¶
In adults the HD information of Isomap tuning curves from waking activity matches that of real HD tuning curves (WT r = 0.95, Fmr1-/y r = 0.90), and does not differ between genotypes.
iso_report("adult")
print()
print(corr("adult", "real200_info", "iso_wake_info").round(4).to_string())
print()
a_iso = show("iso_wake_info", "adult")
Isomap alignment with real HD (Rayleigh length of the error) per recording; recordings with fewer than 6 cells left out:
subject session genotype n_cells iso_alignment iso_flipped
24 H4813 220728 WT 54 0.679 True
25 H4815 220814 WT 76 0.871 True
26 H4817 220828 KO 72 0.386 True
27 H4819 220929 KO 71 0.681 True
28 H4820 221007 WT 51 0.476 True
29 H4822 221023 KO 30 0.152 True
30 H4823 221108 WT 80 0.872 False
31 H4824 221117 KO 57 0.224 False
32 H4826 221203 WT 72 0.884 False
33 H4827 221210 KO 52 0.612 True
34 H4830 230406 WT 62 0.807 True
alignment range 0.152 to 0.884
three highest iso_wake_info per genotype:
genotype subject session unit n_spikes_s1 iso_wake_info real200_info hd_info
677 WT H4815 220814 83 1466 2.6395 2.2890 2.5370
1088 WT H4826 221203 53 451 2.5312 2.8304 3.0664
633 WT H4815 220814 26 1203 2.4450 2.0818 2.1810
741 KO H4817 220828 72 620 2.4165 0.4972 0.6352
749 KO H4817 220828 80 534 2.3580 0.6689 0.8583
711 KO H4817 220828 27 1281 2.0932 0.4531 0.5184
three highest real200_info per genotype:
genotype subject session unit n_spikes_s1 iso_wake_info real200_info hd_info
1088 WT H4826 221203 53 451 2.5312 2.8304 3.0664
1142 KO H4827 221210 31 1099 1.6173 2.2899 2.4662
677 WT H4815 220814 83 1466 2.6395 2.2890 2.5370
633 WT H4815 220814 26 1203 2.4450 2.0818 2.1810
1171 KO H4827 221210 73 1032 1.7040 2.0792 2.3627
1129 KO H4827 221210 9 393 1.4844 2.0709 2.1712
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range
0 WT 395 6 0.9447 0.0 0.9560 0.9447 395 (0.001, 2.83) (0.003, 2.639)
1 KO 282 5 0.6139 0.0 0.7614 0.6139 282 (0.003, 2.29) (0.004, 2.417)
iso_wake_info, adult: cells by genotype
count median mean min max
genotype
KO 282 0.279 0.455 0.004 2.417
WT 395 0.336 0.477 0.003 2.639
per rat
count median mean
genotype animal
KO H4817 72 0.538 0.661
H4819 71 0.248 0.354
H4822 30 0.248 0.357
H4824 57 0.230 0.322
H4827 52 0.307 0.509
WT H4813 54 0.323 0.424
H4815 76 0.398 0.559
H4820 51 0.162 0.248
H4823 80 0.360 0.481
H4826 72 0.472 0.624
H4830 62 0.275 0.435
tests
test n coef_KO_minus_WT p
0 LME (main) 677 -0.0203 0.7869
1 LME on log values 677 -0.0305 0.8542
2 LME, archive labels 702 0.0058 0.9403
3 Mann-Whitney on cells 677 -0.0564 0.3986
4 t-test on animal means, t(9) = -0.26 11 -0.0210 0.8041
Result: fig4c-adult-isomap-wake-correlation partially reproduced; fig4d-adult-isomap-wake-similar reproduced. Isomap and real-HD information correlate with r = 0.945 in WT (paper 0.95, within tolerance) and 0.614 in Fmr1-/y (paper 0.90, outside). Isomap HD information does not differ between genotypes (median 0.279 in Fmr1-/y against 0.336 in WT; LME p = 0.79; rat means p = 0.80). The Isomap angle aligned poorly with real HD in H4822 (0.152), H4824 (0.224) and H4817 (0.386), the three Fmr1-/y rats with the largest decoder drift; the three Fmr1-/y cells with the highest Isomap information are from H4817 and carry little real-HD information (0.45 to 0.67 bits/spike).
fig4g-adult-isomap-rem-correlation and fig4h-adult-isomap-rem-similar¶
In adults the HD information of Isomap tuning curves from REM activity matches that of real HD tuning curves (WT r = 0.82, Fmr1-/y r = 0.80), and does not differ between genotypes.
d = recs[recs.age_group == "adult"]
print(d[["subject", "session", "genotype", "rem_s", "n_cells_rem", "rem_bins", "rem_in_sessions", "rem_in_sessions_s"]].to_string())
print()
print(corr("adult", "real200_info", "iso_rem_info").round(4).to_string())
print()
a_rem = show("iso_rem_info", "adult",
extra=("LME, REM inside exploration left out", cells[cells.age_group == "adult"], "iso_rem_info_outside"))
print("\nvariant, REM inside exploration left out:")
print(corr("adult", "real200_info", "iso_rem_info_outside").round(4).to_string())
print(f"\nrun time so far {time.time() - started:.0f} s")
subject session genotype rem_s n_cells_rem rem_bins rem_in_sessions rem_in_sessions_s 24 H4813 220728 WT 988.000000 54.0 4940.0 0.0 0.000000 25 H4815 220814 WT 406.000000 76.0 2030.0 0.0 0.000000 26 H4817 220828 KO 756.000000 72.0 3780.0 0.0 0.000000 27 H4819 220929 KO 819.000000 70.0 4095.0 0.0 0.000000 28 H4820 221007 WT 408.000000 51.0 2040.0 0.0 0.000000 29 H4822 221023 KO 457.380767 29.0 2287.0 3.0 196.380767 30 H4823 221108 WT 116.000000 63.0 580.0 0.0 0.000000 31 H4824 221117 KO 518.000000 57.0 2590.0 0.0 0.000000 32 H4826 221203 WT 337.000000 72.0 1685.0 0.0 0.000000 33 H4827 221210 KO 391.000000 52.0 1955.0 0.0 0.000000 34 H4830 230406 WT 133.000000 62.0 665.0 0.0 0.000000 genotype cells rats r p spearman r_first_day cells_first_day x_range y_range 0 WT 378 6 0.8201 0.0 0.8306 0.8201 378 (0.001, 2.83) (0.003, 2.66) 1 KO 280 5 0.6505 0.0 0.7043 0.6505 280 (0.003, 2.29) (0.002, 2.356)
iso_rem_info, adult: cells by genotype
count median mean min max
genotype
KO 280 0.413 0.517 0.002 2.356
WT 378 0.332 0.462 0.003 2.660
per rat
count median mean
genotype animal
KO H4817 72 0.288 0.454
H4819 70 0.443 0.517
H4822 29 0.604 0.656
H4824 57 0.329 0.428
H4827 52 0.500 0.623
WT H4813 54 0.302 0.451
H4815 76 0.353 0.462
H4820 51 0.154 0.250
H4823 63 0.434 0.536
H4826 72 0.484 0.634
H4830 62 0.241 0.374
tests
test n coef_KO_minus_WT p
0 LME (main) 658 0.0724 0.2677
1 LME on log values 658 0.1533 0.4068
2 LME, archive labels 683 0.1095 0.1416
3 LME, REM inside exploration left out 658 0.0227 0.7278
4 Mann-Whitney on cells 658 0.0807 0.1611
5 t-test on animal means, t(9) = 1.17 11 0.0845 0.2722
variant, REM inside exploration left out:
genotype cells rats r p spearman r_first_day cells_first_day x_range y_range
0 WT 378 6 0.8201 0.0 0.8306 0.8201 378 (0.001, 2.83) (0.003, 2.66)
1 KO 280 5 0.6905 0.0 0.7713 0.6905 280 (0.003, 2.29) (0.002, 2.356)
run time so far 860 s
Result: fig4g-adult-isomap-rem-correlation partially reproduced; fig4h-adult-isomap-rem-similar reproduced. REM Isomap and waking real-HD information correlate with r = 0.820 over 378 WT cells (paper 0.82) and 0.651 over 280 Fmr1-/y cells (paper 0.80, below the bound of 0.72; 0.691 with the REM inside exploration left out). REM Isomap HD information does not differ between genotypes (median 0.413 in Fmr1-/y against 0.332 in WT; LME p = 0.27; with the REM inside exploration left out p = 0.73).
Session definition of the claims file¶
The analysis above cuts every exploration session to its first 20 min. The claims file defines the sessions as the same tracking blocks but cuts only a block longer than 30 min, to its first 1300 s. This cell repeats the main test of every claim with the claims file's definition, beside the 20 min sessions used above.
def rule_tables(key):
cr, rr = [], []
for r in results:
m = r["meta"]
if r[key] is None:
continue
base = {"subject": m["subject"], "session": m["session_id"], "age_group": m["age_group"], "genotype": m["genotype"],
"first_day": first_day[m["subject"]] == m["session_id"]}
rr.append({**base, **r[key]["rec"]})
c = r[key]["cells"].copy()
for k, v in base.items():
c[k] = v
cr.append(c)
c = pd.concat(cr, ignore_index=True)
c["animal"] = c.subject
return c, pd.DataFrame(rr)
def main_stats(c, rc):
rows = []
def lme(claim, age, col):
d = c[c.age_group == age]
coef, p, n = hdfx.lme_lrt(d, col)
rows.append({"claim": claim, "quantity": f"{col}: LME coef KO-WT; p", "value": f"{coef:.3f}; {p:.4f}", "n": n})
def rr(claim, age, x, y):
d = c[c.age_group == age].dropna(subset=[x, y])
for g in ("WT", "KO"):
e = d[d.genotype == g]
rows.append({"claim": claim, "quantity": f"r {g}", "value": f"{stats.pearsonr(e[x], e[y])[0]:.4f}", "n": len(e)})
def rat_t(claim, age, col):
am = rc[rc.age_group == age].dropna(subset=[col]).groupby(["subject", "genotype"])[col].mean().reset_index()
ko, wt = am.loc[am.genotype == "KO", col], am.loc[am.genotype == "WT", col]
t = stats.ttest_ind(ko, wt)
rows.append({"claim": claim, "quantity": f"{col}: rat means t; p", "value": f"{t.statistic:.2f}; {t.pvalue:.4f}", "n": len(am)})
for age, beh, met in (("juvenile", "figs1c", "figs1"), ("adult", "figs2c", "figs2")):
for col in ("inactive", "centre", "active_speed"):
rat_t(beh, age, col)
for col in ("contamination", "mean_rate", "peak_rate", "vector_length"):
lme(met, age, col)
j = {"tuning": "fig1ef", "halves": "fig1g", "offset": "fig1h", "drift": "fig1j", "epochs_r": "figs1j", "epochs_off": "figs1k",
"iso_r": "fig2c", "iso": "fig2d", "rem_r": "fig2g", "rem": "fig2h"}
a = {"tuning": "fig3ef", "halves": "fig3g", "offset": "fig3h", "drift": "fig3j", "epochs_r": "figs2j", "epochs_off": "figs2k",
"iso_r": "fig4c", "iso": "fig4d", "rem_r": "fig4g", "rem": "fig4h"}
for age, n in (("juvenile", j), ("adult", a)):
lme(n["tuning"], age, "hd_info")
lme(n["tuning"], age, "half_width")
rr(n["halves"], age, "info_half1", "info_half2")
lme(n["offset"], age, "offset_halves")
rat_t(n["drift"], age, "drift_mean")
rr(n["epochs_r"], age, "hd_info", "info_s2")
lme(n["epochs_off"], age, "offset_epochs")
rr(n["iso_r"], age, "real200_info", "iso_wake_info")
lme(n["iso"], age, "iso_wake_info")
rr(n["rem_r"], age, "real200_info", "iso_rem_info")
lme(n["rem"], age, "iso_rem_info")
return pd.DataFrame(rows)
cells_cf, recs_cf = rule_tables("claims_rule")
lens = recs[["subject", "session", "age_group", "genotype", "session_s"]].merge(
recs_cf[["subject", "session", "session_s", "n_cells"]], on=["subject", "session"], suffixes=("_20min", "_claims"))
lens["n_cells_20min"] = recs.n_cells.values
print("session lengths (s) under the two definitions, and cells of session 1:")
print(lens.to_string())
print("\nrecordings whose sessions differ:", int((lens.session_s_20min.astype(str) != lens.session_s_claims.astype(str)).sum()), "of", len(lens))
print("cells per group, claims file definition:")
print(cells_cf.groupby(["age_group", "genotype"]).agg(rats=("subject", "nunique"), cells=("unit", "size")).to_string())
cmp = main_stats(cells, recs).merge(main_stats(cells_cf, recs_cf), on=["claim", "quantity"], suffixes=("_20min", "_claims"))
print("\nmain test of each claim under the two session definitions:")
print(cmp.to_string())
cj = cells_cf[cells_cf.age_group == "juvenile"]
print("\nvariants under the claims file definition, juveniles:")
for name, d in (("first day", cj[cj.first_day]), ("H3026 left out", cj[cj.subject != "H3026"])):
for col in ("hd_info", "offset_halves", "iso_wake_info", "iso_rem_info"):
coef, p, n = hdfx.lme_lrt(d, col)
print(f" {name}, {col}: coef {coef:.3f}, p = {p:.4f} (n = {n})")
for g in ("WT", "KO"):
e = d[d.genotype == g].dropna(subset=["info_half1", "info_half2"])
print(f" {name}, halves r {g}: {stats.pearsonr(e.info_half1, e.info_half2)[0]:.4f} ({len(e)} cells)")
session lengths (s) under the two definitions, and cells of session 1:
subject session age_group genotype session_s_20min session_s_claims n_cells n_cells_20min
0 H3001 200201 juvenile WT [1200.0, 1200.0] [1662.8, 1527.1] 18 18
1 H3001 200202 juvenile WT [1200.0] [1300.0] 13 13
2 H3003 200207 juvenile KO [1200.0, 1183.6] [1227.2, 1183.6] 33 33
3 H3003 200208 juvenile KO [1200.0, 1200.0] [1203.6, 1201.6] 19 19
4 H3006 200314_1 juvenile WT [1200.0, 1200.0] [1271.9, 1511.7] 28 28
5 H3006 200314_2 juvenile WT [1200.0, 1121.3] [1208.5, 1121.3] 23 23
6 H3008 200805 juvenile KO [1200.0, 1200.0] [1273.4, 1211.9] 24 24
7 H3008 200807 juvenile KO [1200.0, 1200.0] [1238.0, 1245.8] 13 13
8 H3009 200812 juvenile WT [1200.0, 1200.0] [1304.9, 1278.9] 30 30
9 H3009 200813 juvenile WT [1200.0, 1200.0] [1245.3, 1432.6] 26 26
10 H3015 210416_1 juvenile WT [1200.0, 1200.0] [1300.0, 1300.0] 27 27
11 H3015 210416_2 juvenile WT [1200.0, 1200.0] [1335.7, 1254.8] 33 33
12 H3015 210417 juvenile WT [1200.0, 1200.0] [1301.5, 1520.7] 15 15
13 H3016 210422 juvenile KO [1200.0, 1200.0] [1263.8, 1235.2] 11 11
14 H3016 210423 juvenile KO [1200.0, 1200.0] [1234.5, 1533.7] 30 30
15 H3019 210617 juvenile KO [1200.0, 1200.0] [1229.7, 1263.4] 10 10
16 H3019 210618_1 juvenile KO [1200.0] [1232.9] 5 5
17 H3022 210805 juvenile WT [1200.0, 1200.0] [1229.1, 1231.6] 18 18
18 H3022 210806 juvenile WT [1200.0, 1200.0] [1219.3, 1355.1] 29 29
19 H3023 210812 juvenile WT [1200.0, 1200.0] [1219.6, 1300.0] 19 19
20 H3023 210813_1 juvenile WT [1200.0, 1200.0] [1210.6, 1300.0] 22 22
21 H3026 211003 juvenile KO [1200.0, 1200.0] [1285.8, 1300.0] 49 49
22 H3026 211004_2 juvenile KO [1200.0, 1200.0] [1215.0, 1300.0] 43 43
23 H3029 230510 juvenile WT [1200.0, 1200.0] [1228.6, 1254.2] 22 22
24 H4813 220728 adult WT [1200.0, 1200.0] [1218.5, 1227.2] 54 54
25 H4815 220814 adult WT [1200.0, 1200.0] [1289.3, 1269.2] 76 76
26 H4817 220828 adult KO [1200.0, 1200.0] [1249.5, 1228.1] 72 72
27 H4819 220929 adult KO [1200.0, 1200.0] [1257.7, 1224.2] 71 71
28 H4820 221007 adult WT [1200.0, 1200.0] [1263.7, 1242.1] 51 51
29 H4822 221023 adult KO [1200.0, 1200.0] [1222.2, 1245.0] 30 30
30 H4823 221108 adult WT [1200.0, 1200.0] [1230.0, 1288.8] 80 80
31 H4824 221117 adult KO [1200.0, 1200.0] [1464.7, 1271.4] 57 57
32 H4826 221203 adult WT [1200.0, 1200.0] [1285.9, 1271.2] 72 72
33 H4827 221210 adult KO [1200.0, 1200.0] [1247.1, 1218.3] 52 52
34 H4830 230406 adult WT [1200.0, 1200.0] [1278.3, 1302.8] 62 62
recordings whose sessions differ: 35 of 35
cells per group, claims file definition:
rats cells
age_group genotype
adult KO 5 282
WT 6 395
juvenile KO 5 237
WT 7 323
main test of each claim under the two session definitions:
claim quantity value_20min n_20min value_claims n_claims
0 figs1c inactive: rat means t; p -0.90; 0.3918 12 -0.95; 0.3666 12
1 figs1c centre: rat means t; p 1.86; 0.0931 12 1.91; 0.0847 12
2 figs1c active_speed: rat means t; p 2.10; 0.0625 12 2.22; 0.0504 12
3 figs1 contamination: LME coef KO-WT; p -0.005; 0.7092 560 -0.005; 0.7092 560
4 figs1 mean_rate: LME coef KO-WT; p -0.389; 0.7154 560 -0.383; 0.7197 560
5 figs1 peak_rate: LME coef KO-WT; p -1.130; 0.6163 560 -1.185; 0.6028 560
6 figs1 vector_length: LME coef KO-WT; p 0.098; 0.1116 560 0.099; 0.1062 560
7 figs2c inactive: rat means t; p 0.11; 0.9120 11 -0.03; 0.9774 11
8 figs2c centre: rat means t; p -0.97; 0.3550 11 -0.99; 0.3474 11
9 figs2c active_speed: rat means t; p 0.40; 0.7018 11 0.44; 0.6729 11
10 figs2 contamination: LME coef KO-WT; p -0.014; 0.1110 677 -0.014; 0.1110 677
11 figs2 mean_rate: LME coef KO-WT; p -0.782; 0.3408 677 -0.763; 0.3547 677
12 figs2 peak_rate: LME coef KO-WT; p -2.148; 0.1006 677 -2.133; 0.1021 677
13 figs2 vector_length: LME coef KO-WT; p -0.062; 0.2552 677 -0.063; 0.2476 677
14 fig1ef hd_info: LME coef KO-WT; p 0.338; 0.0303 560 0.335; 0.0312 560
15 fig1ef half_width: LME coef KO-WT; p -18.891; 0.5371 560 -16.330; 0.5966 560
16 fig1g r WT 0.8151 323 0.7610 323
17 fig1g r KO 0.8354 237 0.8385 237
18 fig1h offset_halves: LME coef KO-WT; p -24.100; 0.0353 559 -26.844; 0.0138 559
19 fig1j drift_mean: rat means t; p -1.91; 0.0845 12 -2.04; 0.0685 12
20 figs1j r WT 0.8534 309 0.8551 309
21 figs1j r KO 0.7533 225 0.7576 226
22 figs1k offset_epochs: LME coef KO-WT; p 2.314; 0.8659 534 0.626; 0.9624 535
23 fig2c r WT 0.8151 323 0.8256 323
24 fig2c r KO 0.9098 232 0.9097 232
25 fig2d iso_wake_info: LME coef KO-WT; p 0.196; 0.0556 555 0.180; 0.0794 555
26 fig2g r WT 0.8311 323 0.8326 323
27 fig2g r KO 0.8332 231 0.8313 231
28 fig2h iso_rem_info: LME coef KO-WT; p 0.207; 0.0451 554 0.207; 0.0451 554
29 fig3ef hd_info: LME coef KO-WT; p -0.074; 0.5534 677 -0.070; 0.5750 677
30 fig3ef half_width: LME coef KO-WT; p -10.902; 0.5903 677 -8.572; 0.6604 677
31 fig3g r WT 0.8038 395 0.8090 395
32 fig3g r KO 0.7477 282 0.7423 282
33 fig3h offset_halves: LME coef KO-WT; p 32.055; 0.0298 677 30.904; 0.0415 677
34 fig3j drift_mean: rat means t; p 2.93; 0.0168 11 2.75; 0.0226 11
35 figs2j r WT 0.7866 395 0.7862 395
36 figs2j r KO 0.5617 276 0.5701 276
37 figs2k offset_epochs: LME coef KO-WT; p 37.021; 0.0282 671 37.641; 0.0292 671
38 fig4c r WT 0.9447 395 0.9370 395
39 fig4c r KO 0.6139 282 0.6037 282
40 fig4d iso_wake_info: LME coef KO-WT; p -0.020; 0.7869 677 -0.019; 0.7984 677
41 fig4g r WT 0.8201 378 0.8200 378
42 fig4g r KO 0.6505 280 0.6516 280
43 fig4h iso_rem_info: LME coef KO-WT; p 0.072; 0.2677 658 0.072; 0.2677 658
variants under the claims file definition, juveniles:
first day, hd_info: coef 0.459, p = 0.0364 (n = 289)
first day, offset_halves: coef -38.061, p = 0.0064 (n = 288)
first day, iso_wake_info: coef 0.217, p = 0.2054 (n = 289)
first day, iso_rem_info: coef 0.200, p = 0.1578 (n = 288)
first day, halves r WT: 0.6496 (162 cells)
first day, halves r KO: 0.8971 (127 cells)
H3026 left out, hd_info: coef 0.301, p = 0.0742 (n = 468)
H3026 left out, offset_halves: coef -26.619, p = 0.0280 (n = 467)
H3026 left out, iso_wake_info: coef 0.193, p = 0.0977 (n = 463)
H3026 left out, iso_rem_info: coef 0.191, p = 0.0949 (n = 462)
H3026 left out, halves r WT: 0.7610 (323 cells)
H3026 left out, halves r KO: 0.8693 (145 cells)
Result. With the claims file's definition every recording's sessions differ from the 20 min sessions, by up to 463 s (session 1 of H3001 200201 lasts 1663 s), and session 1 holds the same cells. One main test changes its outcome. For fig1g WT r falls from 0.815 to 0.761 and Fmr1-/y r is 0.839, so neither value is within tolerance and the claim is not reproduced under the rule used for the correlation claims; the third round of verification agreed with this change of outcome. The other tests stay on the same side of their criterion: figs1c active speed p = 0.0504, fig1ef HD information p = 0.031, fig1h p = 0.014, fig1j p = 0.069, fig2d p = 0.079, fig3h p = 0.042, fig3j p = 0.023, and the correlations of figs1j, fig2c, fig2g, fig3g, figs2j, fig4c and fig4g keep the same values within and outside tolerance. REM Isomap information (fig2h, p = 0.045) is the same under both definitions, as it does not use the sessions and the cells are the same; its change from not reproduced in the first round came from fitting Isomap on every bin.
Summary¶
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.
| Claim | Outcome |
|---|---|
| unit-counts | partially reproduced (3 of 4 groups exact; adult Fmr1-/y 440 units in 5 rats) |
| units-per-recording | partially reproduced (juvenile 8 to 83; adult 55 to 114 for all units) |
| figs1c-juvenile-behaviour-similar | reproduced (active speed p = 0.063; first day p = 0.034) |
| figs2c-adult-behaviour-similar | reproduced |
| figs1-juvenile-cell-metrics-similar | reproduced |
| figs2-adult-cell-metrics-similar | reproduced |
| fig1ef-juvenile-sharper-tuning | partially reproduced (HD information p = 0.030, half-width p = 0.54) |
| fig1g-juvenile-halves-correlation | not reproduced (claims file's sessions: WT r 0.761 below 0.81, Fmr1-/y 0.839 below 0.855; with 20 min sessions WT 0.815 is within) |
| fig1h-juvenile-smaller-offset | reproduced (p = 0.035) |
| fig1j-juvenile-less-drift | not reproduced (p = 0.085, same direction) |
| figs1j-juvenile-epochs-correlation | partially reproduced |
| figs1k-juvenile-epoch-drift-similar | reproduced |
| fig2c-juvenile-isomap-wake-correlation | reproduced |
| fig2d-juvenile-isomap-wake-sharper | not reproduced (p = 0.056, same direction) |
| fig2g-juvenile-isomap-rem-correlation | partially reproduced |
| fig2h-juvenile-isomap-rem-sharper | reproduced (p = 0.045) |
| fig3ef-adult-tuning-similar | reproduced |
| fig3g-adult-halves-correlation | not reproduced (r 0.804 and 0.748 against 0.94) |
| fig3h-adult-larger-offset | reproduced (p = 0.030) |
| fig3j-adult-more-drift | reproduced |
| figs2j-adult-epochs-correlation | not reproduced (r 0.787 and 0.562 against 0.90 and 0.76) |
| figs2k-adult-epoch-drift-larger | reproduced |
| fig4c-adult-isomap-wake-correlation | partially reproduced |
| fig4d-adult-isomap-wake-similar | reproduced |
| fig4g-adult-isomap-rem-correlation | partially reproduced |
| fig4h-adult-isomap-rem-similar | reproduced |
| figs1d-probe-in-posub | blocked (histology without annotation) |
Several juvenile results sit near the 0.05 threshold and depend on the grouping. HD information (fig1ef, p = 0.030), the offset between halves (fig1h, p = 0.035) and REM Isomap information (fig2h, p = 0.045) lose significance with the archive's labels and with H3026 left out; fig1ef and fig1h hold with the first day of each rat alone, fig2h does not. Waking (fig2d) and REM (fig2h) Isomap information fall on opposite sides of 0.05 (p = 0.056 and 0.045) with LME coefficients of 0.196 and 0.207.
How the analysis differs from the paper's. The genotype of H3026 and the age group of H3029 are taken from the paper's unit counts, not from the archive; the archive's labels and the juvenile results with H3026 left out are shown as variants. H4825's file is a re-timed copy of H4824's recording, so the adult Fmr1-/y group has 5 rats where the paper has 6. Cells re-recorded on consecutive days could not be excluded (the files give no probe depth per day), so they are counted on each day; the first day of each rat is shown as a variant. Exploration sessions are taken from the tracking, as the epoch tables do not mark them reliably, and cut to 20 min, the paper's session length. This departs from the claims file, which cuts only blocks over 30 min, to 1300 s, and the change was made after the first round of verification. Under the claims file's definition fig1g has neither correlation within tolerance (WT r 0.761, Fmr1-/y 0.839), so its outcome is not reproduced, following the claims file; no other outcome changes. The LME is a random-intercept linear model on the raw values; the paper chose between linear, lognormal and gamma models by the data. The decoder follows version 2's Methods, as version 1 gives none. Contamination above 0.5 is excluded, reading the Methods' "below 0.5" as a slip. The offsets include weakly tuned cells; cells with half-width below 120 degrees are shown as a variant.
What was found about the dandiset. The archive's genotype of H3026 and date of birth of H3029
disagree with the paper's counts, which they match when H3026 is a juvenile Fmr1-/y rat and H3029 a
juvenile WT rat; the birth dates of H3023 and H3026 are after their recordings, which gives them
negative ages in the archive's asset metadata, and no NWB file sets the age. H4825's file holds
H4824's recording, re-timed to H4825's epochs and clipped at its end, so one adult Fmr1-/y rat's data
are missing. The units table has no cell type, quality or depth. The epoch and task tables mislabel or
merge sessions in several files and one file has a single epoch. Two files give positions in pixels
while stating centimetres, with head direction on another range; in the others y starts at exactly 0.
One unit has unsorted spike times, and juvenile files repeat tracking timestamps. The archive's
about field lists the Fmr1 protein under anatomy with the identifier of the disorder.