Reproducing Tingley & Buzsáki (2018) from dandiset 000213¶
Paper. Tingley D, Buzsáki G (2018). Transformation of a spatial map across the hippocampal-lateral septal circuit. Neuron 98, 1229-1242. doi:10.1016/j.neuron.2018.04.028. This attempt used the full text of the NIH author manuscript in PubMed Central (PMC6605060): Results, figure legends and STAR Methods. The supplementary figures were not read.
Dandiset. DANDI:000213, version 0.250624.0438. The paper cites no version (its data statement says the data were being prepared for CRCNS). There are two published versions, 0.220127.1738 and 0.250624.0438; they hold the same 67 files with the same asset identifiers and sizes (checked below) and differ only in dandiset-level metadata, so the most recent is pinned.
What the dandiset holds. 67 sessions from the five rats (DT2, DT5, DT7, DT8, DT9): sorted units
labelled by region (ls, hpc, ca3 and a few others), LFP at 1250 Hz, head position, and trials.
The paper's processed files (linearized behaviour, trial conditions, the CA1 channel of each session)
are not in it; they are rebuilt here as described in lshpc.py.
Code read. The paper's figure scripts, https://github.com/DavidTingley/papers (LS_phasecoding, commit 9f4cd48a44f211956954558b66d776ccbb74d693); buzcode, https://github.com/buzsakilab/buzcode (commit e615663b2b100782d1f378580f6d7aaa35c12937); and the per-cell decoder in https://github.com/DavidTingley/scratch (commit 2f804532290774f52a442bf0f3ec23dd5398d58d). The functions that bin phases (bz_phaseMap2Bins), compute information (olypherInfo) and detect assemblies are not public.
Claims. The claims file is claims/000213/10.1016-j.neuron.2018.04.028.yaml.
| Claim | Tested here |
|---|---|
| ls-neuron-count: 1,647 LS neurons, 62 sessions | Tested |
| hpc-unit-count: 2,297 CA1 and 654 CA3 units | Tested |
| ls-active-neurons: 840 LS neurons fire at least 1.5 spikes per trial | Tested |
| fig2-ls-phase-vs-shuffle: 89% of LS neurons code position in phase | Tested |
| fig2-ls-phase-beats-rate: phase beats rate in 786/840 neurons, 3,046/4,393 conditions, 62/62 sessions | Tested |
| fig2e-ls-phase-lower-mse: phase MSE below rate MSE across LS conditions and sessions | Tested |
| fig2fg-mse-difference: mean phase minus rate MSE, LS and hippocampus | Tested |
| fig1i-hpc-rate-phase-equivalent: rate and phase decoding equivalent for place fields | Tested |
| ls-few-place-fields: 5.3% of LS and 31.7% of hippocampal rate maps have place fields | Tested |
| hpc-place-field-properties: 711 of 1,425 neurons with fields, 8.5 Hz, 38 bins | Tested |
| ls-place-fields-unstable: LS fields less stable (41.5 against 10) | Tested |
| fig1e-phase-info-smaller-scale: peak information at 15 (phase) and 29 (rate) bins | Tested |
| fig1g-phase-more-info-fine-scale: phase more informative below 6 cm, rate above 10 cm | Tested |
| fig4d-depth-gradient: phase coding grows with LS depth | Tested |
| fig4e-onset-depth: onset phase correlates with depth | Tested |
| fig6c-ca3-coherence-increases: LS-CA3 theta coherence rises along the run | Tested |
| fig6d-cfc-stronger-ca3: theta-gamma coupling rises, stronger for CA3 | Tested |
| figs7-ensemble-ls-phase-best: LS ensemble phases beat hippocampal ensembles | Tested |
| fig5-assemblies: 18.5% of pairs form gamma assemblies | Tested on a random sample of 1% of the pairs |
| ls-information-lower: 0.4 against 1.7 bits/cm | Tested |
| fig5g-assembly-neurons-stronger-phase | Blocked: not runnable (needs the assemblies of every pair) |
| fig6e-assembly-position | Blocked: not runnable (needs the assemblies of every pair) |
| speed-independent: 2.8% of conditions speed-related | Blocked: methods underspecified |
| figs6-reference-frame: maze rotation | Blocked: metadata insufficient |
| fig7-dynamic-weighting-model: spiking model | Blocked: other (a simulation) |
Revision after the first verification round. Place fields now use the Gaussian rate map that the paper's code passes to bz_getPlaceFields1D (SD 4 bins), where the first version used the 5-bin box map; Figure 6 groups sessions by their unit labels, as its criterion states, and leaves out sessions without hippocampal units; the ensemble tests are one-sided; the theta reference of each session is described and the phase claims are repeated on sessions with a clear theta rhythm; fig5-assemblies is tested on a sample of pairs and ls-information-lower is tested, with criteria added to the claims file in this revision.
Second revision. The sentences the second verifier found unsupported are corrected, and three variants are added: place fields without the rule dropping peaks whose SD across trials exceeds their mean, the onset-phase test on sessions with one theta reference label per rat, and the peer prediction with the LS unit's spatial tuning as a covariate. No outcome changed.
The whole notebook streams the data and takes about twelve to fifteen minutes on four processes, most of it the per-cell decoding and the peer prediction.
import os
os.environ.setdefault("OMP_NUM_THREADS", "1")
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
import time
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy import stats
import lshpc
warnings.filterwarnings("ignore", category=RuntimeWarning)
pd.set_option("display.width", 220)
pd.set_option("display.max_columns", 40)
pd.set_option("display.max_rows", 200)
started = time.time()
results = lshpc.run_all(workers=4)
print(f"streamed and analysed {len(results)} files of dandiset {lshpc.DANDISET_ID} "
f"version {lshpc.DANDISET_VERSION} in {time.time() - started:.0f} s")
errors = [(r["summary"]["path"], r["error"]) for r in results if "error" in r]
print("files that failed:", errors if errors else "none")
S = pd.DataFrame([r["summary"] for r in results])
S["session"] = S.index
S["name"] = S.session_id.str.slice(0, 32)
C = pd.DataFrame([dict(c, session=i, subject=results[i]["summary"]["subject"])
for i, r in enumerate(results) for c in r.get("cells", [])])
C["neuron"] = list(zip(C.session, C.unit))
A = C[C.active].copy() # included cell and condition pairs
LS = A[A.region == "ls"]
HP = A[A.region == "hpc"]
LSd = LS[LS.mse_phase.notna()] # decoded (session has a theta channel)
HPd = HP[HP.mse_phase.notna()]
streamed and analysed 67 files of dandiset 000213 version 0.250624.0438 in 864 s files that failed: none
Data check¶
Each check of the metadata against the values is stated under its output.
from dandi.dandiapi import DandiAPIClient
with DandiAPIClient() as client:
ds = client.get_dandiset(lshpc.DANDISET_ID, lshpc.DANDISET_VERSION)
meta = ds.get_raw_metadata()
versions = [v.identifier for v in client.get_dandiset(lshpc.DANDISET_ID).get_versions()]
listing = {}
for v in versions:
if v == "draft":
continue
listing[v] = {a.path: (a.identifier, a.size) for a in client.get_dandiset(lshpc.DANDISET_ID, v).get_assets()}
summary = meta["assetsSummary"]
print("Published versions:", [v for v in versions if v != "draft"])
pub = sorted(listing)
same = all(listing[pub[0]] == listing[v] for v in pub[1:])
print(f"Assets identical (path, asset id, size) across published versions: {same}; files: {len(listing[pub[0]])}")
print("Paper named by the dandiset:", [r.get("identifier") for r in meta.get("relatedResource", [])])
print("assetsSummary: subjects", summary.get("numberOfSubjects"), "| species", [s["name"] for s in summary.get("species", [])],
"| variables", summary.get("variableMeasured"))
print("Subjects in the files:", sorted(S.subject.unique()), "| files per subject:", S.subject.value_counts().sort_index().to_dict())
Published versions: ['0.220127.1738', '0.250624.0438']
Assets identical (path, asset id, size) across published versions: True; files: 67
Paper named by the dandiset: ['https://doi.org/10.1016/j.neuron.2018.04.028']
assetsSummary: subjects 5 | species ['Rattus norvegicus - Norway rat'] | variables ['Position', 'CompassDirection', 'ElectricalSeries', 'LFP', 'Units', 'SpatialSeries']
Subjects in the files: ['DT2', 'DT5', 'DT7', 'DT8', 'DT9'] | files per subject: {'DT2': 11, 'DT5': 16, 'DT7': 9, 'DT8': 17, 'DT9': 14}
The two published versions (2022 and 2025) hold the same 67 files with the same asset identifiers and sizes; they differ only in dandiset-level metadata (contributor identifiers and affiliations, the citation). The newest is pinned. The archive's summary of five rats of one species matches the files. The paper's Methods state five rats, 3 male and 2 female; the files give no sex, so that cannot be checked.
units = (pd.DataFrame([dict(subject=s, location=l, n=n) for s, d in zip(S.subject, S.unit_locations) for l, n in d.items()])
.pivot_table(index="subject", columns="location", values="n", aggfunc="sum", fill_value=0))
units.loc["all"] = units.sum()
print("Units by region label and subject:")
print(units.to_string())
sess = pd.DataFrame([dict(subject=s, location=l) for s, d in zip(S.subject, S.unit_locations) for l in d])
print("\nSessions holding units of each label:", sess.location.value_counts().to_dict())
print("Files without units:", S[S.n_units == 0].session_id.tolist())
print("Units with spike times not in increasing order:", int(S.units_unsorted.sum()),
"in", S[S.units_unsorted > 0].session_id.tolist())
print("Units with spikes after the end of the LFP:", int(S.spikes_after_lfp_end.sum()))
print("\nElectrode labels per subject:")
for subj, g in S.groupby("subject"):
labs = {}
for d in g.electrode_locations:
for k, v in d.items():
labs[k] = labs.get(k, 0) + 1
print(f" {subj}: files with each label {labs}")
key = S[["n_spikes_total", "n_units"]].astype(str).agg("|".join, axis=1) + "|" + S.lfp_shape.astype(str)
print("\nFiles sharing total spikes, units and LFP shape:", S[key.duplicated(keep=False)].session_id.tolist())
print("Files sharing identical trial start times:", S[S.trial_starts_rounded.duplicated(keep=False)].session_id.tolist())
depth_rows = S[["subject", "session_id", "ls_depth", "hpc_depth", "has_hpc_units", "has_ca3_units"]]
print("\nDepths in the session names (um), first and second, with the hippocampal labels of the units:")
print(depth_rows.to_string(index=False))
Units by region label and subject:
location acg ca3 cc hpc ls ms ppc sFi unlabelled
subject
DT2 0 0 0 1035 375 0 28 0 0
DT5 0 279 0 329 480 0 0 0 0
DT7 31 0 6 446 60 25 0 54 43
DT8 0 0 0 0 296 0 32 0 0
DT9 0 345 0 783 485 0 0 0 0
all 31 624 6 2593 1696 25 60 54 43
Sessions holding units of each label: {'ls': 62, 'hpc': 36, 'ca3': 11, 'ppc': 2, 'acg': 2, 'cc': 2, 'ms': 2, 'unlabelled': 1, 'sFi': 1}
Files without units: ['20170324_576um_144um_170324_123932']
Units with spike times not in increasing order: 11 in ['DT2_rPPC_rCCG_3324um_1144um_20160219_160219_130435', 'DT2_rPPC_rCCG_3396um_1180um_20160220_160220_141839', '20161018_1552um_2304um_merge', '20161026_1944um_2232um_merge', '20170321_216um_0um_170321_120259', '20170201_72um_432um_merge']
Units with spikes after the end of the LFP: 0
Electrode labels per subject:
DT2: files with each label {np.str_('unknown'): 11}
DT5: files with each label {np.str_('hpc'): 10, np.str_('ls'): 16, np.str_('ca3'): 6}
DT7: files with each label {np.str_('acg'): 6, np.str_('cc'): 2, np.str_('hpc'): 9, np.str_('ls'): 9, np.str_('ms'): 6, np.str_('sFi'): 1}
DT8: files with each label {np.str_('hpc'): 17, np.str_('ls'): 17}
DT9: files with each label {np.str_('hpc'): 7, np.str_('ls'): 12, np.str_('unknown'): 2, np.str_('ca3'): 5}
Files sharing total spikes, units and LFP shape: []
Files sharing identical trial start times: []
Depths in the session names (um), first and second, with the hippocampal labels of the units:
subject session_id ls_depth hpc_depth has_hpc_units has_ca3_units
DT2 DT2_rPPC_rCCG_3324um_1000um_20160217_160217_103121 3324 1000 False False
DT2 DT2_rPPC_rCCG_3324um_1144um_20160219_160219_130435 3324 1144 True False
DT2 DT2_rPPC_rCCG_3396um_1180um_20160220_160220_141839 3396 1180 True False
DT2 DT2_rPPC_rCCG_3396um_1180um_20160221_160221_135947 3396 1180 True False
DT2 DT2_rPPC_rCCG_3468um_1216um_20160222_160222_120902 3468 1216 True False
DT2 DT2_rPPC_rCCG_3468um_1216um_20160223_160223_121321 3468 1216 True False
DT2 DT2_rPPC_rCCG_3468um_1216um_20160225_160225_130701 3468 1216 True False
DT2 DT2_rPPC_rCCG_3468um_1252um_20160226_160226_124132 3468 1252 True False
DT2 DT2_rPPC_rCCG_3540um_1288um_20160227_160227_121226 3540 1288 True False
DT2 DT2_rPPC_rCCG_3540um_1288um_20160228_160228_135001 3540 1288 True False
DT2 DT2_rPPC_rCCG_3612um_1360um_20160304_160304_150220 3612 1360 True False
DT5 20161011_972um_1224um_merge 972 1224 True False
DT5 20161014_1296um_1476um_merge 1296 1476 True False
DT5 20161015_1368um_1476um_merge 1368 1476 True False
DT5 20161016_1368um_1476um_merge 1368 1476 True False
DT5 20161018_1552um_2304um_merge 1552 2304 True True
DT5 20161019_1624um_2340um_161019_095311 1624 2340 True True
DT5 20161020_1768um_2376um_161020_102642 1768 2376 True False
DT5 20161021_1840um_2412um_merge 1840 2412 True True
DT5 20161023_1872um_2448um_161023_123504 1872 2448 True False
DT5 20161025_1944um_2232um_merge 1944 2232 True False
DT5 20161026_1944um_2232um_merge 1944 2232 True False
DT5 20161027_1944um_2232um_161027_194125 1944 2232 True False
DT5 20161030_2052um_2232um_161030_111142 2052 2232 True False
DT5 20161031_2088um_2232um_161031_104001 2088 2232 True True
DT5 20161101_2088um_2232um_merge 2088 2232 True True
DT5 20161104_2124um_2232um_merge 2124 2232 True True
DT7 20170315_288um_0um_170315_191240 288 0 True False
DT7 20170317_288um_0um_merge 288 0 False False
DT7 20170318_288um_0um_170318_115923 288 0 True False
DT7 20170320_432um_0um_merge 432 0 True False
DT7 20170321_216um_0um_170321_120259 216 0 True False
DT7 20170324_576um_144um_170324_123932 576 144 False False
DT7 20170325_576um_360um_170325_125511 576 360 True False
DT7 20170401_864um_936um_merge 864 936 True False
DT7 20170412_1440um_1170um_170412_103153 1440 1170 True False
DT8 20170125_0um_0um_merge 0 0 False False
DT8 20170128_0um_72um_merge 0 72 False False
DT8 20170201_72um_432um_merge 72 432 False False
DT8 20170202_72um_576um_170202_092033 72 576 False False
DT8 20170206_72um_1872um_merge 72 1872 False False
DT8 20170207_144um_1944um_merge 144 1944 False False
DT8 20170211_144um_1944um_merge 144 1944 False False
DT8 20170214_216um_1944um_170214_102804 216 1944 False False
DT8 20170215_216um_1944um_170215_140739 216 1944 False False
DT8 20170216_216um_1944um_merge 216 1944 False False
DT8 20170217_216um_1944um_merge 216 1944 False False
DT8 20170218_216um_1944um_170218_114724 216 1944 False False
DT8 20170221_324um_1944um_170221_101929 324 1944 False False
DT8 20170224_324um_2088um_170224_101710 324 2088 False False
DT8 20170305_468um_2088um_170305_135233 468 2088 False False
DT8 20170306_468um_2088um_170306_113628 468 2088 False False
DT8 20170308_612um_2088um_merge 612 2088 False False
DT9 20170429_0um_0um_merge 0 0 True False
DT9 20170430_0um_0um_merge 0 0 True False
DT9 20170501_216um_0um_170501_112210 216 0 True False
DT9 20170502_288um_0um_merge 288 0 True False
DT9 20170504_396um_0um_merge 396 0 True False
DT9 20170505_396um_0um_merge 396 0 True False
DT9 20170506_468um_36um_170506_111835 468 36 True False
DT9 20170507_468um_36um_merge 468 36 True False
DT9 20170509_468um_36um_170509_103451 468 36 True False
DT9 20170518_828um_864um_merge 828 864 True True
DT9 20170519_864um_900um_merge 864 900 True True
DT9 20170521_900um_936um_170521_125602 900 936 True True
DT9 20170522_900um_936um_170522_151132 900 936 True True
DT9 20170525_900um_936um_170525_150124 900 936 True True
Units carry a region label: ls (lateral septum), hpc, ca3, and a few cortical or other labels
(acg, cc, ms, ppc, sFi). One file (DT7, 20170317) has units without any label and is left
out of every count by region; one (DT7, 20170324) has no units. No two files share their spike
totals, unit counts and LFP length, or their trial times, so no recording was deposited twice.
Several sessions were recorded at the same depths on consecutive days (for example five DT8
sessions at 216 and 1944 um); each session's units are treated as separate units, as the paper's
counts do, and no claim assumes the same unit across sessions.
The electrode labels of sub-DT2 are all unknown; its hippocampal and LS channels are taken from
the electrode groups of its labelled units. The session names hold two depths that no metadata
describes. In DT9 the units are labelled ca3 exactly in the sessions whose second depth is 828 um
or more, which fits the second depth being the hippocampal probe's; the first depth is taken as the
LS probe's. This is an assumption, used only by the depth claims. It is not settled by the other
rats: in DT5 the files labelled hpc and ca3 alternate at second depths of 2232 to 2448 um, and the
DT8 depths (0 to 612 and 0 to 2088 um) do not say which probe is which.
pos = S[["subject", "name", "task", "position_unit_stated", "position_extent_stated_units", "position_unit_used",
"position_dt_median", "position_dt", "position_nonincreasing_steps", "position_z_equals_y",
"position_nan_fraction", "path_length_median"]].copy()
pos["extent_1_99"] = pos.position_extent_stated_units.round(2)
print(pos.drop(columns="position_extent_stated_units").round(4).to_string(index=False))
odd = S[(S.position_unit_stated != "pixels") & (((S.position_unit_stated == "mm") & (S.position_extent_stated_units < 10)) |
((S.position_unit_stated == "m") & (S.position_extent_stated_units > 10)))]
print(f"\nFiles whose stated position unit disagrees with the values: {len(odd)}:", odd.name.tolist())
print("Files whose third position column equals the second:", int(S.position_z_equals_y.sum()), "of", len(S))
print("Files with repeated or decreasing position timestamps:", S[S.position_nonincreasing_steps > 0].name.tolist())
subject name task position_unit_stated position_unit_used position_dt_median position_dt position_nonincreasing_steps position_z_equals_y position_nan_fraction path_length_median extent_1_99
DT2 DT2_rPPC_rCCG_3324um_1000um_2016 wheel_alternation_task pixels pixels 0.0333 0.0333 0 True 0.9395 1013.4146 399.29
DT2 DT2_rPPC_rCCG_3324um_1144um_2016 wheel_alternation_task pixels pixels 0.0333 0.0333 0 True 0.9027 990.4751 390.51
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 284650 True 0.8663 1041.9535 411.93
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 503067 True 0.8905 1063.7525 397.92
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 335021 True 0.8771 1037.1292 404.21
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 159069 True 0.3060 1037.3105 351.77
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 387416 True 0.4805 1055.0257 342.19
DT2 DT2_rPPC_rCCG_3468um_1252um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 575713 True 0.9223 1029.4623 397.52
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 wheel_alternation_task pixels pixels 0.0333 0.0333 0 True 0.8333 991.4633 393.74
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 wheel_alternation_task pixels pixels 0.0000 0.0333 218643 True 0.6671 1059.5769 369.89
DT2 DT2_rPPC_rCCG_3612um_1360um_2016 wheel_alternation_task pixels pixels 0.0300 0.0333 12865 True 0.0695 974.7727 418.39
DT5 20161011_972um_1224um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 215.0444 1.38
DT5 20161014_1296um_1476um_merge central_alternation_task m cm 0.0084 0.0083 0 True 0.0000 220.1540 1.01
DT5 20161015_1368um_1476um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 219.8351 1.02
DT5 20161016_1368um_1476um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 221.8106 1.11
DT5 20161018_1552um_2304um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 224.0515 1.08
DT5 20161019_1624um_2340um_161019_09 central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 221.5655 1.04
DT5 20161020_1768um_2376um_161020_10 central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 218.9629 1.11
DT5 20161021_1840um_2412um_merge linear_task m cm 0.0083 0.0083 0 True 0.8735 131.2191 1.44
DT5 20161023_1872um_2448um_161023_12 central_alternation_task m cm 0.0083 0.0083 0 True 0.4663 219.5207 0.97
DT5 20161025_1944um_2232um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.8670 224.3449 1.47
DT5 20161026_1944um_2232um_merge linear_task m cm 0.0083 0.0083 0 True 0.8977 129.7367 1.39
DT5 20161027_1944um_2232um_161027_19 central_alternation_task m cm 0.0083 0.0083 0 True 0.0071 220.6123 1.01
DT5 20161030_2052um_2232um_161030_11 central_alternation_task m cm 0.0083 0.0083 0 True 0.8982 219.3806 1.08
DT5 20161031_2088um_2232um_161031_10 wheel_alternation_task m cm 0.0083 0.0083 0 True 0.9143 222.8863 1.13
DT5 20161101_2088um_2232um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.0000 220.8995 1.43
DT5 20161104_2124um_2232um_merge central_alternation_task m cm 0.0083 0.0083 0 True 0.8465 225.6465 1.12
DT7 20170315_288um_0um_170315_191240 wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0482 273.5789 1024.96
DT7 20170317_288um_0um_merge linear_task mm cm 0.0083 0.0083 0 True 0.0000 129.1852 1599.63
DT7 20170318_288um_0um_170318_115923 wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 273.1420 1105.68
DT7 20170320_432um_0um_merge wheel_alternation_task mm cm 0.0083 0.0357 0 True 0.0013 278.3766 1506.73
DT7 20170321_216um_0um_170321_120259 wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 276.9192 1431.41
DT7 20170324_576um_144um_170324_1239 wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 273.7343 998.76
DT7 20170325_576um_360um_170325_1255 wheel_alternation_task m cm 0.0083 0.0084 0 True 0.0000 282.6229 1.06
DT7 20170401_864um_936um_merge linear_task mm cm 0.0083 0.0083 0 True 0.0000 153.0244 1577.03
DT7 20170412_1440um_1170um_170412_10 both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 256.7746 1583.51
DT8 20170125_0um_0um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 222.1212 1.14
DT8 20170128_0um_72um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 231.7116 1.26
DT8 20170201_72um_432um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 224.3831 1.30
DT8 20170202_72um_576um_170202_09203 central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 229.4058 1.28
DT8 20170206_72um_1872um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 224.3654 1181.80
DT8 20170207_144um_1944um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 221.6774 1196.79
DT8 20170211_144um_1944um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 232.2945 1.31
DT8 20170214_216um_1944um_170214_102 central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 223.8942 1036.90
DT8 20170215_216um_1944um_170215_140 central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 226.1991 1178.78
DT8 20170216_216um_1944um_merge both_alternation_task mm cm 0.0084 0.0083 0 True 0.0000 233.6049 1179.19
DT8 20170217_216um_1944um_merge both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 239.0856 1.22
DT8 20170218_216um_1944um_170218_114 both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 248.3878 1.15
DT8 20170221_324um_1944um_170221_101 central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 221.5746 1142.28
DT8 20170224_324um_2088um_170224_101 central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 232.6887 1231.67
DT8 20170305_468um_2088um_170305_135 central_alternation_task mm cm 0.0084 0.0083 0 True 0.0000 227.1590 1182.31
DT8 20170306_468um_2088um_170306_113 both_alternation_task mm cm 0.0084 0.0083 0 True 0.0000 253.3195 1.18
DT8 20170308_612um_2088um_merge both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 272.3338 1240.09
DT9 20170429_0um_0um_merge central_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 230.3910 1074.36
DT9 20170430_0um_0um_merge wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 289.4971 1216.18
DT9 20170501_216um_0um_170501_112210 both_alternation_task mm cm 0.0083 0.0092 0 True 0.0000 133.7079 1742.27
DT9 20170502_288um_0um_merge linear_task mm cm 0.0083 0.0083 0 True 0.0000 150.8991 1736.98
DT9 20170504_396um_0um_merge linear_task mm cm 0.0083 0.0083 0 True 0.0000 170.2450 1736.25
DT9 20170505_396um_0um_merge both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 269.9068 1103.78
DT9 20170506_468um_36um_170506_11183 both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 244.7696 1043.45
DT9 20170507_468um_36um_merge linear_task mm cm 0.0083 0.0083 0 True 0.0000 145.1550 1773.56
DT9 20170509_468um_36um_170509_10345 both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 225.0518 1103.24
DT9 20170518_828um_864um_merge both_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 248.0722 1142.68
DT9 20170519_864um_900um_merge wheel_alternation_task mm cm 0.0083 0.0083 0 True 0.0000 224.3662 1621.40
DT9 20170521_900um_936um_170521_1256 linear_task mm cm 0.0083 0.0083 0 True 0.0000 132.3526 1734.94
DT9 20170522_900um_936um_170522_1511 linear_task mm cm 0.0083 0.0083 0 True 0.0000 161.2094 1657.93
DT9 20170525_900um_936um_170525_1501 linear_task mm cm 0.0083 0.0083 0 True 0.0000 150.5245 1704.10
Files whose stated position unit disagrees with the values: 8: ['20170125_0um_0um_merge', '20170128_0um_72um_merge', '20170201_72um_432um_merge', '20170202_72um_576um_170202_09203', '20170211_144um_1944um_merge', '20170217_216um_1944um_merge', '20170218_216um_1944um_170218_114', '20170306_468um_2088um_170306_113']
Files whose third position column equals the second: 67 of 67
Files with repeated or decreasing position timestamps: ['DT2_rPPC_rCCG_3396um_1180um_2016', 'DT2_rPPC_rCCG_3396um_1180um_2016', 'DT2_rPPC_rCCG_3468um_1216um_2016', 'DT2_rPPC_rCCG_3468um_1216um_2016', 'DT2_rPPC_rCCG_3468um_1216um_2016', 'DT2_rPPC_rCCG_3468um_1252um_2016', 'DT2_rPPC_rCCG_3540um_1288um_2016', 'DT2_rPPC_rCCG_3612um_1360um_2016']
Position is stated in m, mm or pixels. Eight DT8 files state mm but hold values spanning about
1.1 to 1.3, which are metres (a maze of about a metre across; the same rat's other files span 1000
to 1200 mm). The unit used here is inferred from the extent: below 10 the values are taken as
metres, otherwise as millimetres; sub-DT2 positions stay in pixels, with no scale given. In every
file the third position column (z) is a copy of the second (y). In eight of the eleven sub-DT2 files
position timestamps repeat or go back (the count of such steps is printed), so the time per sample
is taken as the session's span over its sample count, which gives 33.3 ms (30 Hz) in every sub-DT2
file. The median path of a trial is 2.2 to 2.9 m on
the alternation mazes and 1.3 to 1.7 m on the linear track (outside sub-DT2), against the paper's
maze of about 3.2 m; the paper gives no other maze dimensions in the main text.
tr = S[["subject", "name", "task", "n_trials", "trial_s_median", "trial_types", "directions", "conditions_used",
"trials_without_positions", "trials_after_position_end"]]
print(tr.to_string(index=False))
print("\nTrial types:", sorted({str(t) for x in S.trial_types for t in x}), "| directions:", sorted({str(t) for x in S.directions for t in x}))
print("Files whose trials carry no type or direction:", S[S.trial_types.apply(lambda x: x == [""])].name.tolist())
print("Conditions with at least 10 trials, all files:", int(S.conditions_used.sum()))
subject name task n_trials trial_s_median trial_types directions conditions_used trials_without_positions trials_after_position_end
DT2 DT2_rPPC_rCCG_3324um_1000um_2016 wheel_alternation_task 69 4.933333 [wheel alternation] [clockwise, counter-clockwise] 4 0 0
DT2 DT2_rPPC_rCCG_3324um_1144um_2016 wheel_alternation_task 84 4.683333 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 wheel_alternation_task 71 4.500000 [wheel alternation] [clockwise, counter-clockwise] 2 0 0
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 wheel_alternation_task 121 5.233281 [wheel alternation] [clockwise, counter-clockwise] 4 0 1
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task 100 4.650000 [wheel alternation] [clockwise, counter-clockwise] 5 0 0
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task 115 4.300000 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 wheel_alternation_task 113 4.500000 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT2 DT2_rPPC_rCCG_3468um_1252um_2016 wheel_alternation_task 134 4.400000 [wheel alternation] [clockwise, counter-clockwise] 5 0 0
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 wheel_alternation_task 207 4.733333 [wheel alternation] [clockwise, counter-clockwise] 7 0 0
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 wheel_alternation_task 106 4.500000 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT2 DT2_rPPC_rCCG_3612um_1360um_2016 wheel_alternation_task 30 3.590000 [wheel alternation] [clockwise, counter-clockwise] 0 0 0
DT5 20161011_972um_1224um_merge central_alternation_task 186 3.733333 [central alternation] [clockwise, counter-clockwise] 7 0 1
DT5 20161014_1296um_1476um_merge central_alternation_task 151 4.433333 [central alternation] [clockwise, counter-clockwise] 5 0 1
DT5 20161015_1368um_1476um_merge central_alternation_task 115 4.125000 [central alternation] [clockwise, counter-clockwise] 5 0 1
DT5 20161016_1368um_1476um_merge central_alternation_task 33 4.350000 [central alternation] [clockwise, counter-clockwise] 2 0 1
DT5 20161018_1552um_2304um_merge central_alternation_task 213 3.791667 [central alternation] [clockwise, counter-clockwise] 7 0 1
DT5 20161019_1624um_2340um_161019_09 central_alternation_task 238 3.804167 [central alternation] [clockwise, counter-clockwise] 8 0 1
DT5 20161020_1768um_2376um_161020_10 central_alternation_task 245 3.716667 [central alternation] [clockwise, counter-clockwise] 6 0 1
DT5 20161021_1840um_2412um_merge linear_task 54 2.354167 [] [] 2 0 0
DT5 20161023_1872um_2448um_161023_12 central_alternation_task 138 3.737500 [central alternation] [clockwise, counter-clockwise] 7 0 0
DT5 20161025_1944um_2232um_merge central_alternation_task 117 4.091667 [central alternation] [clockwise, counter-clockwise] 4 0 0
DT5 20161026_1944um_2232um_merge linear_task 57 1.981250 [] [] 2 0 1
DT5 20161027_1944um_2232um_161027_19 central_alternation_task 190 3.641667 [central alternation] [clockwise, counter-clockwise] 7 0 0
DT5 20161030_2052um_2232um_161030_11 central_alternation_task 225 3.633333 [central alternation] [clockwise, counter-clockwise] 6 0 0
DT5 20161031_2088um_2232um_161031_10 wheel_alternation_task 185 3.508333 [wheel alternation] [clockwise, counter-clockwise] 7 0 0
DT5 20161101_2088um_2232um_merge central_alternation_task 76 3.433333 [central alternation] [clockwise, counter-clockwise] 2 0 1
DT5 20161104_2124um_2232um_merge central_alternation_task 150 4.677995 [central alternation] [clockwise, counter-clockwise] 8 0 1
DT7 20170315_288um_0um_170315_191240 wheel_alternation_task 123 4.250000 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT7 20170317_288um_0um_merge linear_task 76 2.033333 [] [] 2 0 0
DT7 20170318_288um_0um_170318_115923 wheel_alternation_task 252 4.283333 [wheel alternation] [clockwise, counter-clockwise] 7 0 0
DT7 20170320_432um_0um_merge wheel_alternation_task 326 3.916667 [wheel alternation] [clockwise, counter-clockwise] 8 0 0
DT7 20170321_216um_0um_170321_120259 wheel_alternation_task 249 4.418750 [wheel alternation] [clockwise, counter-clockwise] 6 0 1
DT7 20170324_576um_144um_170324_1239 wheel_alternation_task 121 4.550000 [wheel alternation] [clockwise, counter-clockwise] 6 0 0
DT7 20170325_576um_360um_170325_1255 wheel_alternation_task 239 3.958333 [wheel alternation] [clockwise, counter-clockwise] 7 0 0
DT7 20170401_864um_936um_merge linear_task 81 2.008333 [] [] 2 0 0
DT7 20170412_1440um_1170um_170412_10 both_alternation_task 76 3.637338 [central alternation, wheel alternation] [clockwise, counter-clockwise] 2 0 0
DT8 20170125_0um_0um_merge central_alternation_task 17 4.416475 [central alternation] [clockwise, counter-clockwise] 1 0 0
DT8 20170128_0um_72um_merge central_alternation_task 71 3.666667 [central alternation] [clockwise, counter-clockwise] 4 0 1
DT8 20170201_72um_432um_merge central_alternation_task 137 3.583333 [central alternation] [clockwise, counter-clockwise] 4 0 1
DT8 20170202_72um_576um_170202_09203 central_alternation_task 116 3.761924 [central alternation] [clockwise, counter-clockwise] 4 0 0
DT8 20170206_72um_1872um_merge central_alternation_task 146 3.404167 [central alternation] [clockwise, counter-clockwise] 5 0 1
DT8 20170207_144um_1944um_merge central_alternation_task 174 3.208333 [] [] 4 0 1
DT8 20170211_144um_1944um_merge central_alternation_task 74 3.391667 [central alternation] [clockwise, counter-clockwise] 4 0 1
DT8 20170214_216um_1944um_170214_102 central_alternation_task 242 3.749825 [central alternation] [clockwise, counter-clockwise] 6 0 0
DT8 20170215_216um_1944um_170215_140 central_alternation_task 72 3.329167 [central alternation] [clockwise, counter-clockwise] 3 0 1
DT8 20170216_216um_1944um_merge both_alternation_task 264 3.497641 [central alternation, wheel alternation] [clockwise, counter-clockwise] 10 0 1
DT8 20170217_216um_1944um_merge both_alternation_task 226 3.579167 [central alternation, wheel alternation] [clockwise, counter-clockwise] 5 0 1
DT8 20170218_216um_1944um_170218_114 both_alternation_task 254 3.983163 [central alternation, wheel alternation] [clockwise, counter-clockwise] 9 0 0
DT8 20170221_324um_1944um_170221_101 central_alternation_task 199 3.279948 [central alternation, wheel alternation] [clockwise, counter-clockwise] 12 0 1
DT8 20170224_324um_2088um_170224_101 central_alternation_task 210 3.395955 [] [] 7 0 1
DT8 20170305_468um_2088um_170305_135 central_alternation_task 209 3.353125 [central alternation] [clockwise, counter-clockwise] 6 0 1
DT8 20170306_468um_2088um_170306_113 both_alternation_task 234 4.408333 [central alternation, wheel alternation] [clockwise, counter-clockwise] 8 0 1
DT8 20170308_612um_2088um_merge both_alternation_task 92 3.799825 [central alternation, wheel alternation] [clockwise, counter-clockwise] 3 0 0
DT9 20170429_0um_0um_merge central_alternation_task 160 3.925000 [central alternation, wheel alternation] [clockwise, counter-clockwise] 8 0 1
DT9 20170430_0um_0um_merge wheel_alternation_task 159 4.391667 [wheel alternation] [clockwise, counter-clockwise] 5 0 1
DT9 20170501_216um_0um_170501_112210 both_alternation_task 175 4.750000 [central alternation, wheel alternation] [clockwise, counter-clockwise] 0 0 1
DT9 20170502_288um_0um_merge linear_task 60 2.033333 [] [] 2 0 0
DT9 20170504_396um_0um_merge linear_task 56 2.433225 [] [] 2 0 0
DT9 20170505_396um_0um_merge both_alternation_task 221 4.125000 [central alternation, wheel alternation] [clockwise, counter-clockwise] 10 0 1
DT9 20170506_468um_36um_170506_11183 both_alternation_task 293 3.933333 [central alternation, wheel alternation] [clockwise, counter-clockwise] 13 0 1
DT9 20170507_468um_36um_merge linear_task 62 1.712500 [] [] 2 0 0
DT9 20170509_468um_36um_170509_10345 both_alternation_task 263 3.541667 [central alternation, wheel alternation] [clockwise, counter-clockwise] 9 0 1
DT9 20170518_828um_864um_merge both_alternation_task 315 3.683333 [central alternation, wheel alternation] [clockwise, counter-clockwise] 11 0 1
DT9 20170519_864um_900um_merge wheel_alternation_task 85 3.208333 [central alternation] [clockwise, counter-clockwise] 4 0 1
DT9 20170521_900um_936um_170521_1256 linear_task 93 1.641600 [] [] 2 0 0
DT9 20170522_900um_936um_170522_1511 linear_task 105 2.108333 [] [] 2 0 0
DT9 20170525_900um_936um_170525_1501 linear_task 57 1.916667 [] [] 2 0 0
Trial types: ['', 'central alternation', 'wheel alternation'] | directions: ['', 'clockwise', 'counter-clockwise']
Files whose trials carry no type or direction: ['20161021_1840um_2412um_merge', '20161026_1944um_2232um_merge', '20170317_288um_0um_merge', '20170401_864um_936um_merge', '20170207_144um_1944um_merge', '20170224_324um_2088um_170224_101', '20170502_288um_0um_merge', '20170504_396um_0um_merge', '20170507_468um_36um_merge', '20170521_900um_936um_170521_1256', '20170522_900um_936um_170522_1511', '20170525_900um_936um_170525_1501']
Conditions with at least 10 trials, all files: 349
The trials table has trial_type (central or wheel alternation) and direction (clockwise or
counter-clockwise) for the alternation tasks, and only start and stop times on the linear track and
in two DT8 alternation files (20170207 and 20170224).
Trials last a median of 1.6 to 5.2 s. The paper's trial conditions are not in the dandiset; the
conditions formed here (type, direction, start and end site) give 0 to 13 conditions of at least
10 trials per file. DT9 20170501 has none: its trials do not start or end at common sites (see the
clock check below).
lf = S[["subject", "name", "lfp_shape", "lfp_chunks", "lfp_rate", "lfp_start", "lfp_conversion", "hpc_channels_from",
"n_hpc_channels", "n_ls_channels", "theta_channel", "ls_channel"]].copy()
sel = [d if isinstance(d, dict) else {} for d in S.theta_channel_selection]
lf["theta_label"] = [d.get("label") for d in sel]
lf["theta_ratio"] = [d.get("theta_ratio", np.nan) for d in sel]
lf["median_ratio"] = [d.get("median_theta_ratio", np.nan) for d in sel]
lf["psd_peak_hz"] = [d.get("psd_peak_hz", np.nan) for d in sel]
lf["theta_contrast"] = [d.get("theta_peak_over_neighbours", np.nan) for d in sel]
lf["lfp_conversion"] = lf.lfp_conversion.map("{:.3g}".format)
S["theta_ratio"], S["theta_label"] = lf.theta_ratio.values, lf.theta_label.values
print(lf.round(2).to_string(index=False))
print("\nLFP sampling rates:", S.lfp_rate.unique(), "| starting times:", S.lfp_start.unique())
print("Files without a hippocampal channel (no theta reference):", S[~S.has_theta].name.tolist())
print("Hippocampal channel labels per file:", pd.Series([tuple(x) for x in S.hpc_channel_labels]).value_counts().to_dict(),
"| files with both hpc and ca3 channels:", int(sum(("hpc" in x) and ("ca3" in x) for x in S.hpc_channel_labels)))
print("Label of the theta channel, files:", lf.theta_label.value_counts(dropna=False).to_dict())
q = lf[lf.theta_ratio.notna()].groupby("subject").agg(files=("name", "size"), ratio_below_1=("theta_ratio", lambda x: int((x < 1).sum())),
ratio_min=("theta_ratio", "min"), ratio_max=("theta_ratio", "max"),
psd_peak_min=("psd_peak_hz", "min"), psd_peak_max=("psd_peak_hz", "max"),
contrast_median=("theta_contrast", "median"))
print("\nTheta channel per subject: 6-9 Hz over 1-4 Hz power, frequency of the spectral peak between 2 and 20 Hz, and the")
print("6-9 Hz peak over the mean power at 2-5 and 11-15 Hz (theta_contrast):")
print(q.round(2).to_string())
subject name lfp_shape lfp_chunks lfp_rate lfp_start lfp_conversion hpc_channels_from n_hpc_channels n_ls_channels theta_channel ls_channel theta_label theta_ratio median_ratio psd_peak_hz theta_contrast
DT2 DT2_rPPC_rCCG_3324um_1000um_2016 (32632065, 128) (500, 128) 1250.0 0.0 1.95e-07 groups of the units 0 52 NaN NaN NaN NaN NaN NaN NaN
DT2 DT2_rPPC_rCCG_3324um_1144um_2016 (27225225, 128) (212697, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 101.0 6.0 unknown 8.49 7.51 8.50 32.91
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 (17010855, 128) (132897, 1) 1250.0 0.0 1.95e-07 groups of the units 64 52 111.0 6.0 unknown 9.13 8.84 9.00 94.45
DT2 DT2_rPPC_rCCG_3396um_1180um_2016 (26425350, 128) (206448, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 123.0 6.0 unknown 8.97 7.58 8.75 80.22
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 (19182015, 128) (149859, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 73.0 6.0 unknown 12.89 12.72 8.75 115.84
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 (11191860, 128) (87436, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 98.0 6.0 unknown 12.66 12.64 8.50 131.01
DT2 DT2_rPPC_rCCG_3468um_1216um_2016 (21440742, 128) (167505, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 83.0 6.0 unknown 3.53 3.37 8.00 20.45
DT2 DT2_rPPC_rCCG_3468um_1252um_2016 (29556630, 128) (230911, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 113.0 6.0 unknown 7.58 7.24 9.00 131.59
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 (20994795, 128) (164021, 1) 1250.0 0.0 1.95e-07 groups of the units 64 64 113.0 6.0 unknown 8.66 8.26 9.00 99.03
DT2 DT2_rPPC_rCCG_3540um_1288um_2016 (14165685, 128) (110669, 1) 1250.0 0.0 1.95e-07 groups of the units 60 60 113.0 6.0 unknown 12.24 11.80 8.75 137.00
DT2 DT2_rPPC_rCCG_3612um_1360um_2016 (2054160, 128) (48144, 3) 1250.0 0.0 1.95e-07 groups of the units 60 60 111.0 6.0 unknown 9.10 7.54 8.75 81.35
DT5 20161011_972um_1224um_merge (41328630, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 41.0 4.0 hpc 2.27 2.26 8.75 25.91
DT5 20161014_1296um_1476um_merge (25007625, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 51.0 4.0 hpc 1.30 1.26 9.50 15.52
DT5 20161015_1368um_1476um_merge (21792600, 96) (227006, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 62.0 4.0 hpc 0.49 0.32 9.50 4.31
DT5 20161016_1368um_1476um_merge (3984120, 96) (83002, 2) 1250.0 0.0 1.95e-07 electrodes table 64 32 32.0 4.0 hpc 0.74 0.71 9.50 8.11
DT5 20161018_1552um_2304um_merge (38386485, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 ca3 0.60 0.49 9.50 2.54
DT5 20161019_1624um_2340um_161019_09 (29323260, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 ca3 0.48 0.44 9.50 2.23
DT5 20161020_1768um_2376um_161020_10 (33005295, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 hpc 0.46 0.40 9.75 3.25
DT5 20161021_1840um_2412um_merge (35784945, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 ca3 0.72 0.70 2.00 3.55
DT5 20161023_1872um_2448um_161023_12 (5626440, 96) (117216, 2) 1250.0 0.0 1.95e-07 electrodes table 64 32 94.0 4.0 hpc 0.97 0.63 9.00 10.19
DT5 20161025_1944um_2232um_merge (33168195, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 84.0 4.0 hpc 0.63 0.59 2.50 2.65
DT5 20161026_1944um_2232um_merge (34552530, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 95.0 4.0 hpc 0.40 0.40 8.75 3.83
DT5 20161027_1944um_2232um_161027_19 (2841120, 96) (59190, 2) 1250.0 0.0 1.95e-07 electrodes table 64 32 80.0 4.0 hpc 0.62 0.59 9.25 3.94
DT5 20161030_2052um_2232um_161030_11 (31125000, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 81.0 4.0 hpc 0.62 0.57 9.00 3.31
DT5 20161031_2088um_2232um_161031_10 (39212055, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 95.0 4.0 ca3 0.33 0.33 2.00 1.99
DT5 20161101_2088um_2232um_merge (28839664, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 81.0 4.0 ca3 0.39 0.33 9.75 1.30
DT5 20161104_2124um_2232um_merge (30052035, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 81.0 4.0 ca3 0.59 0.55 9.25 3.50
DT7 20170315_288um_0um_170315_191240 (2680965, 128) (62835, 3) 1250.0 0.0 1.95e-07 electrodes table 64 23 0.0 81.0 hpc 3.00 2.86 9.00 29.14
DT7 20170317_288um_0um_merge (30896487, 128) (241378, 1) 1250.0 0.0 1.95e-07 electrodes table 64 64 59.0 96.0 hpc 4.38 3.95 9.00 16.32
DT7 20170318_288um_0um_170318_115923 (35846370, 128) (500, 128) 1250.0 0.0 1.95e-07 electrodes table 63 24 59.0 63.0 hpc 2.64 1.80 9.50 15.23
DT7 20170320_432um_0um_merge (37460925, 128) (500, 128) 1250.0 0.0 1.95e-07 electrodes table 64 23 49.0 80.0 hpc 2.86 1.89 9.25 78.81
DT7 20170321_216um_0um_170321_120259 (45056880, 128) (500, 128) 1250.0 0.0 1.95e-07 electrodes table 63 24 55.0 63.0 hpc 2.78 2.46 9.25 40.24
DT7 20170324_576um_144um_170324_1239 (12303900, 128) (96124, 1) 1250.0 0.0 1.95e-07 electrodes table 63 24 22.0 63.0 hpc 10.37 9.55 8.00 68.72
DT7 20170325_576um_360um_170325_1255 (37256670, 128) (500, 128) 1250.0 0.0 1.95e-07 electrodes table 64 21 49.0 87.0 hpc 1.19 1.18 9.50 17.84
DT7 20170401_864um_936um_merge (18219375, 128) (142338, 1) 1250.0 0.0 1.95e-07 electrodes table 63 24 17.0 96.0 hpc 0.71 0.68 8.75 5.32
DT7 20170412_1440um_1170um_170412_10 (33977565, 128) (500, 128) 1250.0 0.0 1.95e-07 electrodes table 63 17 24.0 110.0 hpc 1.03 1.01 8.00 8.88
DT8 20170125_0um_0um_merge (29268585, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 35.0 4.0 hpc 0.22 0.21 2.00 1.27
DT8 20170128_0um_72um_merge (24716295, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 55.0 4.0 hpc 2.68 2.67 8.75 18.17
DT8 20170201_72um_432um_merge (17565525, 96) (182974, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 95.0 4.0 hpc 1.51 1.28 9.25 10.98
DT8 20170202_72um_576um_170202_09203 (24669945, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 94.0 4.0 hpc 1.79 1.74 7.75 6.64
DT8 20170206_72um_1872um_merge (40832730, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 hpc 1.85 1.57 8.75 22.43
DT8 20170207_144um_1944um_merge (35203230, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 85.0 4.0 hpc 0.95 0.81 9.25 17.01
DT8 20170211_144um_1944um_merge (24766290, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 85.0 4.0 hpc 1.56 1.16 8.75 15.64
DT8 20170214_216um_1944um_170214_102 (25032105, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 90.0 4.0 hpc 1.04 0.80 8.75 10.76
DT8 20170215_216um_1944um_170215_140 (28069875, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 71.0 4.0 hpc 1.50 1.37 8.50 11.69
DT8 20170216_216um_1944um_merge (27245835, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 74.0 4.0 hpc 0.76 0.45 8.75 13.08
DT8 20170217_216um_1944um_merge (26107605, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 83.0 4.0 hpc 1.18 1.00 9.25 9.95
DT8 20170218_216um_1944um_170218_114 (22726485, 96) (236734, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 89.0 4.0 hpc 1.60 1.20 8.50 9.19
DT8 20170221_324um_1944um_170221_101 (25058835, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 91.0 4.0 hpc 1.33 1.32 8.75 12.94
DT8 20170224_324um_2088um_170224_101 (39324735, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 81.0 4.0 hpc 1.30 1.16 9.00 10.30
DT8 20170305_468um_2088um_170305_135 (20643750, 96) (215039, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 79.0 4.0 hpc 1.16 0.41 9.25 7.54
DT8 20170306_468um_2088um_170306_113 (36137382, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 91.0 4.0 hpc 0.49 0.44 9.25 4.66
DT8 20170308_612um_2088um_merge (37364535, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 77.0 4.0 hpc 0.97 0.37 9.25 8.20
DT9 20170429_0um_0um_merge (32214150, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 33.0 4.0 hpc 5.60 4.80 8.50 39.10
DT9 20170430_0um_0um_merge (6280380, 96) (65420, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 48.0 4.0 hpc 5.46 4.62 8.75 41.23
DT9 20170501_216um_0um_170501_112210 (40590585, 96) (500, 96) 1250.0 0.0 1.95e-07 groups of the units 64 32 93.0 4.0 unknown 4.98 4.84 8.25 33.15
DT9 20170502_288um_0um_merge (43905780, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 40.0 4.0 hpc 10.79 8.16 7.75 42.27
DT9 20170504_396um_0um_merge (43722495, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 43.0 4.0 hpc 3.01 3.00 8.75 23.20
DT9 20170505_396um_0um_merge (34992135, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 40.0 4.0 hpc 4.42 3.77 8.75 52.01
DT9 20170506_468um_36um_170506_11183 (33079905, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 48.0 4.0 hpc 4.61 4.38 8.75 58.25
DT9 20170507_468um_36um_merge (41310810, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 48.0 4.0 hpc 17.41 7.41 7.25 41.13
DT9 20170509_468um_36um_170509_10345 (33042915, 96) (500, 96) 1250.0 0.0 1.95e-07 groups of the units 40 24 43.0 4.0 unknown 5.92 5.70 8.25 37.59
DT9 20170518_828um_864um_merge (41010480, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 54.0 4.0 ca3 0.59 0.58 9.00 4.38
DT9 20170519_864um_900um_merge (30231900, 96) (500, 96) 1250.0 0.0 1.95e-07 electrodes table 64 32 54.0 4.0 ca3 0.66 0.63 9.00 10.20
DT9 20170521_900um_936um_170521_1256 (20646270, 96) (215065, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 52.0 4.0 ca3 2.61 2.60 7.75 16.74
DT9 20170522_900um_936um_170522_1511 (8425305, 96) (87763, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 50.0 4.0 ca3 1.81 1.81 7.75 10.46
DT9 20170525_900um_936um_170525_1501 (8969220, 96) (93429, 1) 1250.0 0.0 1.95e-07 electrodes table 64 32 48.0 4.0 ca3 1.22 1.11 8.75 11.02
LFP sampling rates: [1250.] | starting times: [0.]
Files without a hippocampal channel (no theta reference): ['DT2_rPPC_rCCG_3324um_1000um_2016']
Hippocampal channel labels per file: {('hpc',): 43, ('unknown',): 12, ('ca3',): 11, (): 1} | files with both hpc and ca3 channels: 0
Label of the theta channel, files: {'hpc': 43, 'unknown': 12, 'ca3': 11, nan: 1}
Theta channel per subject: 6-9 Hz over 1-4 Hz power, frequency of the spectral peak between 2 and 20 Hz, and the
6-9 Hz peak over the mean power at 2-5 and 11-15 Hz (theta_contrast):
files ratio_below_1 ratio_min ratio_max psd_peak_min psd_peak_max contrast_median
subject
DT2 10 0 3.53 12.89 8.00 9.00 96.74
DT5 16 14 0.33 2.27 2.00 9.75 3.52
DT7 9 1 0.71 10.37 8.00 9.50 17.84
DT8 17 5 0.22 2.68 2.00 9.25 10.76
DT9 14 2 0.59 17.41 7.25 9.00 35.37
The LFP is stored at 1250 Hz from time 0 in every file, as the paper's code assumes
(phases(round(t*1250))). 42 files chunk it as 500 samples by all channels, so the analysis reads
only the trials (with 1 s on each side), two channels at a time. One file (DT2, 20160217) has no
hippocampal units or labelled hippocampal channels, so it has no theta reference: its LS units are
counted, but not decoded.
No file has both hpc and ca3 channels: the hippocampal channels of a file carry one label (43
files hpc, 11 ca3, and 12 unknown, taken from the groups of the hpc units). In the 11 files
with ca3 channels the theta reference is therefore a CA3 channel. The paper's code does the same
for a session without a CA1 channel (it uses sessionInfo.ca1, else sessionInfo.ca3), but the paper's
Figure 6A counts 63 CA1 and 19 CA3 sessions, so its sessions had CA1 channels that are not labelled
here.
The theta reference is weak in DT5. On the chosen channel, 6 to 9 Hz power is below 1 to 4 Hz power in 14 of 16 DT5 files (ratio 0.33 to 2.27), and the 6 to 9 Hz peak stands a median 3.5 times above the power at 2 to 5 and 11 to 15 Hz, against medians of 11 to 97 in the other rats. The spectral peak between 2 and 20 Hz is at 2 to 2.5 Hz in three DT5 files and one DT8 file, and at 7.25 to 9.75 Hz in all others. The phase claims are repeated on the sessions whose ratio is above 1.
lags = list(lshpc.TRIAL_SHIFTS_S)
sp = pd.DataFrame([r["summary"]["clock_trial_speed"] for r in results], index=S.name)
sp_peak = sp.idxmax(axis=1)
print("Mean running speed (position units per s) inside the trial windows shifted by each lag (s); peak lag per file:")
print(pd.concat([sp.round(1), sp_peak.rename("peak")], axis=1).to_string())
print("\nPeak lag of speed inside trials, files per lag:", sp_peak.value_counts().sort_index().to_dict())
ratio = sp[0.0] / sp[[-3.0, 3.0]].mean(axis=1)
print("Speed at lag 0 over speed at +-3 s, median", round(float(ratio.median()), 2), "| range", round(float(ratio.min()), 2), "to", round(float(ratio.max()), 2))
lfp_lags = list(lshpc.LFP_LAGS_MS)
lk = pd.DataFrame([r.get("clock_lfp", {}) for r in results], index=S.name)
ok = lk.notna().all(axis=1)
lk_peak = lk[ok].idxmax(axis=1)
print("\nTheta phase locking (mean resultant length) of hippocampal spikes, LFP shifted by each lag (ms):")
print(pd.concat([lk[ok].round(3), lk_peak.rename("peak")], axis=1).to_string())
print("Files per peak lag (ms):", lk_peak.value_counts().sort_index().to_dict())
print("Locking at 0 ms over locking at +-200 ms, median",
round(float((lk[ok][0] / lk[ok][[-200, 200]].mean(axis=1)).median()), 2))
rt = pd.DataFrame([r["summary"]["clock_trial_rate"] or {} for r in results], index=S.name).dropna()
rt_peak = rt.idxmax(axis=1)
print("\nMean firing rate of all units in the trial windows shifted by each lag, files per peak lag:",
rt_peak.value_counts().sort_index().to_dict())
Mean running speed (position units per s) inside the trial windows shifted by each lag (s); peak lag per file:
-3.0 -2.0 -1.0 -0.5 0.0 0.5 1.0 2.0 3.0 peak
name
DT2_rPPC_rCCG_3324um_1000um_2016 109.2 146.3 187.1 206.9 218.6 215.0 203.4 163.3 121.2 0.0
DT2_rPPC_rCCG_3324um_1144um_2016 112.3 150.2 190.9 210.5 221.5 219.0 204.1 159.1 117.2 0.0
DT2_rPPC_rCCG_3396um_1180um_2016 97.7 138.8 183.5 204.7 225.5 226.2 215.9 171.6 126.2 0.5
DT2_rPPC_rCCG_3396um_1180um_2016 60.6 77.0 107.8 125.6 142.7 160.9 172.6 164.3 134.6 1.0
DT2_rPPC_rCCG_3468um_1216um_2016 96.3 134.8 180.9 202.9 220.5 221.1 211.9 168.0 122.9 0.5
DT2_rPPC_rCCG_3468um_1216um_2016 92.7 137.8 186.0 208.9 228.9 227.0 215.1 165.6 116.5 0.0
DT2_rPPC_rCCG_3468um_1216um_2016 106.5 142.3 184.9 205.5 217.1 214.2 199.9 154.5 114.5 0.0
DT2_rPPC_rCCG_3468um_1252um_2016 90.8 133.6 181.5 204.0 224.6 225.6 215.3 169.0 121.6 0.5
DT2_rPPC_rCCG_3540um_1288um_2016 107.0 143.7 186.6 206.0 220.4 217.6 208.5 167.2 127.7 0.0
DT2_rPPC_rCCG_3540um_1288um_2016 110.2 148.5 193.2 215.0 227.5 225.9 212.8 168.3 126.0 0.0
DT2_rPPC_rCCG_3612um_1360um_2016 103.3 155.7 219.5 251.0 276.5 285.7 269.0 196.7 123.2 0.5
20161011_972um_1224um_merge 18.0 27.9 43.2 51.6 57.2 55.4 50.6 38.2 23.0 0.0
20161014_1296um_1476um_merge 23.9 29.8 40.1 45.8 49.5 47.8 44.3 36.0 27.7 0.0
20161015_1368um_1476um_merge 20.8 28.2 39.1 45.7 50.2 48.5 45.2 36.2 26.9 0.0
20161016_1368um_1476um_merge 21.1 28.4 41.1 47.3 51.2 49.6 46.3 36.8 25.7 0.0
20161018_1552um_2304um_merge 24.0 30.4 44.7 53.5 59.9 58.0 52.2 38.4 26.2 0.0
20161019_1624um_2340um_161019_09 21.6 29.4 43.9 52.3 58.2 56.4 51.2 38.0 24.3 0.0
20161020_1768um_2376um_161020_10 19.5 28.9 44.0 52.9 59.4 57.8 52.2 37.8 22.7 0.0
20161021_1840um_2412um_merge 18.8 23.7 38.4 48.6 58.5 58.6 50.5 27.9 15.5 0.5
20161023_1872um_2448um_161023_12 18.1 29.2 42.9 50.8 55.9 53.1 48.4 35.2 20.5 0.0
20161025_1944um_2232um_merge 21.1 28.8 40.5 47.4 52.2 50.6 46.3 34.8 24.3 0.0
20161026_1944um_2232um_merge 15.5 18.3 34.8 46.9 62.1 60.0 48.3 22.3 12.4 0.0
20161027_1944um_2232um_161027_19 20.1 31.4 46.1 54.3 58.4 55.2 49.0 34.1 20.4 0.0
20161030_2052um_2232um_161030_11 22.3 29.9 43.9 52.3 58.7 56.4 50.5 36.3 23.8 0.0
20161031_2088um_2232um_161031_10 28.6 34.3 45.6 53.8 59.5 56.9 51.4 38.6 28.8 0.0
20161101_2088um_2232um_merge 28.2 32.8 48.7 59.0 65.8 63.0 56.7 40.2 27.2 0.0
20161104_2124um_2232um_merge 23.5 28.8 39.2 44.4 47.4 45.3 41.4 32.9 26.3 0.0
20170315_288um_0um_170315_191240 27.0 37.5 52.0 59.4 64.5 62.5 57.1 43.2 31.1 0.0
20170317_288um_0um_merge 20.7 22.7 46.5 60.1 68.5 66.5 54.3 24.9 18.9 0.0
20170318_288um_0um_170318_115923 31.7 40.4 53.0 59.7 63.8 61.6 56.2 43.1 33.1 0.0
20170320_432um_0um_merge 39.1 43.8 58.0 66.6 72.0 68.9 62.1 48.0 38.8 0.0
20170321_216um_0um_170321_120259 28.8 38.6 51.8 58.9 63.9 61.4 56.0 43.2 32.3 0.0
20170324_576um_144um_170324_1239 27.4 36.4 48.7 55.2 60.6 59.9 55.6 43.3 32.2 0.0
20170325_576um_360um_170325_1255 36.0 41.0 55.8 64.5 70.0 67.3 60.9 46.4 37.5 0.0
20170401_864um_936um_merge 54.5 34.4 47.8 63.4 76.8 75.3 61.5 34.2 43.3 0.0
20170412_1440um_1170um_170412_10 27.2 33.1 52.9 64.4 72.5 70.4 61.3 38.7 29.9 0.0
20170125_0um_0um_merge 24.2 28.9 38.0 44.1 49.3 48.7 46.4 38.4 28.9 0.0
20170128_0um_72um_merge 26.6 35.3 48.5 56.7 62.4 58.7 52.4 40.2 25.4 0.0
20170201_72um_432um_merge 26.7 33.3 45.8 54.8 61.1 57.6 52.3 41.1 27.2 0.0
20170202_72um_576um_170202_09203 30.0 33.3 44.5 53.2 60.1 58.3 53.6 42.5 31.1 0.0
20170206_72um_1872um_merge 27.2 37.5 52.2 61.9 67.0 62.2 54.3 39.6 22.8 0.0
20170207_144um_1944um_merge 33.2 37.4 48.9 59.8 69.5 66.3 58.7 43.3 28.3 0.0
20170211_144um_1944um_merge 30.1 36.5 50.3 60.3 68.5 65.2 59.1 44.2 28.0 0.0
20170214_216um_1944um_170214_102 29.2 32.8 44.3 53.2 59.6 57.3 52.7 43.1 30.8 0.0
20170215_216um_1944um_170215_140 27.3 38.2 51.6 62.1 69.3 64.4 57.0 42.0 23.7 0.0
20170216_216um_1944um_merge 33.7 37.7 52.2 62.4 69.5 65.7 59.6 45.5 32.2 0.0
20170217_216um_1944um_merge 33.7 41.3 52.7 61.0 66.5 62.5 56.3 44.1 32.4 0.0
20170218_216um_1944um_170218_114 27.4 35.3 50.3 58.9 63.3 60.4 55.6 42.9 29.6 0.0
20170221_324um_1944um_170221_101 29.9 37.9 53.1 64.3 71.0 66.4 58.7 42.8 28.2 0.0
20170224_324um_2088um_170224_101 37.7 42.2 56.4 66.5 69.9 65.2 58.0 44.2 34.1 0.0
20170305_468um_2088um_170305_135 32.4 37.0 53.8 64.1 65.8 59.0 51.0 38.2 26.8 0.0
20170306_468um_2088um_170306_113 27.6 34.6 44.4 50.6 55.1 53.1 49.5 40.3 30.3 0.0
20170308_612um_2088um_merge 28.4 38.5 54.1 63.8 70.0 67.5 61.6 46.8 30.1 0.0
20170429_0um_0um_merge 29.9 33.3 44.5 52.9 58.0 55.5 50.0 39.8 29.9 0.0
20170430_0um_0um_merge 32.9 41.3 54.4 61.2 65.2 61.9 56.5 43.9 34.1 0.0
20170501_216um_0um_170501_112210 32.1 32.8 32.7 32.1 31.5 30.6 29.7 29.1 29.1 -2.0
20170502_288um_0um_merge 19.9 21.5 45.3 62.0 75.5 72.3 57.2 23.3 18.2 0.0
20170504_396um_0um_merge 34.8 28.0 40.4 55.3 70.2 70.8 61.5 36.4 26.3 0.5
20170505_396um_0um_merge 32.5 37.4 50.6 59.2 64.1 60.9 55.6 43.4 33.1 0.0
20170506_468um_36um_170506_11183 33.7 39.0 52.8 62.3 67.5 63.9 57.6 43.8 31.9 0.0
20170507_468um_36um_merge 28.9 24.8 51.4 72.4 87.4 80.0 57.7 19.7 28.1 0.0
20170509_468um_36um_170509_10345 25.3 36.0 49.7 58.8 63.6 58.6 51.2 38.1 23.6 0.0
20170518_828um_864um_merge 30.6 37.9 53.3 63.7 70.6 66.8 59.8 43.7 30.2 0.0
20170519_864um_900um_merge 22.7 35.6 50.7 62.8 70.9 65.9 57.4 40.4 20.1 0.0
20170521_900um_936um_170521_1256 34.5 19.8 47.1 70.4 87.4 84.0 59.5 17.1 27.3 0.0
20170522_900um_936um_170522_1511 32.5 24.0 46.3 65.5 79.5 76.3 61.7 26.4 24.8 0.0
20170525_900um_936um_170525_1501 24.1 22.9 51.2 70.2 82.6 75.7 57.0 21.0 20.7 0.0
Peak lag of speed inside trials, files per lag: {-2.0: 1, 0.0: 59, 0.5: 6, 1.0: 1}
Speed at lag 0 over speed at +-3 s, median 2.22 | range 1.03 to 4.45
Theta phase locking (mean resultant length) of hippocampal spikes, LFP shifted by each lag (ms):
-200 -175 -150 -125 -100 -75 -50 -25 0 25 50 75 100 125 150 175 200 peak
name
DT2_rPPC_rCCG_3324um_1144um_2016 0.139 0.145 0.151 0.157 0.162 0.167 0.170 0.173 0.175 0.176 0.175 0.174 0.172 0.169 0.164 0.159 0.153 25
DT2_rPPC_rCCG_3396um_1180um_2016 0.129 0.136 0.142 0.148 0.155 0.161 0.165 0.168 0.170 0.172 0.172 0.170 0.166 0.163 0.159 0.154 0.147 25
DT2_rPPC_rCCG_3396um_1180um_2016 0.140 0.145 0.150 0.156 0.160 0.164 0.168 0.171 0.173 0.173 0.173 0.172 0.170 0.167 0.164 0.159 0.155 25
DT2_rPPC_rCCG_3468um_1216um_2016 0.120 0.125 0.130 0.134 0.138 0.142 0.145 0.148 0.149 0.150 0.151 0.150 0.148 0.145 0.142 0.139 0.135 50
DT2_rPPC_rCCG_3468um_1216um_2016 0.173 0.180 0.186 0.193 0.198 0.203 0.208 0.212 0.214 0.216 0.216 0.215 0.213 0.210 0.207 0.202 0.197 50
DT2_rPPC_rCCG_3468um_1216um_2016 0.080 0.088 0.096 0.103 0.112 0.120 0.127 0.132 0.136 0.137 0.136 0.134 0.130 0.124 0.117 0.109 0.100 25
DT2_rPPC_rCCG_3468um_1252um_2016 0.151 0.157 0.161 0.165 0.169 0.173 0.176 0.178 0.179 0.180 0.181 0.180 0.178 0.176 0.173 0.170 0.166 50
DT2_rPPC_rCCG_3540um_1288um_2016 0.135 0.139 0.143 0.147 0.151 0.154 0.157 0.159 0.160 0.161 0.161 0.159 0.158 0.155 0.153 0.149 0.145 25
DT2_rPPC_rCCG_3540um_1288um_2016 0.161 0.167 0.172 0.177 0.182 0.187 0.191 0.194 0.196 0.197 0.198 0.197 0.194 0.191 0.188 0.184 0.179 50
DT2_rPPC_rCCG_3612um_1360um_2016 0.244 0.254 0.263 0.273 0.283 0.292 0.301 0.308 0.313 0.317 0.317 0.314 0.310 0.305 0.298 0.290 0.279 25
20161011_972um_1224um_merge 0.244 0.257 0.273 0.283 0.293 0.301 0.310 0.316 0.320 0.320 0.319 0.315 0.308 0.300 0.290 0.277 0.263 25
20161014_1296um_1476um_merge 0.039 0.046 0.053 0.057 0.062 0.069 0.076 0.079 0.080 0.080 0.080 0.080 0.075 0.070 0.068 0.067 0.063 50
20161015_1368um_1476um_merge 0.091 0.097 0.103 0.109 0.114 0.122 0.129 0.135 0.139 0.143 0.142 0.139 0.135 0.132 0.127 0.122 0.113 25
20161016_1368um_1476um_merge 0.100 0.109 0.120 0.128 0.129 0.132 0.138 0.145 0.146 0.140 0.140 0.142 0.136 0.125 0.120 0.114 0.110 0
20161018_1552um_2304um_merge 0.086 0.093 0.101 0.109 0.115 0.119 0.122 0.124 0.123 0.120 0.113 0.106 0.098 0.088 0.077 0.068 0.063 -25
20161019_1624um_2340um_161019_09 0.087 0.098 0.110 0.119 0.123 0.127 0.130 0.133 0.129 0.121 0.113 0.102 0.090 0.075 0.066 0.062 0.061 -25
20161020_1768um_2376um_161020_10 0.080 0.088 0.096 0.104 0.109 0.112 0.114 0.113 0.110 0.105 0.099 0.091 0.084 0.076 0.069 0.062 0.057 -50
20161021_1840um_2412um_merge 0.174 0.188 0.205 0.218 0.225 0.234 0.245 0.252 0.250 0.243 0.236 0.231 0.222 0.207 0.191 0.180 0.172 -25
20161023_1872um_2448um_161023_12 0.075 0.076 0.079 0.086 0.089 0.088 0.086 0.087 0.089 0.089 0.088 0.090 0.091 0.091 0.089 0.085 0.082 125
20161025_1944um_2232um_merge 0.105 0.112 0.118 0.124 0.131 0.135 0.139 0.143 0.144 0.143 0.140 0.134 0.126 0.120 0.114 0.108 0.101 0
20161026_1944um_2232um_merge 0.054 0.056 0.063 0.067 0.065 0.061 0.059 0.064 0.064 0.060 0.056 0.058 0.059 0.052 0.043 0.039 0.040 -125
20161027_1944um_2232um_161027_19 0.039 0.043 0.052 0.057 0.058 0.059 0.061 0.063 0.059 0.056 0.056 0.056 0.055 0.047 0.040 0.038 0.038 -25
20161030_2052um_2232um_161030_11 0.101 0.105 0.109 0.114 0.119 0.122 0.123 0.123 0.120 0.114 0.106 0.098 0.093 0.088 0.083 0.077 0.075 -50
20161031_2088um_2232um_161031_10 0.012 0.014 0.016 0.020 0.022 0.025 0.026 0.028 0.028 0.028 0.026 0.022 0.017 0.014 0.011 0.006 0.003 0
20161101_2088um_2232um_merge 0.058 0.062 0.067 0.073 0.077 0.079 0.079 0.078 0.076 0.072 0.068 0.063 0.058 0.053 0.045 0.039 0.032 -75
20161104_2124um_2232um_merge 0.095 0.100 0.106 0.111 0.115 0.118 0.120 0.120 0.118 0.112 0.105 0.098 0.092 0.087 0.081 0.077 0.073 -50
20170315_288um_0um_170315_191240 0.126 0.131 0.135 0.139 0.143 0.147 0.149 0.151 0.153 0.153 0.152 0.152 0.150 0.147 0.143 0.140 0.137 25
20170318_288um_0um_170318_115923 0.210 0.217 0.223 0.228 0.233 0.238 0.241 0.244 0.247 0.247 0.245 0.243 0.241 0.237 0.233 0.228 0.222 25
20170320_432um_0um_merge 0.122 0.126 0.130 0.134 0.137 0.139 0.142 0.145 0.146 0.145 0.144 0.144 0.144 0.141 0.137 0.134 0.132 0
20170321_216um_0um_170321_120259 0.129 0.134 0.138 0.142 0.145 0.148 0.151 0.153 0.153 0.153 0.153 0.153 0.151 0.148 0.145 0.142 0.139 0
20170325_576um_360um_170325_1255 0.050 0.051 0.053 0.056 0.059 0.061 0.062 0.064 0.065 0.066 0.066 0.066 0.067 0.066 0.063 0.061 0.061 100
20170401_864um_936um_merge 0.073 0.079 0.084 0.091 0.098 0.104 0.108 0.111 0.114 0.113 0.110 0.106 0.100 0.098 0.096 0.091 0.085 0
20170412_1440um_1170um_170412_10 0.116 0.118 0.120 0.121 0.121 0.123 0.124 0.124 0.122 0.118 0.116 0.116 0.114 0.109 0.105 0.103 0.103 -25
20170429_0um_0um_merge 0.127 0.133 0.138 0.144 0.149 0.153 0.156 0.160 0.162 0.164 0.164 0.163 0.162 0.159 0.155 0.151 0.146 50
20170430_0um_0um_merge 0.175 0.179 0.183 0.186 0.189 0.192 0.195 0.196 0.197 0.198 0.198 0.196 0.193 0.190 0.187 0.183 0.179 25
20170501_216um_0um_170501_112210 0.184 0.191 0.197 0.203 0.208 0.213 0.216 0.218 0.219 0.219 0.218 0.215 0.210 0.205 0.199 0.192 0.184 0
20170502_288um_0um_merge 0.185 0.193 0.200 0.207 0.212 0.216 0.220 0.222 0.222 0.220 0.218 0.214 0.209 0.202 0.194 0.187 0.179 -25
20170504_396um_0um_merge 0.130 0.137 0.143 0.148 0.153 0.158 0.162 0.165 0.165 0.166 0.166 0.165 0.162 0.159 0.156 0.154 0.151 50
20170505_396um_0um_merge 0.126 0.132 0.137 0.142 0.147 0.153 0.158 0.162 0.165 0.168 0.169 0.170 0.169 0.167 0.164 0.160 0.156 75
20170506_468um_36um_170506_11183 0.151 0.155 0.160 0.165 0.170 0.175 0.179 0.183 0.186 0.189 0.190 0.190 0.189 0.187 0.184 0.180 0.176 75
20170507_468um_36um_merge 0.157 0.161 0.165 0.167 0.170 0.172 0.174 0.174 0.172 0.169 0.166 0.162 0.156 0.148 0.141 0.134 0.127 -50
20170509_468um_36um_170509_10345 0.208 0.216 0.223 0.229 0.234 0.239 0.243 0.246 0.248 0.248 0.248 0.246 0.243 0.239 0.234 0.229 0.224 0
20170518_828um_864um_merge 0.184 0.190 0.198 0.205 0.212 0.219 0.223 0.225 0.225 0.224 0.220 0.215 0.208 0.201 0.195 0.187 0.180 0
20170519_864um_900um_merge 0.118 0.123 0.125 0.126 0.125 0.126 0.128 0.130 0.129 0.129 0.132 0.131 0.130 0.129 0.127 0.127 0.127 50
20170521_900um_936um_170521_1256 0.171 0.178 0.182 0.184 0.186 0.190 0.192 0.195 0.196 0.193 0.190 0.187 0.184 0.179 0.172 0.164 0.157 0
20170522_900um_936um_170522_1511 0.166 0.173 0.179 0.183 0.185 0.190 0.194 0.197 0.196 0.194 0.193 0.196 0.196 0.191 0.187 0.185 0.183 -25
20170525_900um_936um_170525_1501 0.155 0.162 0.166 0.166 0.168 0.171 0.171 0.171 0.170 0.171 0.171 0.171 0.168 0.165 0.164 0.162 0.158 50
Files per peak lag (ms): {-125: 1, -75: 1, -50: 4, -25: 7, 0: 10, 25: 11, 50: 9, 75: 2, 100: 1, 125: 1}
Locking at 0 ms over locking at +-200 ms, median 1.2
Mean firing rate of all units in the trial windows shifted by each lag, files per peak lag: {-3.0: 2, -2.0: 5, -1.0: 7, 0.0: 16, 0.5: 14, 1.0: 4, 2.0: 10, 3.0: 8}
Three clock checks, each a contrast between the true and shifted alignments.
- Positions against the trials table: running speed inside the trial windows peaks at a lag of 0 or 0.5 s in 65 of 67 files and is a median 2.2 times its value at 3 s, so positions and trials share a clock to within about half a second. In DT9 20170501 speed does not change with the lag (31.5 cm/s at 0 against 29.1 to 32.8 at other lags): its trials do not match its positions, and it is left out by the condition rule (no condition reaches 10 trials). In one DT2 file (20160221) speed peaks at a lag of 1 s; its trials may be offset from its positions by up to a second. This is consistent with the data, not proven for every trial.
- Spikes against the LFP: theta phase locking of hippocampal spikes peaks within 75 ms of zero lag in 44 of the 47 files with hippocampal units and a theta channel, and at 200 ms it is lower by a median of about a sixth (ratio 1.2). The contrast is weak: theta has a period of about 125 ms, so a shift of 200 ms is under two cycles. This is consistent with a shared clock to within about 100 ms, and does not prove it. It could not be checked in the 17 DT8 files and the three DT2 and DT7 files without labelled hippocampal units.
- Spikes against the trials: the mean rate of all units in the trial windows changes little with the lag (running modulates many LS units weakly or negatively), so this contrast does not settle the alignment of spikes and trials. It is not established for the LS-only sessions beyond the spike-LFP check of the other files.
print("processing/behavior/allocentric_frame_tracking, per subject:")
for subj, g in S.groupby("subject"):
held = [d for d in g.allocentric_frame_tracking if d]
print(f" {subj}: in {len(held)} of {len(g)} files;", held[0] if held else "")
processing/behavior/allocentric_frame_tracking, per subject:
DT2: in 0 of 11 files;
DT5: in 16 of 16 files; {'orientation/data': ((512745, 4), 'meters'), 'orientation/reference_frame': ((), ''), 'orientation/timestamps': ((512745,), 'seconds'), 'orientation description': '(x, y, z, w) orientation coordinates, orientation type: quaternion'}
DT7: in 9 of 9 files; {'orientation/data': ((257372, 4), 'meters'), 'orientation/reference_frame': ((), ''), 'orientation/timestamps': ((257372,), 'seconds'), 'orientation description': '(x, y, z, w) orientation coordinates, orientation type: quaternion'}
DT8: in 17 of 17 files; {'orientation/data': ((249460, 4), 'meters'), 'orientation/reference_frame': ((), ''), 'orientation/timestamps': ((249460,), 'seconds'), 'orientation description': '(x, y, z, w) orientation coordinates, orientation type: quaternion'}
DT9: in 14 of 14 files; {'orientation/data': ((301541, 4), 'meters'), 'orientation/reference_frame': ((), ''), 'orientation/timestamps': ((301541,), 'seconds'), 'orientation description': '(x, y, z, w) orientation coordinates, orientation type: quaternion'}
processing/behavior/allocentric_frame_tracking holds one series, orientation: a head-orientation
quaternion (x, y, z, w) with its timestamps, in every file of DT5, DT7, DT8 and DT9 and in none of
DT2. Its stated unit is metres, which does not apply to a quaternion. Nothing in it, or in the
trials table, marks a maze rotation, so figs6-reference-frame stays blocked.
LS neurons recorded (ls-neuron-count)¶
A total of 1,647 LS neurons were recorded from five animals, in 62 sessions.
ls_units = units["ls"]
print("LS units per subject:", ls_units.drop("all").to_dict(), "| total", int(ls_units["all"]))
n_ls_sessions = sum("ls" in d for d in S.unit_locations)
print("Sessions with LS units:", n_ls_sessions, "| subjects with LS units:", int((ls_units.drop("all") > 0).sum()))
print("Paper: 1,647 LS neurons, 62 sessions, five animals. Difference in units:",
int(ls_units["all"]) - 1647, f"({(int(ls_units['all']) - 1647) / 1647:+.1%})")
print("Unlabelled units (DT7 20170317), not counted:", int(units.loc["all"].get("unlabelled", 0)))
LS units per subject: {'DT2': 375, 'DT5': 480, 'DT7': 60, 'DT8': 296, 'DT9': 485} | total 1696
Sessions with LS units: 62 | subjects with LS units: 5
Paper: 1,647 LS neurons, 62 sessions, five animals. Difference in units: 49 (+3.0%)
Unlabelled units (DT7 20170317), not counted: 43
Result: reproduced. 1,696 units are labelled LS, 3.0% more than the paper's 1,647 and within tolerance, in 62 sessions as in the paper, and all five rats hold LS units.
Hippocampal units (hpc-unit-count)¶
The hippocampal recordings hold 2,297 isolated CA1 units and 654 CA3 units (2,951 in all).
ca1, ca3 = int(units.loc["all", "hpc"]), int(units.loc["all", "ca3"])
print("Units labelled hpc (taken as CA1) per subject:", units["hpc"].drop("all").to_dict(), "| total", ca1)
print("Units labelled ca3 per subject:", units["ca3"].drop("all").to_dict(), "| total", ca3)
print(f"CA1: {ca1} against 2,297 ({(ca1 - 2297) / 2297:+.1%}); CA3: {ca3} against 654 ({(ca3 - 654) / 654:+.1%}); "
f"sum {ca1 + ca3} against 2,951 ({(ca1 + ca3 - 2951) / 2951:+.1%})")
print("Sessions with hpc units:", int(S.has_hpc_units.sum()) - int(S.has_ca3_units.sum()), "| with ca3 units:", int(S.has_ca3_units.sum()),
"| paper, Figure 6A: 63 CA1 and 19 CA3 sessions; 45 hippocampal sessions in Figure 1I")
Units labelled hpc (taken as CA1) per subject: {'DT2': 1035, 'DT5': 329, 'DT7': 446, 'DT8': 0, 'DT9': 783} | total 2593
Units labelled ca3 per subject: {'DT2': 0, 'DT5': 279, 'DT7': 0, 'DT8': 0, 'DT9': 345} | total 624
CA1: 2593 against 2,297 (+12.9%); CA3: 624 against 654 (-4.6%); sum 3217 against 2,951 (+9.0%)
Sessions with hpc units: 36 | with ca3 units: 11 | paper, Figure 6A: 63 CA1 and 19 CA3 sessions; 45 hippocampal sessions in Figure 1I
Result: partially reproduced. 2,593 units are labelled hpc against 2,297 CA1 units (+12.9%, outside tolerance) and 624 are labelled ca3 against 654 (-4.6%, within). Their sum, 3,217, is 9.0% above 2,951. The labels hpc and ca3 are read as CA1 and CA3; the dandiset does not say that hpc means CA1.
LS neurons passing the activity criterion (ls-active-neurons)¶
Of the LS neurons, 840 fired at least 1.5 action potentials per trial on average.
ls_all = C[C.region == "ls"]
def active_neurons(df, k):
return df[df.n_spikes >= k * df.n_trials].groupby("neuron").ngroups
n_active = LS.neuron.nunique()
print("LS units in a condition with at least 10 trials:", ls_all.neuron.nunique(), "of", int(units.loc["all", "ls"]))
print("Active LS neurons (1.5 spikes per trial in at least one condition):", n_active, "| paper 840")
print("Per subject:", LS.groupby("subject").neuron.nunique().to_dict())
print("Included LS conditions (neuron and condition pairs):", len(LS), "| paper 4,393 conditions")
for k in (1.0, 1.5, 2.0, 3.0):
print(f" threshold {k} spikes per trial: {active_neurons(ls_all, k)} neurons")
LS units in a condition with at least 10 trials: 1630 of 1696
Active LS neurons (1.5 spikes per trial in at least one condition): 793 | paper 840
Per subject: {'DT2': 174, 'DT5': 309, 'DT7': 18, 'DT8': 131, 'DT9': 161}
Included LS conditions (neuron and condition pairs): 3694 | paper 4,393 conditions
threshold 1.0 spikes per trial: 932 neurons
threshold 1.5 spikes per trial: 793 neurons
threshold 2.0 spikes per trial: 707 neurons
threshold 3.0 spikes per trial: 563 neurons
Result: reproduced. 793 LS neurons fire at least 1.5 spikes per trial in a condition with at least 10 trials, against 840 (-5.6%, within tolerance), over 3,694 neuron-condition pairs (the paper has 4,393). The count depends on how conditions are formed, which the dandiset does not record.
Phase coding against shuffled data (fig2-ls-phase-vs-shuffle)¶
The majority of LS neurons (751 of 840, 89%) showed position encoding in their spike theta phase, compared with shuffled data, in at least one condition.
def frac_neurons(df, mask):
return mask.groupby(df.neuron).any()
sig_chance = (LSd.p_phase_vs_chance < 0.01) & (LSd.mse_phase < LSd.mse_chance_phase)
per_neuron = frac_neurons(LSd, sig_chance)
print(f"Active LS neurons decoded: {LSd.neuron.nunique()} (dropped {n_active - LSd.neuron.nunique()} in the file without theta reference)")
print(f"Neurons with phase MSE below chance at p < 0.01 in at least one condition: {int(per_neuron.sum())} "
f"of {len(per_neuron)} = {per_neuron.mean():.3f} | paper 751 of 840 = 0.894")
print("Conditions significant:", f"{sig_chance.mean():.3f}", "of", len(LSd))
print("Per subject:", per_neuron.groupby([S.subject[n[0]] for n in per_neuron.index]).mean().round(3).to_dict())
for p in (0.05, 0.01, 0.001):
m = (LSd.p_phase_vs_chance < p) & (LSd.mse_phase < LSd.mse_chance_phase)
print(f" p < {p}: {frac_neurons(LSd, m).mean():.3f} of neurons")
print("Mean MSE (bins^2) over LS conditions: phase", round(LSd.mse_phase.mean()), "| chance phase", round(LSd.mse_chance_phase.mean()),
"| rate", round(LSd.mse_rate.mean()), "| chance rate", round(LSd.mse_chance_rate.mean()),
"| uniform guessing over 200 bins", round(2 * (200**2 - 1) / 12))
rate_sig = (LSd.p_rate_vs_chance < 0.01) & (LSd.mse_rate < LSd.mse_chance_rate)
print(f"For comparison, rate MSE below chance at p < 0.01: {frac_neurons(LSd, rate_sig).mean():.3f} of neurons")
good_theta = S.session[S.theta_ratio > 1]
m1 = LSd.session.isin(good_theta)
pn = frac_neurons(LSd[m1], sig_chance[m1])
print(f"Variant, sessions whose theta channel has more 6-9 Hz than 1-4 Hz power ({LSd[m1].session.nunique()} sessions): "
f"{pn.mean():.3f} of {len(pn)} neurons; other sessions: {frac_neurons(LSd[~m1], sig_chance[~m1]).mean():.3f}")
Active LS neurons decoded: 783 (dropped 10 in the file without theta reference) Neurons with phase MSE below chance at p < 0.01 in at least one condition: 408 of 783 = 0.521 | paper 751 of 840 = 0.894 Conditions significant: 0.232 of 3660
Per subject: {'DT2': 0.39, 'DT5': 0.56, 'DT7': 0.556, 'DT8': 0.458, 'DT9': 0.627}
p < 0.05: 0.660 of neurons
p < 0.01: 0.521 of neurons
p < 0.001: 0.433 of neurons
Mean MSE (bins^2) over LS conditions: phase 6359 | chance phase 6839 | rate 7404 | chance rate 7996 | uniform guessing over 200 bins 6666
For comparison, rate MSE below chance at p < 0.01: 0.544 of neurons
Variant, sessions whose theta channel has more 6-9 Hz than 1-4 Hz power (37 sessions): 0.529 of 456 neurons; other sessions: 0.511
Result: not reproduced. 52.1% of the decoded active LS neurons (408 of 783) decode position from phase better than chance at p < 0.01 in at least one condition, against 89% in the paper. With p < 0.05 the fraction is 66.0%, still outside tolerance; at p < 0.01 the rate code passes the same test against its own chance in 54.4% of neurons. In the 37 sessions whose theta channel has more 6 to 9 Hz than 1 to 4 Hz power the fraction is 52.9%, so a weak theta reference does not account for the gap. The decoder and the phase maps are rebuilt from the Methods and code, without the paper's linearization, conditions or theta channel.
Phase decoding better than rate decoding (fig2-ls-phase-beats-rate)¶
Spike-phase decoding outperformed rate decoding of the rat's position for 786 of 840 LS neurons, 3,046 of 4,393 conditions, and 62 of 62 sessions.
better = (LSd.p_phase_vs_rate < 0.01) & (LSd.mse_phase < LSd.mse_rate)
nb = frac_neurons(LSd, better)
ses = LSd.groupby("session")[["mse_phase", "mse_rate"]].mean()
print(f"Neurons: {int(nb.sum())} of {len(nb)} = {nb.mean():.3f} | paper 786 of 840 = 0.936")
print(f"Conditions: {int(better.sum())} of {len(better)} = {better.mean():.3f} | paper 3,046 of 4,393 = 0.693")
print(f"Sessions with lower mean phase than rate MSE: {int((ses.mse_phase < ses.mse_rate).sum())} of {len(ses)} = "
f"{(ses.mse_phase < ses.mse_rate).mean():.3f} | paper 62 of 62")
worse = (LSd.p_phase_vs_rate < 0.01) & (LSd.mse_phase > LSd.mse_rate)
print(f"Conditions where rate is better at p < 0.01: {worse.mean():.3f}")
by = pd.DataFrame({"neurons": nb.groupby([S.subject[n[0]] for n in nb.index]).mean(),
"conditions": better.groupby(LSd.subject).mean(),
"sessions": (ses.mse_phase < ses.mse_rate).groupby(S.subject[ses.index].values).mean()})
print("\nPer subject (fractions):")
print(by.round(3).to_string())
for p in (0.05, 0.001):
m = (LSd.p_phase_vs_rate < p) & (LSd.mse_phase < LSd.mse_rate)
print(f" p < {p}: neurons {frac_neurons(LSd, m).mean():.3f}, conditions {m.mean():.3f}")
bt = (LSd.p_phase_vs_rate_trialsplit < 0.01) & (LSd.mse_phase_trialsplit < LSd.mse_rate_trialsplit)
print(f"Variant, whole trials held out: neurons {frac_neurons(LSd, bt).mean():.3f}, conditions {bt.mean():.3f}")
nb1 = frac_neurons(LSd[m1], better[m1])
print(f"Variant, sessions with theta ratio above 1: neurons {nb1.mean():.3f} of {len(nb1)}, conditions {better[m1].mean():.3f} of {int(m1.sum())}")
Neurons: 662 of 783 = 0.845 | paper 786 of 840 = 0.936 Conditions: 1762 of 3660 = 0.481 | paper 3,046 of 4,393 = 0.693 Sessions with lower mean phase than rate MSE: 58 of 58 = 1.000 | paper 62 of 62 Conditions where rate is better at p < 0.01: 0.053
Per subject (fractions):
neurons conditions sessions
DT2 0.945 0.630 1.0
DT5 0.793 0.412 1.0
DT7 0.722 0.290 1.0
DT8 0.824 0.486 1.0
DT9 0.876 0.477 1.0
p < 0.05: neurons 0.895, conditions 0.601
p < 0.001: neurons 0.714, conditions 0.328
Variant, whole trials held out: neurons 0.729, conditions 0.354
Variant, sessions with theta ratio above 1: neurons 0.875 of 456, conditions 0.528 of 2029
Result: not reproduced. Phase beats rate at p < 0.01 in 84.5% of neurons (paper 93.6%) and 48.1% of conditions (paper 69.3%), both outside tolerance, and in 58 of 58 sessions (paper 62 of 62). As fewer than half the conditions pass, the criterion's partial outcome does not apply. The direction holds in every rat and session. In the 37 sessions with a theta ratio above 1, 87.5% of neurons and 52.8% of conditions pass. Samples, not whole trials, are split at random, as the paper's per-cell decoder does (randperm over all trial-by-bin samples in scratch_07_11_17_spatialBinnedMaxCorr.m); with whole trials held out the fractions fall to 72.9% and 35.4%.
Phase MSE lower than rate MSE (fig2e-ls-phase-lower-mse)¶
Across LS neurons the spike-phase code is stronger than the rate code (two-sample t tests; N = 4,393 conditions, p < 1e-100; N = 62 sessions, p < 1e-10).
t_c = stats.ttest_ind(LSd.mse_phase, LSd.mse_rate)
t_s = stats.ttest_ind(ses.mse_phase, ses.mse_rate)
print(f"Conditions (N = {len(LSd)}): phase {LSd.mse_phase.mean():.0f}, rate {LSd.mse_rate.mean():.0f}; t = {t_c.statistic:.1f}, p = {t_c.pvalue:.2e}")
print(f"Sessions (N = {len(ses)}): phase {ses.mse_phase.mean():.0f}, rate {ses.mse_rate.mean():.0f}; t = {t_s.statistic:.1f}, p = {t_s.pvalue:.2e}")
print("Per subject, conditions:")
for subj, g in LSd.groupby("subject"):
t = stats.ttest_ind(g.mse_phase, g.mse_rate)
print(f" {subj}: N = {len(g)}, phase {g.mse_phase.mean():.0f}, rate {g.mse_rate.mean():.0f}, p = {t.pvalue:.1e}")
tg = stats.ttest_ind(LSd[m1].mse_phase, LSd[m1].mse_rate)
print(f"Variant, sessions with theta ratio above 1: phase {LSd[m1].mse_phase.mean():.0f}, rate {LSd[m1].mse_rate.mean():.0f}, p = {tg.pvalue:.1e}")
tt = stats.ttest_ind(LSd.mse_phase_trialsplit, LSd.mse_rate_trialsplit)
print(f"Variant, whole trials held out: phase {LSd.mse_phase_trialsplit.mean():.0f}, rate {LSd.mse_rate_trialsplit.mean():.0f}, p = {tt.pvalue:.1e}")
fig, ax = plt.subplots(1, 2, figsize=(10, 3.5))
bins = np.arange(2000, 14001, 250)
ax[0].hist(LSd.mse_phase, bins, alpha=.6, label="phase"); ax[0].hist(LSd.mse_rate, bins, alpha=.6, label="rate")
ax[0].set_xlabel("MSE (bins$^2$)"); ax[0].set_ylabel("LS conditions"); ax[0].legend()
d = LSd.mse_phase - LSd.mse_rate
ax[1].hist(d, np.arange(-6000, 6001, 200), color="m"); ax[1].set_xlabel("MSE phase - rate (bins$^2$)")
plt.tight_layout(); plt.show()
print("Outside the axes: MSE", int(((LSd.mse_phase < 2000) | (LSd.mse_phase > 14000)).sum()), "phase and",
int(((LSd.mse_rate < 2000) | (LSd.mse_rate > 14000)).sum()), "rate values; difference", int((d.abs() > 6000).sum()),
"| ranges: phase", LSd.mse_phase.min().round(), "to", LSd.mse_phase.max().round(), ", rate", LSd.mse_rate.min().round(), "to", LSd.mse_rate.max().round())
Conditions (N = 3660): phase 6359, rate 7404; t = -33.8, p = 2.49e-232 Sessions (N = 58): phase 6349, rate 7481; t = -12.6, p = 2.85e-23 Per subject, conditions: DT2: N = 787, phase 6407, rate 7835, p = 9.5e-92 DT5: N = 1501, phase 6492, rate 7364, p = 3.1e-68 DT7: N = 69, phase 6381, rate 6946, p = 1.8e-02 DT8: N = 551, phase 6202, rate 7368, p = 2.4e-55 DT9: N = 752, phase 6156, rate 7103, p = 2.1e-39 Variant, sessions with theta ratio above 1: phase 6275, rate 7402, p = 2.9e-147 Variant, whole trials held out: phase 6527, rate 7920, p = 0.0e+00
Outside the axes: MSE 0 phase and 0 rate values; difference 8 | ranges: phase 3438.0 to 10826.0 , rate 2022.0 to 13214.0
Result: reproduced. Over 3,660 LS conditions the phase MSE (6,359) is below the rate MSE (7,404), t = -33.8, p = 2.5e-232, below the paper's 1e-100; over 58 sessions p = 2.9e-23, below 1e-10. It holds in each rat (DT7 only at p = 0.018), in the sessions with a theta ratio above 1 (p = 2.9e-147) and with whole trials held out.
Hippocampal place fields, rate and phase decoding (fig1i-hpc-rate-phase-equivalent)¶
For hippocampal place fields the distributions of rate and phase decoding errors are statistically equivalent (two-sample KS test; 1,820 place fields, p = 0.19; 45 sessions, p = 0.61).
PF = HPd[HPd.n_fields > 0]
hs = PF.groupby("session")[["mse_phase", "mse_rate"]].mean()
k1 = stats.ks_2samp(PF.mse_phase, PF.mse_rate)
k2 = stats.ks_2samp(hs.mse_phase, hs.mse_rate)
print(f"Place fields: N = {len(PF)} (paper 1,820); phase {PF.mse_phase.mean():.0f}, rate {PF.mse_rate.mean():.0f}; "
f"KS D = {k1.statistic:.3f}, p = {k1.pvalue:.3f}; mean difference {(PF.mse_phase - PF.mse_rate).mean():.0f}")
print(f"Sessions: N = {len(hs)} (paper 45); KS D = {k2.statistic:.3f}, p = {k2.pvalue:.3f}; mean difference {(hs.mse_phase - hs.mse_rate).mean():.0f}")
print("Per subject (fields):")
for subj, g in PF.groupby("subject"):
k = stats.ks_2samp(g.mse_phase, g.mse_rate)
print(f" {subj}: N = {len(g)}, phase - rate {(g.mse_phase - g.mse_rate).mean():.0f}, KS p = {k.pvalue:.3f}")
k3 = stats.ks_2samp(HPd.mse_phase, HPd.mse_rate)
print(f"Variant, all included hippocampal conditions (N = {len(HPd)}): phase - rate {(HPd.mse_phase - HPd.mse_rate).mean():.0f}, KS p = {k3.pvalue:.2e}")
k4 = stats.ks_2samp(PF.mse_phase_trialsplit, PF.mse_rate_trialsplit)
print(f"Variant, whole trials held out: phase - rate {(PF.mse_phase_trialsplit - PF.mse_rate_trialsplit).mean():.0f}, KS p = {k4.pvalue:.3f}")
PFb = HPd[HPd.n_fields_box5 > 0]
k5 = stats.ks_2samp(PFb.mse_phase, PFb.mse_rate)
print(f"Variant, fields of the 5-bin box map: N = {len(PFb)}, phase - rate {(PFb.mse_phase - PFb.mse_rate).mean():.0f}, KS p = {k5.pvalue:.3f}")
PFn = HPd[HPd.n_fields_nosd > 0]
k6 = stats.ks_2samp(PFn.mse_phase, PFn.mse_rate)
print(f"Variant, fields without the rule dropping peaks whose SD across trials exceeds their mean: N = {len(PFn)}, "
f"phase - rate {(PFn.mse_phase - PFn.mse_rate).mean():.0f}, KS D = {k6.statistic:.3f}, p = {k6.pvalue:.3f}")
Place fields: N = 531 (paper 1,820); phase 5846, rate 6081; KS D = 0.085, p = 0.044; mean difference -234 Sessions: N = 42 (paper 45); KS D = 0.167, p = 0.610; mean difference -126 Per subject (fields): DT2: N = 230, phase - rate -365, KS p = 0.001 DT5: N = 94, phase - rate -104, KS p = 0.785 DT7: N = 41, phase - rate -118, KS p = 0.779 DT9: N = 166, phase - rate -155, KS p = 0.508 Variant, all included hippocampal conditions (N = 5045): phase - rate -419, KS p = 7.36e-48 Variant, whole trials held out: phase - rate -448, KS p = 0.000 Variant, fields of the 5-bin box map: N = 318, phase - rate -172, KS p = 0.097 Variant, fields without the rule dropping peaks whose SD across trials exceeds their mean: N = 2320, phase - rate -282, KS D = 0.104, p = 0.000
Result: not reproduced. Over 531 hippocampal place fields the KS test finds a difference between phase and rate MSE (D = 0.085, p = 0.044), where the paper finds none (p = 0.19); over 42 sessions it finds none (p = 0.61). The phase MSE is lower by 234 bins squared on average over fields. The result sits near the threshold and depends on the set of fields: with the 318 fields of the 5-bin box map p = 0.097, and per rat only DT2 differs (p = 0.001). Without the code's rule dropping peaks whose SD across trials exceeds their mean, 2,320 fields are found, more than the paper's 1,820, and the distributions differ more clearly (D = 0.104, p below 0.001). Only 531 fields are found here, against 1,820 (see ls-few-place-fields); over all hippocampal conditions the distributions differ (p = 7.4e-48).
Mean phase minus rate MSE (fig2fg-mse-difference)¶
The mean phase minus rate MSE is about -1,000 for LS conditions and -33 for hippocampal place fields, and -1,024 and -25 for LS and hippocampal sessions.
vals = {"LS conditions": (LSd.mse_phase - LSd.mse_rate).mean(), "hippocampal place fields": (PF.mse_phase - PF.mse_rate).mean(),
"LS sessions": (ses.mse_phase - ses.mse_rate).mean(), "hippocampal sessions": (hs.mse_phase - hs.mse_rate).mean()}
paper = {"LS conditions": -1000, "hippocampal place fields": -33, "LS sessions": -1024, "hippocampal sessions": -25}
for k, v in vals.items():
print(f"{k}: {v:.0f} (paper {paper[k]}, tolerance +-{abs(paper[k]) * 0.1:.1f})")
print("\nPer subject, LS conditions and hippocampal place fields:")
print(pd.DataFrame({"LS": (LSd.mse_phase - LSd.mse_rate).groupby(LSd.subject).mean(),
"HPC fields": (PF.mse_phase - PF.mse_rate).groupby(PF.subject).mean()}).round(0).to_string())
print("\nVariant, whole trials held out: LS", round((LSd.mse_phase_trialsplit - LSd.mse_rate_trialsplit).mean()),
"| hippocampal fields", round((PF.mse_phase_trialsplit - PF.mse_rate_trialsplit).mean()))
LS conditions: -1045 (paper -1000, tolerance +-100.0)
hippocampal place fields: -234 (paper -33, tolerance +-3.3)
LS sessions: -1132 (paper -1024, tolerance +-102.4)
hippocampal sessions: -126 (paper -25, tolerance +-2.5)
Per subject, LS conditions and hippocampal place fields:
LS HPC fields
subject
DT2 -1428.0 -365.0
DT5 -872.0 -104.0
DT7 -565.0 -118.0
DT8 -1165.0 NaN
DT9 -947.0 -155.0
Variant, whole trials held out: LS -1393 | hippocampal fields -448
Result: partially reproduced. The LS condition mean, -1,045, is within tolerance of -1,000; the LS session mean, -1,132, is just outside -1,024 +- 102; the hippocampal values, -234 for place fields and -126 for sessions, are far from -33 and -25. LS values are negative and larger in magnitude than the hippocampal ones at both levels.
Place fields in LS and hippocampus (ls-few-place-fields)¶
Only 5.3% (232 of 4,393) of LS rate maps showed place fields by the criteria applied to hippocampal units, where 31.7% (1,820 of 5,735) did.
f_ls, f_hp = (LS.n_fields > 0), (HP.n_fields > 0)
print(f"LS rate maps with a field: {int(f_ls.sum())} of {len(LS)} = {f_ls.mean():.3f} (paper 0.053)")
print(f"Hippocampal rate maps with a field: {int(f_hp.sum())} of {len(HP)} = {f_hp.mean():.3f} (paper 0.317)")
tab = [[f_ls.sum(), (~f_ls).sum()], [f_hp.sum(), (~f_hp).sum()]]
chi = stats.chi2_contingency(tab)
print(f"Chi-squared {chi.statistic:.1f}, p = {chi.pvalue:.2e}")
print(pd.DataFrame({"LS": f_ls.groupby(LS.subject).mean(), "HPC": f_hp.groupby(HP.subject).mean(),
"n LS": f_ls.groupby(LS.subject).size(), "n HPC": f_hp.groupby(HP.subject).size()}).round(3).to_string())
print("\nVariants of the rate map and threshold:")
for col, name in (("n_fields", "Gaussian SD 4 bins, 20% threshold (main)"), ("n_fields_gauss5", "Gaussian SD 5 bins, 20%"),
("n_fields_box5", "5-bin box map, 20%"), ("n_fields_thresh01", "Gaussian SD 4 bins, 1% (the code's default)"),
("n_fields_nosd", "Gaussian SD 4 bins, 20%, without the mean < SD exclusion")):
a, b = LS[col] > 0, HP[col] > 0
c2 = stats.chi2_contingency([[a.sum(), (~a).sum()], [b.sum(), (~b).sum()]])
print(f" {name}: LS {a.mean():.3f}, hippocampus {b.mean():.3f}, chi-squared p = {c2.pvalue:.1e}")
LS rate maps with a field: 198 of 3694 = 0.054 (paper 0.053)
Hippocampal rate maps with a field: 531 of 5045 = 0.105 (paper 0.317)
Chi-squared 73.7, p = 8.92e-18
LS HPC n LS n HPC
subject
DT2 0.044 0.097 821 2373.0
DT5 0.062 0.101 1501 933.0
DT7 0.014 0.080 69 515.0
DT8 0.038 NaN 551 NaN
DT9 0.062 0.136 752 1224.0
Variants of the rate map and threshold:
Gaussian SD 4 bins, 20% threshold (main): LS 0.054, hippocampus 0.105, chi-squared p = 8.9e-18
Gaussian SD 5 bins, 20%: LS 0.049, hippocampus 0.116, chi-squared p = 2.8e-27
5-bin box map, 20%: LS 0.058, hippocampus 0.063, chi-squared p = 4.0e-01
Gaussian SD 4 bins, 1% (the code's default): LS 0.004, hippocampus 0.046, chi-squared p = 7.2e-31
Gaussian SD 4 bins, 20%, without the mean < SD exclusion: LS 0.200, hippocampus 0.460, chi-squared p = 4.7e-139
Result: partially reproduced. 5.4% of LS rate maps have a place field, within tolerance of 5.3%, and fewer than in the hippocampus (chi-squared p = 8.9e-18), but only 10.5% of hippocampal rate maps have a field, against 31.7%. The hippocampal fraction is 8.0% to 13.6% per rat. With a Gaussian of SD 5 bins the fractions are 4.9% and 11.6%; with the 5-bin box map 5.8% and 6.3%, which do not differ (p = 0.40); with the 1% threshold of the code's default, 0.4% and 4.6%. The rule of bz_getPlaceFields1D that drops peaks whose SD across trials exceeds their mean accounts for most of the hippocampal shortfall: without it the fractions are 20.0% (LS) and 46.0% (hippocampus), so LS is then far above 5.3% and the hippocampus above 31.7%. Neither setting matches both of the paper's fractions. The rule is strict here probably because the rebuilt linearization gives about one position sample per bin and trial, which makes per-trial rates noisy.
Properties of hippocampal place fields (hpc-place-field-properties)¶
711 of 1,425 hippocampal neurons had at least one place field (1.27 fields per neuron on average); the median peak in-field rate was 8.5 Hz and the median field width 38 bins.
has = (HP.n_fields > 0).groupby(HP.neuron).any()
peaks = np.concatenate(HP.field_peaks_hz.dropna().values)
widths = np.concatenate(HP.field_widths.dropna().values)
nf = HP.groupby("neuron").n_fields.sum()
print(f"Hippocampal neurons with a field: {int(has.sum())} of {len(has)} = {has.mean():.3f} (paper 711 of 1,425 = 0.499)")
print(f"Fields per active neuron: mean {nf.mean():.2f} (paper 1.27)")
print(f"Median peak rate {np.median(peaks):.1f} Hz (paper 8.5); median width {np.median(widths):.0f} bins (paper 38); N = {len(peaks)} fields")
print("Per subject: fraction with a field", has.groupby([S.subject[n[0]] for n in has.index]).mean().round(3).to_dict())
for col, name in (("n_fields_gauss5", "Gaussian SD 5"), ("n_fields_box5", "5-bin box map"), ("n_fields_thresh01", "1% threshold"), ("n_fields_nosd", "no mean < SD exclusion")):
print(f"Variant, {name}: {(HP[col] > 0).groupby(HP.neuron).any().mean():.3f} of neurons with a field")
Hippocampal neurons with a field: 301 of 1314 = 0.229 (paper 711 of 1,425 = 0.499)
Fields per active neuron: mean 0.47 (paper 1.27)
Median peak rate 8.4 Hz (paper 8.5); median width 39 bins (paper 38); N = 614 fields
Per subject: fraction with a field {'DT2': 0.199, 'DT5': 0.24, 'DT7': 0.202, 'DT9': 0.287}
Variant, Gaussian SD 5: 0.241 of neurons with a field
Variant, 5-bin box map: 0.147 of neurons with a field
Variant, 1% threshold: 0.124 of neurons with a field
Variant, no mean < SD exclusion: 0.623 of neurons with a field
Result: partially reproduced. The median peak rate, 8.4 Hz, and the median field width, 39 bins, are within tolerance of 8.5 Hz and 38 bins; but 22.9% of active hippocampal neurons have a field, against 49.9%, with 0.47 fields per neuron against 1.27. Under the variants of the map and threshold the fraction is 12.4% to 24.1%, and 62.3% without the rule dropping peaks whose SD across trials exceeds their mean (see ls-few-place-fields).
Stability of LS and hippocampal place fields (ls-place-fields-unstable)¶
The few LS rate maps with a place field were less stable across trials than CA1/CA3 place fields (median coefficient of variance 41.5 against 10; two-sample t test, p < 1e-20).
lf_, hf_ = LS[LS.n_fields > 0], HP[HP.n_fields > 0]
for name, col, scale in (("(a) SD over trials at the field peak, Hz", "field_peak_sd", 1), ("(b) SD over mean at the peak, %", "field_peak_cv", 100)):
a, b = lf_[col] * scale, hf_[col] * scale
t = stats.ttest_ind(a, b)
print(f"{name}: LS median {a.median():.1f} (N = {len(a)}), hippocampus median {b.median():.1f} (N = {len(b)}); t = {t.statistic:.2f}, p = {t.pvalue:.2e}")
print("Paper: 41.5 against 10.")
(a) SD over trials at the field peak, Hz: LS median 3.5 (N = 198), hippocampus median 6.4 (N = 531); t = -7.76, p = 2.78e-14 (b) SD over mean at the peak, %: LS median 86.2 (N = 198), hippocampus median 83.6 (N = 531); t = 1.56, p = 1.19e-01 Paper: 41.5 against 10.
Result: not reproduced. Under neither reading are LS fields more variable than hippocampal ones. Under reading (a), the SD at the peak that makeFig2.m computes, the LS median (3.5 Hz) is below the hippocampal one (6.4 Hz, t = -7.76, p = 2.8e-14), the reverse of the claim. Under reading (b), SD over mean, the medians are 86.2% and 83.6% and do not differ (p = 0.12). Both readings are far from 41.5 and 10.
Smoothing scale of peak information (fig1e-phase-info-smaller-scale)¶
Hippocampal place fields reach their peak information at smaller smoothing scales for phase than for rate (medians 15 and 29 bins; two-sample t test, p < 1e-40).
info = [dict(x, session=i, subject=results[i]["summary"]["subject"]) for i, r in enumerate(results) for x in r.get("info", [])]
def smooth5(v):
return lshpc.matlab_smooth(v, 5)
best_p = np.array([np.argmax(smooth5(x["phase"])) + 1 for x in info])
best_r = np.array([np.argmax(smooth5(x["rate"])) + 1 for x in info])
keep_p, keep_r = best_p < 49, best_r < 49
t = stats.ttest_ind(best_p[keep_p], best_r[keep_r])
print(f"Place fields with information curves: {len(info)}; kept (best smoothing below 49): phase {keep_p.sum()}, rate {keep_r.sum()}")
print(f"Median best smoothing: phase {np.median(best_p[keep_p]):.0f} bins, rate {np.median(best_r[keep_r]):.0f} bins (paper 15 and 29); "
f"means {best_p[keep_p].mean():.1f} and {best_r[keep_r].mean():.1f}; t = {t.statistic:.2f}, p = {t.pvalue:.2e}")
print(f"Fields left out at 49 or more: phase {(~keep_p).sum()}, rate {(~keep_r).sum()}")
subj = np.array([x["subject"] for x in info])
for s_ in sorted(set(subj)):
m = subj == s_
print(f" {s_}: N = {m.sum()}, median phase {np.median(best_p[m & keep_p]) if (m & keep_p).any() else np.nan}, "
f"rate {np.median(best_r[m & keep_r]) if (m & keep_r).any() else np.nan}")
fig, ax = plt.subplots(figsize=(5, 3))
ax.hist(best_p[keep_p], np.arange(0, 51, 2), alpha=.6, label="phase"); ax.hist(best_r[keep_r], np.arange(0, 51, 2), alpha=.6, label="rate")
ax.set_xlabel("smoothing with peak information (bins)"); ax.set_ylabel("place fields"); ax.legend(); plt.show()
print("Plotted values: phase", best_p[keep_p].min(), "to", best_p[keep_p].max(), "| rate", best_r[keep_r].min(), "to", best_r[keep_r].max(), "bins; none outside the axes")
Place fields with information curves: 531; kept (best smoothing below 49): phase 525, rate 493 Median best smoothing: phase 10 bins, rate 17 bins (paper 15 and 29); means 12.1 and 19.3; t = -11.18, p = 1.94e-27 Fields left out at 49 or more: phase 6, rate 38 DT2: N = 230, median phase 7.0, rate 16.0 DT5: N = 94, median phase 13.0, rate 17.5 DT7: N = 41, median phase 15.0, rate 19.0 DT9: N = 166, median phase 13.0, rate 17.0
Plotted values: phase 1 to 47 | rate 1 to 48 bins; none outside the axes
Result: partially reproduced. Phase information peaks at smaller smoothing than rate information (medians 10 and 17 bins, t = -11.18, p = 1.9e-27), and in each rat, but both medians are below the paper's 15 and 29, and p does not reach 1e-40 with 531 fields. At the same nominal span the rate and phase smoothings differ slightly (MATLAB smooth drops an even span by one; circ_smoothTS uses 2 ceil(w/2) + 1 bins), as in the paper's code.
Information of phase and rate at fine and coarse scales (fig1g-phase-more-info-fine-scale)¶
At smoothing below 6 cm (about one theta cycle) phase carries more spatial information than rate in hippocampal place fields, and above 10 cm rate carries more.
P = np.array([x["phase"] / x["n_trials"] for x in info])
R = np.array([x["rate"] / x["n_trials"] for x in info])
rows = []
for w in lshpc.INFO_SMOOTHINGS:
t = stats.ttest_ind(P[:, w - 1], R[:, w - 1])
rows.append({"smoothing": w, "phase_minus_rate": (P[:, w - 1] - R[:, w - 1]).mean(), "p": t.pvalue})
D = pd.DataFrame(rows)
print(D[D.smoothing.isin([1, 2, 3, 4, 5, 6, 7, 10, 15, 20, 30, 40, 50])].to_string(index=False))
fine = D[D.smoothing.isin([2, 3])]
coarse = D[D.smoothing >= 7]
print(f"\nFine (2 and 3 bins): phase above rate at p < 1e-5 in {int(((fine.phase_minus_rate > 0) & (fine.p < 1e-5)).sum())} of 2")
print(f"Coarse (7 to 50 bins): rate above phase at p < 0.05 in {int(((coarse.phase_minus_rate < 0) & (coarse.p < 0.05)).sum())} of {len(coarse)} "
f"({((coarse.phase_minus_rate < 0) & (coarse.p < 0.05)).mean():.2f})")
print("Bin size: the median trial path over 200 bins is", round(float(np.nanmedian(S[S.position_unit_used == "cm"].path_length_median)) / 200, 2),
"cm in the files with a scale (paper about 1.5 cm)")
smoothing phase_minus_rate p
1 0.006100 1.806744e-01
2 0.018115 2.134525e-05
3 0.005834 1.553831e-01
4 0.005834 1.553831e-01
5 -0.003479 4.243736e-01
6 -0.003479 4.243736e-01
7 -0.007554 9.081621e-02
10 -0.012487 6.401212e-03
15 -0.019879 1.999584e-05
20 -0.022573 1.087465e-06
30 -0.027117 3.612065e-09
40 -0.031027 1.531080e-11
50 -0.032728 7.630086e-13
Fine (2 and 3 bins): phase above rate at p < 1e-5 in 0 of 2
Coarse (7 to 50 bins): rate above phase at p < 0.05 in 42 of 44 (0.95)
Bin size: the median trial path over 200 bins is 1.12 cm in the files with a scale (paper about 1.5 cm)
Result: partially reproduced. At coarse smoothing (7 to 50 bins) rate carries more information than phase at p < 0.05 in 42 of 44 smoothings (95%, above the criterion's 80%), as the paper reports above 10 cm. At fine smoothing phase carries more, but not at p < 1e-5 (2 bins, +0.018, p = 2.1e-5; 3 bins, +0.006, p = 0.16). Bins here are about 1.1 cm, so 2 and 3 bins are below 6 cm.
Phase coding and LS depth (fig4d-depth-gradient)¶
The strength of phase coding relative to rate coding increases with recording depth within the LS, within sessions and across animals.
sd = LSd.groupby("session").apply(lambda g: (g.mse_phase - g.mse_rate).mean()).rename("diff").to_frame()
sd["subject"] = S.subject[sd.index].values
sd["depth"] = S.ls_depth[sd.index].values
rows = []
for subj, g in sd.groupby("subject"):
if len(g) >= 4 and g.depth.nunique() > 1:
r, p = stats.pearsonr(g.depth, g["diff"])
else:
r, p = np.nan, np.nan
rows.append({"subject": subj, "sessions": len(g), "depth_range": f"{g.depth.min()}-{g.depth.max()}", "r": r, "p": p})
print(pd.DataFrame(rows).round(3).to_string(index=False))
c = sd.copy()
c["depth"] -= c.groupby("subject").depth.transform("mean")
c["diff"] -= c.groupby("subject")["diff"].transform("mean")
r, p = stats.pearsonr(c.depth, c["diff"])
print(f"Pooled, centred within animal: r = {r:.3f}, p = {p:.3f}, N = {len(c)} sessions")
r2, p2 = stats.pearsonr(sd.depth, sd["diff"])
print(f"Variant, pooled without centring: r = {r2:.3f}, p = {p2:.3f}")
sd2 = sd.copy(); sd2["depth"] = S.hpc_depth[sd.index].values
for subj, g in sd2.groupby("subject"):
if len(g) >= 4 and g.depth.nunique() > 1:
print(f" variant with the second depth, {subj}: r = {stats.pearsonr(g.depth, g['diff'])[0]:.3f}")
c2 = sd2.copy()
c2["depth"] -= c2.groupby("subject").depth.transform("mean")
c2["diff"] -= c2.groupby("subject")["diff"].transform("mean")
r3, p3 = stats.pearsonr(c2.depth, c2["diff"])
print(f"Variant, second depth, pooled and centred within animal: r = {r3:.3f}, p = {p3:.3f}")
subject sessions depth_range r p
DT2 9 3324-3540 -0.704 0.034
DT5 16 972-2124 -0.426 0.100
DT7 3 288-1440 NaN NaN
DT8 17 0-612 0.239 0.356
DT9 13 0-900 -0.620 0.024
Pooled, centred within animal: r = -0.365, p = 0.005, N = 58 sessions
Variant, pooled without centring: r = -0.102, p = 0.445
variant with the second depth, DT2: r = -0.729
variant with the second depth, DT5: r = -0.528
variant with the second depth, DT8: r = 0.030
variant with the second depth, DT9: r = -0.604
Variant, second depth, pooled and centred within animal: r = -0.268, p = 0.042
Result: partially reproduced. With depth and value centred within each rat, deeper LS sessions have more negative phase minus rate MSE (r = -0.365, p = 0.005, 58 sessions). Per rat r is negative in DT2 (-0.70), DT5 (-0.43) and DT9 (-0.62) but positive in DT8 (+0.24), so it does not hold in every rat. With the second depth of the name the per-rat signs are the same and the pooled r is -0.268 (p = 0.042); which depth is the LS probe's is an assumption (see the data check). The within-session part cannot be tested, as the dandiset gives no recording site per unit.
Onset phase of LS phase fields and depth (fig4e-onset-depth)¶
The theta phase at the onset of LS phase fields varies with recording depth (DT5 r = 0.38, DT9 r = 0.25, DT2 r = 0.27; circular-linear correlation, p < 0.001).
sig = LSd[sig_chance & LSd.onset_phase.notna()]
best = sig.loc[sig.groupby("neuron").mse_phase.idxmin()]
best = best.assign(depth=S.ls_depth[best.session].values)
print(f"Neurons with significant phase coding and an onset phase: {len(best)}")
for subj in ["DT5", "DT9", "DT2", "DT7", "DT8"]:
g = best[best.subject == subj]
if len(g) > 5 and g.depth.nunique() > 1:
r, p = lshpc.circ_corrcl(g.onset_phase.values, g.depth.values)
print(f" {subj}: N = {len(g)} neurons, {g.session.nunique()} sessions, depths {g.depth.min()}-{g.depth.max()} um, r = {r:.3f}, p = {p:.2e}")
print("Paper: DT5 0.38, DT9 0.25, DT2 0.27, each p < 0.001.")
allc = sig.assign(depth=S.ls_depth[sig.session].values)
print("Variant, every significant condition:")
for subj in ["DT5", "DT9", "DT2"]:
g = allc[allc.subject == subj]
r, p = lshpc.circ_corrcl(g.onset_phase.values, g.depth.values)
print(f" {subj}: N = {len(g)}, r = {r:.3f}, p = {p:.2e}")
print("Variant, sessions whose theta channel has the rat's most common label (one reference region per rat):")
lab = S.theta_label[best.session].values
for subj in ["DT5", "DT9", "DT2"]:
g = best[(best.subject == subj)]
gl = lab[best.subject == subj]
top = pd.Series(gl).value_counts(dropna=False).index[0]
g = g[pd.Series(gl).eq(top).values] if top == top else g
r, p = lshpc.circ_corrcl(g.onset_phase.values, g.depth.values)
print(f" {subj}: label {top}, N = {len(g)} neurons, {g.session.nunique()} sessions, depths {g.depth.min()}-{g.depth.max()} um, "
f"r = {r:.3f}, p = {p:.2e}")
Neurons with significant phase coding and an onset phase: 396 DT5: N = 169 neurons, 16 sessions, depths 972-2124 um, r = 0.082, p = 5.69e-01 DT9: N = 98 neurons, 11 sessions, depths 0-900 um, r = 0.072, p = 7.76e-01 DT2: N = 62 neurons, 9 sessions, depths 3324-3540 um, r = 0.118, p = 6.50e-01 DT7: N = 10 neurons, 2 sessions, depths 288-576 um, r = 0.537, p = 2.36e-01 DT8: N = 57 neurons, 15 sessions, depths 0-612 um, r = 0.112, p = 6.99e-01 Paper: DT5 0.38, DT9 0.25, DT2 0.27, each p < 0.001. Variant, every significant condition: DT5: N = 360, r = 0.058, p = 5.48e-01 DT9: N = 247, r = 0.102, p = 2.76e-01 DT2: N = 89, r = 0.156, p = 3.38e-01 Variant, sessions whose theta channel has the rat's most common label (one reference region per rat): DT5: label hpc, N = 105 neurons, 10 sessions, depths 972-2052 um, r = 0.027, p = 9.61e-01 DT9: label hpc, N = 68 neurons, 7 sessions, depths 0-468 um, r = 0.170, p = 3.74e-01 DT2: label unknown, N = 62 neurons, 9 sessions, depths 3324-3540 um, r = 0.118, p = 6.50e-01
Result: not reproduced. The circular-linear correlation between onset phase and LS depth is r = 0.082 (p = 0.57) in DT5, 0.072 (p = 0.78) in DT9 and 0.118 (p = 0.65) in DT2, against 0.38, 0.25 and 0.27 at p < 0.001. Using every significant condition gives the same, and so does keeping only the sessions whose theta channel has the rat's most common label (hpc in DT5 and DT9; r = 0.027 and 0.170, p = 0.96 and 0.37), which removes the switches between hpc and ca3 references. The test rests on the session depth (the first number in the session name) and on a theta channel chosen per session, which may differ in layer between sessions. That the first depth is the LS depth is an assumption (see fig4d-depth-gradient).
LS-hippocampal theta coherence along the run (fig6c-ca3-coherence-increases)¶
Theta phase coherence between LS and the CA3 pyramidal layer increases from the beginning to the end of the run, while coherence between LS and CA1 stays relatively flat.
rows = []
for i, r in enumerate(results):
f6 = r.get("fig6")
if not f6:
continue
sm = r["summary"]
labels = sm["unit_locations"]
groups = (["CA3"] if "ca3" in labels else []) + (["CA1"] if ("hpc" in labels or "ca1" in labels) else [])
groups = groups or ["none"] # no hippocampal units: left out of the main test, kept for a variant
seg = np.arange(lshpc.N_SEGMENTS)
ok = np.isfinite(f6["coherence"])
ok2 = np.isfinite(f6["cfc"])
for group in groups:
rows.append({"session": i, "subject": sm["subject"], "group": group, "channel": S.theta_label[i],
"coh_mean": np.nanmean(f6["coherence"]), "coh_slope": np.polyfit(seg[ok], f6["coherence"][ok], 1)[0] if ok.sum() > 2 else np.nan,
"cfc_mean": np.nanmean(f6["cfc"]), "cfc_slope": np.polyfit(seg[ok2], f6["cfc"][ok2], 1)[0] if ok2.sum() > 2 else np.nan,
"coh": f6["coherence"], "cfc": f6["cfc"]})
F6all = pd.DataFrame(rows)
F6 = F6all[F6all.group != "none"]
print("Sessions by group and subject (CA3: units labelled ca3; CA1: units labelled hpc):")
print(F6.groupby(["group", "subject"]).size().to_string())
print("Left out, no hippocampal units:", F6all[F6all.group == "none"].groupby("subject").size().to_dict())
print("Label of the hippocampal channel by group:", F6.groupby("group").channel.value_counts().to_dict())
for g in ("CA3", "CA1"):
x = F6[F6.group == g].coh_slope.dropna()
w = stats.wilcoxon(x)
print(f"{g}: N = {len(x)} sessions, median coherence slope {x.median():.4f} per segment, signed-rank p = {w.pvalue:.3f}, positive in {(x > 0).sum()}")
mw = stats.mannwhitneyu(F6[F6.group == "CA3"].coh_slope.dropna(), F6[F6.group == "CA1"].coh_slope.dropna(), alternative="greater")
print(f"CA3 slopes above CA1 slopes: Mann-Whitney p = {mw.pvalue:.3f}")
print("Mean coherence by segment:")
print(pd.DataFrame({g: np.nanmean(np.vstack(F6[F6.group == g].coh.values), 0) for g in ("CA3", "CA1")}).round(3).T.to_string())
print("Per subject, median slope:", F6.groupby(["group", "subject"]).coh_slope.median().round(4).to_dict())
print("Within animal, CA3 slopes above CA1 slopes (Mann-Whitney):")
for subj in ("DT5", "DT9"):
g = F6[F6.subject == subj]
a, b = g[g.group == "CA3"].coh_slope.dropna(), g[g.group == "CA1"].coh_slope.dropna()
print(f" {subj}: CA3 N = {len(a)}, median {a.median():.4f}; CA1 N = {len(b)}, median {b.median():.4f}; p = {stats.mannwhitneyu(a, b, alternative='greater').pvalue:.3f}")
F6v = F6all.assign(group=F6all.group.replace({"none": "CA1"}))
mwv = stats.mannwhitneyu(F6v[F6v.group == "CA3"].coh_slope.dropna(), F6v[F6v.group == "CA1"].coh_slope.dropna(), alternative="greater")
print(f"Variant, sessions without hippocampal units counted as CA1 (as before revision, N = {int((F6v.group == 'CA1').sum())}): CA3 above CA1, p = {mwv.pvalue:.3f}")
Sessions by group and subject (CA3: units labelled ca3; CA1: units labelled hpc):
group subject
CA1 DT2 10
DT5 10
DT7 7
DT9 9
CA3 DT5 6
DT9 5
Left out, no hippocampal units: {'DT7': 2, 'DT8': 17}
Label of the hippocampal channel by group: {('CA1', 'hpc'): 24, ('CA1', 'unknown'): 12, ('CA3', 'ca3'): 11}
CA3: N = 11 sessions, median coherence slope 0.0026 per segment, signed-rank p = 0.831, positive in 7
CA1: N = 36 sessions, median coherence slope -0.0018 per segment, signed-rank p = 0.346, positive in 13
CA3 slopes above CA1 slopes: Mann-Whitney p = 0.348
Mean coherence by segment:
0 1 2 3 4 5 6 7 8 9
CA3 0.748 0.738 0.754 0.747 0.738 0.749 0.744 0.746 0.743 0.759
CA1 0.798 0.795 0.796 0.793 0.777 0.783 0.782 0.781 0.784 0.807
Per subject, median slope: {('CA1', 'DT2'): -0.0012, ('CA1', 'DT5'): -0.0024, ('CA1', 'DT7'): -0.0029, ('CA1', 'DT9'): 0.0027, ('CA3', 'DT5'): 0.0035, ('CA3', 'DT9'): -0.0081}
Within animal, CA3 slopes above CA1 slopes (Mann-Whitney):
DT5: CA3 N = 6, median 0.0035; CA1 N = 10, median -0.0024; p = 0.184
DT9: CA3 N = 5, median -0.0081; CA1 N = 9, median 0.0027; p = 0.905
Variant, sessions without hippocampal units counted as CA1 (as before revision, N = 55): CA3 above CA1, p = 0.235
Result: not reproduced. Theta phase locking between the hippocampal and LS channels does not rise along the run in the 11 CA3 sessions (median slope 0.0026 per segment, signed-rank p = 0.83), and CA3 slopes are not above those of the 36 CA1 sessions (p = 0.35). Within DT5 (p = 0.18) and DT9 (p = 0.91) CA3 slopes are not above CA1 slopes either. The measure is a phase locking value, not the paper's multitaper coherence, and the hippocampal channel is chosen here, not the paper's pyramidal layer site.
Theta-gamma coupling between hippocampus and LS (fig6d-cfc-stronger-ca3)¶
Coupling between hippocampal theta phase and LS gamma amplitude increases along the run for both CA1 and CA3, and is stronger for CA3-LS than for CA1-LS.
mw = stats.mannwhitneyu(F6[F6.group == "CA3"].cfc_mean.dropna(), F6[F6.group == "CA1"].cfc_mean.dropna(), alternative="greater")
print(f"Mean coupling (circular-linear r): CA3 median {F6[F6.group == 'CA3'].cfc_mean.median():.4f}, CA1 median {F6[F6.group == 'CA1'].cfc_mean.median():.4f}; "
f"CA3 above CA1, Mann-Whitney p = {mw.pvalue:.3f}")
for g in ("CA3", "CA1"):
x = F6[F6.group == g].cfc_slope.dropna()
w = stats.wilcoxon(x)
print(f"{g}: N = {len(x)}, median slope {x.median():.5f} per segment, signed-rank p = {w.pvalue:.3f}, positive in {(x > 0).sum()}")
print("Mean coupling by segment:")
print(pd.DataFrame({g: np.nanmean(np.vstack(F6[F6.group == g].cfc.values), 0) for g in ("CA3", "CA1")}).round(4).T.to_string())
print("Per subject, mean coupling:", F6.groupby(["group", "subject"]).cfc_mean.median().round(4).to_dict())
print("Within animal, CA3 coupling above CA1 coupling (Mann-Whitney):")
for subj in ("DT5", "DT9"):
g = F6[F6.subject == subj]
a, b = g[g.group == "CA3"].cfc_mean.dropna(), g[g.group == "CA1"].cfc_mean.dropna()
print(f" {subj}: CA3 N = {len(a)}, median {a.median():.4f}; CA1 N = {len(b)}, median {b.median():.4f}; p = {stats.mannwhitneyu(a, b, alternative='greater').pvalue:.3f}")
mwv = stats.mannwhitneyu(F6v[F6v.group == "CA3"].cfc_mean.dropna(), F6v[F6v.group == "CA1"].cfc_mean.dropna(), alternative="greater")
print(f"Variant, sessions without hippocampal units counted as CA1 (as before revision): CA3 above CA1, p = {mwv.pvalue:.3f}")
Mean coupling (circular-linear r): CA3 median 0.0594, CA1 median 0.0511; CA3 above CA1, Mann-Whitney p = 0.089
CA3: N = 11, median slope 0.00359 per segment, signed-rank p = 0.002, positive in 10
CA1: N = 36, median slope 0.00125 per segment, signed-rank p = 0.001, positive in 24
Mean coupling by segment:
0 1 2 3 4 5 6 7 8 9
CA3 0.0390 0.0415 0.0531 0.0505 0.0653 0.0793 0.0829 0.0817 0.0740 0.0568
CA1 0.0395 0.0479 0.0456 0.0581 0.0509 0.0645 0.0721 0.0617 0.0573 0.0574
Per subject, mean coupling: {('CA1', 'DT2'): 0.0274, ('CA1', 'DT5'): 0.0568, ('CA1', 'DT7'): 0.0903, ('CA1', 'DT9'): 0.0568, ('CA3', 'DT5'): 0.0725, ('CA3', 'DT9'): 0.049}
Within animal, CA3 coupling above CA1 coupling (Mann-Whitney):
DT5: CA3 N = 6, median 0.0725; CA1 N = 10, median 0.0568; p = 0.011
DT9: CA3 N = 5, median 0.0490; CA1 N = 9, median 0.0568; p = 0.880 Variant, sessions without hippocampal units counted as CA1 (as before revision): CA3 above CA1, p = 0.041
Result: not reproduced. Coupling between hippocampal theta phase and LS gamma amplitude rises along the run in both groups (signed-rank p = 0.002 in 11 CA3 sessions and 0.001 in 36 CA1 sessions), but it is not higher in CA3 than in CA1 sessions at p < 0.05 (medians 0.059 and 0.051, Mann-Whitney p = 0.089), which the criterion needs for a full or a partial outcome. Within DT5 CA3 coupling is higher (p = 0.011); within DT9 it is not (p = 0.88). Before revision, with the 19 sessions without hippocampal units counted as CA1, p was 0.041.
Ensemble decoding (figs7-ensemble-ls-phase-best)¶
The firing phases of ensembles of simultaneously recorded LS neurons read out position better than the firing phases or rates of an equal number of hippocampal neurons (p < 0.001 at 15 to 25 neurons).
E = pd.DataFrame([dict(x, session=i, subject=results[i]["summary"]["subject"]) for i, r in enumerate(results) for x in r.get("ensemble", [])])
print("Conditions with at least 15 included LS and 15 hippocampal units:", E.drop_duplicates(["session", "condition"]).shape[0],
"in", E.session.nunique(), "sessions;", E.drop_duplicates(["session", "condition"]).groupby("subject").size().to_dict())
for n, g in E.groupby("size"):
v = {k: np.concatenate(g[k].values) for k in ("ls_phase", "ls_rate", "hpc_phase", "hpc_rate")}
print(f"size {n}: {len(g)} conditions; mean MSE LS phase {v['ls_phase'].mean():.0f}, LS rate {v['ls_rate'].mean():.0f}, "
f"HPC phase {v['hpc_phase'].mean():.0f}, HPC rate {v['hpc_rate'].mean():.0f}")
for other in ("hpc_phase", "hpc_rate"):
lower = stats.ttest_ind(v["ls_phase"], v[other], alternative="less")
higher = stats.ttest_ind(v["ls_phase"], v[other], alternative="greater")
print(f" LS phase minus {other}: {v['ls_phase'].mean() - v[other].mean():+.0f}; one-sided p, LS phase lower = {lower.pvalue:.2g}, "
f"LS phase higher = {higher.pvalue:.2g}")
Conditions with at least 15 included LS and 15 hippocampal units: 65 in 13 sessions; {'DT2': 32, 'DT5': 22, 'DT9': 11}
size 15: 65 conditions; mean MSE LS phase 4738, LS rate 4418, HPC phase 4597, HPC rate 3119
LS phase minus hpc_phase: +141; one-sided p, LS phase lower = 1, LS phase higher = 0.00058
LS phase minus hpc_rate: +1619; one-sided p, LS phase lower = 1, LS phase higher = 3e-186
size 20: 7 conditions; mean MSE LS phase 4260, LS rate 4647, HPC phase 3971, HPC rate 2592
LS phase minus hpc_phase: +290; one-sided p, LS phase lower = 1, LS phase higher = 0.0016
LS phase minus hpc_rate: +1668; one-sided p, LS phase lower = 1, LS phase higher = 1e-38
size 25: 3 conditions; mean MSE LS phase 3459, LS rate 4195, HPC phase 3746, HPC rate 2259
LS phase minus hpc_phase: -288; one-sided p, LS phase lower = 0.0075, LS phase higher = 0.99
LS phase minus hpc_rate: +1200; one-sided p, LS phase lower = 1, LS phase higher = 1.3e-12
Result: not reproduced. In 65 conditions from 13 sessions with at least 15 active LS and hippocampal units, LS phase ensembles of 15 units have a higher MSE (4,738) than hippocampal phase ensembles (4,597; one-sided p = 0.00058 for LS phase higher) and hippocampal rate ensembles (3,119; p = 3e-186). The same holds at 20 units (7 conditions). Only at 25 units (3 conditions) is the LS phase MSE lower than the hippocampal phase MSE (3,459 against 3,746, one-sided p = 0.0075), and it stays above the hippocampal rate MSE (2,259). That p value treats the ensemble draws within each of the 3 conditions as independent, so it overstates the evidence; at 15 and 20 units the direction is the reverse of the claim in any case.
Hippocampal-LS assemblies, on a sample of pairs (fig5-assemblies)¶
Spike trains of hippocampal neurons predicted LS firing in 18.5% (2,087 of 11,264) of hippocampal-LS pairs, with a median optimal timescale of 25 ms.
The peer prediction is run on a random sample of about 1% of the pairs, as all of them do not fit
the time limit (the estimate is printed below). The procedure is in lshpc.py and the claims file.
AS = pd.DataFrame([dict(x, session=i, subject=results[i]["summary"]["subject"]) for i, r in enumerate(results) for x in r.get("assemblies", [])])
n_total = sum(r.get("assembly_pairs_total", 0) for r in results)
pairs_units = sum(len(set(LS[LS.session == s_].unit)) * len(set(HP[HP.session == s_].unit)) for s_ in S.session)
print(f"Pairs of active hippocampal and LS units recorded together: {pairs_units:,}; pairs active in the same condition, "
f"counted per condition: {n_total:,} (paper 11,264 pairs)")
print(f"Sampled with p = {lshpc.ASSEMBLY_SAMPLE_P}: {len(AS)} pairs in {AS.session.nunique()} sessions; per subject {AS.groupby('subject').size().to_dict()}")
print("Fits without a finite strength:", int((~np.isfinite(AS.strength)).sum()))
is_a = AS.strength >= lshpc.ASSEMBLY_THRESHOLD
k, n = int(is_a.sum()), len(AS)
ci = stats.binomtest(k, n).proportion_ci(0.95)
print(f"Assemblies (strength at least 4): {k} of {n} = {k / n:.3f}, 95% interval {ci.low:.3f} to {ci.high:.3f} | paper 0.185")
print(f"Median best window of the assemblies: {AS[is_a].window_ms.median():.1f} ms (paper 25); of all sampled pairs {AS.window_ms.median():.1f} ms")
print("Best windows of the assemblies (ms: pairs):", AS[is_a].window_ms.value_counts().sort_index().to_dict())
print("Per subject, fraction of assemblies:", is_a.groupby(AS.subject).mean().round(3).to_dict())
for th in (1.5, 2, 4, 8):
print(f" threshold {th}: {(AS.strength >= th).mean():.3f} of sampled pairs")
print(f"Real gain above all 10 shuffles (strength above 1): {(AS.strength > 1).mean():.3f} of sampled pairs")
it = AS.strength_tuning >= lshpc.ASSEMBLY_THRESHOLD
ci2 = stats.binomtest(int(it.sum()), n).proportion_ci(0.95)
print(f"Variant, with the LS unit's rate map at the current position as a covariate: {int(it.sum())} of {n} = {it.mean():.3f} "
f"(95% interval {ci2.low:.3f} to {ci2.high:.3f}); median best window {AS[it].window_ms_tuning.median():.1f} ms; "
f"threshold 1.5: {(AS.strength_tuning >= 1.5).mean():.3f}; pairs found by both: {int((it & is_a).sum())}")
sec = AS.seconds.mean()
print(f"Time per pair: {sec:.2f} s on one process; all {n_total:,} pairs would take about {n_total * sec / 3600:.0f} process-hours")
Pairs of active hippocampal and LS units recorded together: 20,979; pairs active in the same condition, counted per condition: 70,898 (paper 11,264 pairs)
Sampled with p = 0.01: 670 pairs in 39 sessions; per subject {'DT2': 408, 'DT5': 157, 'DT7': 5, 'DT9': 100}
Fits without a finite strength: 0
Assemblies (strength at least 4): 35 of 670 = 0.052, 95% interval 0.037 to 0.072 | paper 0.185
Median best window of the assemblies: 20.0 ms (paper 25); of all sampled pairs 15.0 ms
Best windows of the assemblies (ms: pairs): {1: 5, 10: 2, 15: 7, 20: 7, 30: 3, 40: 1, 100: 1, 150: 9}
Per subject, fraction of assemblies: {'DT2': 0.039, 'DT5': 0.102, 'DT7': 0.0, 'DT9': 0.03}
threshold 1.5: 0.194 of sampled pairs
threshold 2: 0.127 of sampled pairs
threshold 4: 0.052 of sampled pairs
threshold 8: 0.018 of sampled pairs
Real gain above all 10 shuffles (strength above 1): 0.354 of sampled pairs
Variant, with the LS unit's rate map at the current position as a covariate: 37 of 670 = 0.055 (95% interval 0.039 to 0.075); median best window 15.0 ms; threshold 1.5: 0.197; pairs found by both: 29
Time per pair: 1.18 s on one process; all 70,898 pairs would take about 23 process-hours
Result: not reproduced. In a random sample of 670 of the 70,898 hippocampal-LS pairs active in the same condition, 35 (5.2%, 95% interval 3.7% to 7.2%) form an assembly of strength at least 4, against 18.5%, and the median best window of the assemblies is 20 ms, against 25 ms. The real gain beats all ten shuffles in 35.4% of the pairs. This cannot be compared with 1 in 11, since the window is chosen to maximise the real fit and the shuffles are run only at that window, so the real fit and the shuffles are not exchangeable without coupling. With a threshold of 1.5 the fraction is 19.4%. Position enters the fit as one linear term, so shared spatial tuning is not removed; adding the LS unit's rate map at the current position as a covariate gives 5.5% (95% interval 3.9% to 7.5%; 29 of the 35 assemblies found again), so the linear coding does not account for the low fraction. The bin size (1 ms), the Gaussian kernel and the window grid are choices made here, as the Methods do not give them and the paper's assembly code is not public. Most sampled pairs come from DT2 (408 of 670), and the pairs are counted per condition, as the Methods imply ("Each neuron pair has a single assembly strength value, determined by all spikes that occur during a single block of trials").
Peak information of LS and hippocampal rate maps (ls-information-lower)¶
LS rate maps have lower peak information rates than hippocampal place field maps (0.4 against 1.7 bits/cm; p < 1e-100).
S["cm_per_bin"] = np.where(S.position_unit_used == "cm", S.path_length_median / lshpc.N_BINS, np.nan)
I = A.assign(cm_per_bin=S.cm_per_bin[A.session].values)
print("Included maps left out for positions in pixels (DT2):", int(I.cm_per_bin.isna().sum()))
I = I[I.cm_per_bin.notna()]
li, hi = I[I.region == "ls"], I[(I.region == "hpc") & (I.n_fields > 0)]
a, b = li.info_peak_bits / li.cm_per_bin, hi.info_peak_bits / hi.cm_per_bin
t = stats.ttest_ind(a, b)
print(f"LS rate maps: N = {len(a)}, mean {a.mean():.3f}, median {a.median():.3f} bits/cm (paper 0.4)")
print(f"Hippocampal place-field maps: N = {len(b)}, mean {b.mean():.3f}, median {b.median():.3f} bits/cm (paper 1.7)")
print(f"LS against hippocampus: t = {t.statistic:.1f}, p = {t.pvalue:.1e}")
print("Bin size, cm: median", round(float(I.drop_duplicates("session").cm_per_bin.median()), 2), "| range",
round(float(I.cm_per_bin.min()), 2), "to", round(float(I.cm_per_bin.max()), 2))
print("Per subject, mean bits/cm:", pd.DataFrame({"LS": a.groupby(li.subject).mean(), "HPC fields": b.groupby(hi.subject).mean()}).round(3).to_dict())
ha = I[I.region == "hpc"]
print(f"Variant, every included hippocampal map: mean {(ha.info_peak_bits / ha.cm_per_bin).mean():.3f} bits/cm")
print(f"In bits per bin: LS mean {li.info_peak_bits.mean():.3f}, hippocampal fields {hi.info_peak_bits.mean():.3f} (at most log2(7) = {np.log2(7):.2f})")
Included maps left out for positions in pixels (DT2): 3194
LS rate maps: N = 2873, mean 0.632, median 0.556 bits/cm (paper 0.4)
Hippocampal place-field maps: N = 301, mean 1.490, median 1.435 bits/cm (paper 1.7)
LS against hippocampus: t = -40.3, p = 6.0e-287
Bin size, cm: median 1.12 | range 0.65 to 1.45
Per subject, mean bits/cm: {'LS': {'DT5': 0.657, 'DT7': 0.516, 'DT8': 0.587, 'DT9': 0.625}, 'HPC fields': {'DT5': 1.603, 'DT7': 1.063, 'DT8': nan, 'DT9': 1.532}}
Variant, every included hippocampal map: mean 0.876 bits/cm
In bits per bin: LS mean 0.713, hippocampal fields 1.724 (at most log2(7) = 2.81)
Result: partially reproduced. LS rate maps carry less peak information than hippocampal place-field maps (means 0.632 and 1.490 bits/cm, t = -40.3, p = 6.0e-287, below the paper's 1e-100), but neither value is within tolerance of 0.4 and 1.7 under either reading (medians 0.556 and 1.435). The measure is that of fig1e (7 levels); the paper's normalization of it is not public, so the scale of these values is uncertain. DT2 is left out for its positions in pixels.
Blocked claims¶
- fig5g-assembly-neurons-stronger-phase and fig6e-assembly-position need the assembly strength of every pair: which LS neurons take part in any assembly, and the strengths of all CA1 and CA3 place cells paired with LS. At about 0.6 s per pair on one process in this run (1.2 s in the previous one; printed under fig5-assemblies) the 70,898 pairs take about 12 process-hours, beyond the time limit, so both are blocked as not runnable. Sampling LS neurons and running all of their pairs (about 89 per neuron) would test them on part of the data; that analysis was not run in this attempt.
- speed-independent: the paper does not define the rate of phase precession or its test of speed modulation, and no code for it is public. The data needed are in the dandiset.
- figs6-reference-frame: no file marks a maze rotation (see the data check).
- fig7-dynamic-weighting-model: a simulation that uses no recorded data.
Summary¶
| Claim | Outcome |
|---|---|
| ls-neuron-count | Reproduced |
| hpc-unit-count | Partially reproduced |
| ls-active-neurons | Reproduced |
| fig2-ls-phase-vs-shuffle | Not reproduced |
| fig2-ls-phase-beats-rate | Not reproduced |
| fig2e-ls-phase-lower-mse | Reproduced |
| fig2fg-mse-difference | Partially reproduced |
| fig1i-hpc-rate-phase-equivalent | Not reproduced |
| ls-few-place-fields | Partially reproduced |
| hpc-place-field-properties | Partially reproduced |
| ls-place-fields-unstable | Not reproduced |
| fig1e-phase-info-smaller-scale | Partially reproduced |
| fig1g-phase-more-info-fine-scale | Partially reproduced |
| fig4d-depth-gradient | Partially reproduced |
| fig4e-onset-depth | Not reproduced |
| fig6c-ca3-coherence-increases | Not reproduced |
| fig6d-cfc-stronger-ca3 | Not reproduced |
| figs7-ensemble-ls-phase-best | Not reproduced |
| fig5-assemblies | Not reproduced (on a sample of pairs) |
| ls-information-lower | Partially reproduced |
| fig5g-assembly-neurons-stronger-phase, fig6e-assembly-position | Blocked: not runnable |
| speed-independent | Blocked: methods underspecified |
| figs6-reference-frame | Blocked: metadata insufficient |
| fig7-dynamic-weighting-model | Blocked: other |
A failure to reproduce here may be a failure of this attempt, not of the paper: see the reasoning and the differences from the paper's method.
How the analysis differs from the paper's.
- The paper's linearized behaviour, trial conditions and choice of CA1 channel are not in the
dandiset. Positions are linearized here by the fraction of each trial's path (200 bins, about 1.1
cm), conditions are formed from trial type, direction and start and end sites, and the theta
channel is the hippocampal channel with high theta and the most 100 to 250 Hz power. In the 11
sessions with
ca3channels it is a CA3 channel, and in DT5 its theta rhythm is weak. - The per-cell decoder follows the paper's scratch code; the function that bins spike phases is not public, and the circular mean per bin is used.
- Place fields follow bz_getPlaceFields1D on the Gaussian rate map of bz_firingMap1D (SD 4 bins), with the Methods' limits converted to bins at 1.5 cm. This finds a third of the paper's share of hippocampal fields; without the code's rule dropping peaks whose SD across trials exceeds their mean it finds more than the paper in both regions (46.0% hippocampal, 20.0% LS).
- The information measure of Figure 1 and of the information rates is built from the Methods' formula with choices fixed in the claims file; the paper's function is not public.
- Coherence in Figure 6 is a phase locking value of the 4 to 12 Hz phases, not multitaper coherence.
- Only the trials are read from the LFP, with 1 s of padding for filtering.
- Assemblies (Figure 5) are computed on a random 1% of the pairs, with a bin size, kernel and window grid chosen here; the claims that need every pair (Figure 5G, 6E) were not tested.
What was found about the dandiset.
- The paper's processed behaviour (linearized position and trial conditions), the CA1 channel per session, and the unit recording sites are not in the dandiset. No session has both CA1 and CA3 channels labelled, where the paper's Figure 6A has sessions with both.
- Eight DT8 files state positions in mm but hold metres; in every file the z column of position is a copy of y; eight of eleven DT2 files repeat or reverse position timestamps; DT2 positions are in pixels with no scale; the head-orientation quaternion is stated in metres.
- DT2 electrodes are all labelled
unknown; DT7 20170317 has 43 units with no region label; DT7 20170324 has no units; 11 units hold spike times out of order. - The depths in the session names are not described; the first is taken as the LS depth.
- DT9 20170501's trials do not match its positions; DT8 20170207 and 20170224 have trials without type or direction.
- The units labelled
hpc(2,593) are 12.9% more than the paper's 2,297 CA1 units. - In the script that writes the paper's place-field files (scratch_07_25_17_calc_firingMaps.m), the file the figures load is named for a 20% threshold, but no threshold is passed, so the function's default of 1% applies.