Entorhinal cortex represents task-relevant remote locations independently of CA1.
The 19 matches · 2 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
- [1] § Methods › Neural data preprocessing ↔ qualityMetrics/eaj_qualityParamValues.m, the whole file · a weak match · score 0.87 · BombCell, spatial decay, noise ratio, spikes missing, halfwidth, violations
- [2] § Methods › LFP analysis ↔ src/ripple_detection/literature_methods.py, lines 2506–2540 · score 0.83 · selected CA1 channel, Hilbert envelope, equiripple filtered, 125 Hz, trace, SWRs
- [3] § Methods › Neural data preprocessing ↔ qualityMetrics/bc_qualityParamValues.m, the whole file · a weak match · score 0.81 · spatial decay, noise ratio, spikes missing, BombCell, violations, global
- [4] § Methods › Single unit analysis ↔ Figures_published_edition.ipynb, lines 2248–2315 · score 0.80 · Spatial aperiodic cells, Border scores, Speed scores, angle, cm, locations
- [5] § Methods › Single unit analysis ↔ Yggdrasil/Spikes/spikes.py, lines 394–434 · score 0.77 · co fire, CA1 spike, MEC spike, 1–10 ms, monosynaptic, shuffled
- [6] § Results › CA1 decouples from MEC during nonlocal coding ↔ Yggdrasil/Spikes/spikes.py, lines 394–434 · score 0.68 · co fired, CA1 spike, MEC spike, 1–10 ms, shuffle, summed
- [7] § Methods › Position tracking ↔ Yggdrasil/Position/arena.py, lines 438–558 · score 0.67 · arena boundaries, track graph, videos, connected, behavior, edges
- [8] § Methods › Electrophysiology ↔ Yggdrasil/LFP/lfp.py, lines 58–140 · score 0.65 · 0.5–500 Hz, spikeGLX, Imec, streamed, preprocessing, cat
- [9] § Methods › LFP analysis ↔ src/ripple_detection/detectors/_lfp.py, lines 57–124 · score 0.60 · Hilbert envelope, ripple filtered, Hz, LFP, trace, score
- [10] § Methods › Position tracking ↔ src/track_linearization/core.py, lines 1036–1097 · score 0.60 · track graph, jumped, network, adjacent, linearized, behavior
- [11] § Methods › Decoding linearized position from population spiking ↔ Yggdrasil/Sequences/sequences.py, lines 232–271 · score 0.59 · acausal posterior, position bin, stationary, fragmented, decoder, probability
- [12] § Methods › Behavioral training ↔ Figures_published_edition.ipynb, lines 192–275 · score 0.57 · linear track, open field, ran, surgery, day, maze
- [13] § Methods › LFP analysis ↔ Yggdrasil/LFP/lfp.py, lines 58–140 · score 0.57 · hardware filter, downsampled, shift, reversed, stream, temporal
- [14] § Methods › Single unit analysis ↔ Yggdrasil/Sequences/sequences.py, lines 629–713 · score 0.56 · consecutive bins, position bin, shuffling, Gaussian, movement, cm
- [15] § Results › Nonlocal content represents task-relevant information ↔ extract_sequences_published_edition.ipynb, lines 646–709 · score 0.53 · naive Bayesian, Bayesian decoder, model, decoding, MEC, immobility
- [16] § Results › MEC represents nonlocal positions during immobility ↔ extract_sequences_published_edition.ipynb, lines 646–709 · score 0.52 · naive Bayesian decoder, immobility bout, classified, model, MEC, decoded
- [17] § Results › Characterizing cells involved in nonlocal coding ↔ Figures_published_edition.ipynb, lines 725–821 · score 0.52 · nonlocal intervals, active cells, Decoded position, ratio, fields, immobility
- [18] § Results › Nonlocal content represents task-relevant information ↔ Figures_published_edition.ipynb, lines 725–821 · score 0.52 · acausal posterior, active cells, decoded position, immobility, Nonlocal, location
- [19] § Results › MEC nonlocal coding occurs largely outside of SWRs ↔ src/ripple_detection/detectors/_hse.py, lines 111–167 · score 0.51 · high synchrony events, active units, Kernel, plus, traces, movement
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 3,709 lines · 195 KB · GPL-3.0 · 4 matches
- # %% [markdown]
- # Calculate and display all figures for paper
- # %%
- # imports
- from os.path import exists, join
- from os import chdir
- import numpy as np
- import pandas as pd
- from datetime import datetime
- from copy import deepcopy
- import matplotlib.pyplot as plt
- import matplotlib as mpl
- import re
- from scipy import signal, stats
- import time
- from sklearn.metrics.pairwise import cosine_similarity
- from sklearn.linear_model import LogisticRegression, LinearRegression
- from sklearn.model_selection import train_test_split
- from sklearn.metrics import confusion_matrix
- from Yggdrasil.Position.position import Position
- import Yggdrasil.Position.position as pos
- from Yggdrasil.Position.arena import Box, BoxWithObject, LinearTrack, DoubleYMaze
- from Yggdrasil.Task.task import LinearTrackTask, DoubleYMazeTask
- from Yggdrasil.Spikes.spikes import Spikes
- import Yggdrasil.Spikes.spikes as sp
- from Yggdrasil.Position.spatial_functions import *
- from Yggdrasil.Sequences.sequences import *
- from Yggdrasil.Sequences.plot import *
- from Yggdrasil.statistics import calc_lmm
- from Yggdrasil.LFP.lfp import LFP
- import Yggdrasil.LFP.lfp as lf
- from Yggdrasil.Electrodes.electrodes import Electrodes
- from Yggdrasil.utilities import get_starts
- from ripple_detection import Kay_ripple_detector, multiunit_HSE_detector, get_multiunit_population_firing_rate
- # reload modules without restarting the kernel
- %load_ext autoreload
- %autoreload 2
- import warnings
- warnings.filterwarnings("ignore", category=DeprecationWarning)
- #chdir(r'C:\Users\emily\OneDrive - Stanford\GitHub\GiocomoLab')
- chdir(r'C:\Users\Niflheim\Documents\GitHub\Giocomo')
- # %%
- # matplotlib style sheet
- from cycler import cycler
- from matplotlib import rcParams
- rcParams['lines.linewidth'] = 1
- rcParams['axes.linewidth'] = 1
- rcParams['font.size'] = 9
- rcParams['font.family'] = 'Arial'
- rcParams['figure.autolayout'] = True
- rcParams['pdf.fonttype'] = 42
- #rcParams['xtick.major.pad'] = 2
- #rcParams['ytick.major.pad'] = 2
- rcParams['xtick.bottom'] = False
- rcParams['ytick.left'] = False
- rcParams['axes.spines.top'] = False
- rcParams['axes.spines.right'] = False
- rcParams['axes.grid'] = False
- rcParams['lines.markersize'] = 2
- # %% [markdown]
- # 👉 Set the figure output path and path to the list of sessions and list of animals
- # %%
- # figure_path = r"C:\Users\emily\Dropbox\Giocomo Lab\WT Sequences\Figures"
- figure_path = r"Z:\WT_Sequences\Analysis"
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- subjects = pd.read_csv('Z:/WT_Sequences/subjects.csv')
- n_animals = len(subjects)
- mpl.rcParams['axes.prop_cycle'] = plt.cycler("color", plt.cm.gray(np.linspace(0, 0.7, n_animals)))
- colors = ['#B21F67','#DF5B25','#FFB000','#648FFF','#785EF0']
- # %%
- # specify animals
- animal_dict = {
- 'StickPin': 0,
- 'TopCoat': 1,
- 'TopHat': 2,
- 'AppleBottom': 3,
- 'BaggySweatpants': 4,
- 'StrappyReeboks': 5,
- 'Curie': 6,
- 'Lovelace': 7,
- 'Noether': 8,
- 'Franklin': 9,
- 'Lamarr': 10,
- 'Payne': 11
- }
- border_dict = {
- 'StickPin': 1780,
- 'TopCoat': 1900,
- 'TopHat': 1800,
- 'AppleBottom': (2100+2280)/2,
- 'BaggySweatpants': (1740+1660)/2,
- 'StrappyReeboks': 2040,
- 'Curie': [np.NaN, np.NaN, 2670, np.NaN],
- 'Lovelace': [np.NaN, 336/2*15, 348/2*15, np.NaN],
- 'Noether': [np.NaN, np.NaN, 364/2*15, np.NaN],
- 'Franklin': [np.NaN, np.NaN, 256/2*15, 268/2*15],
- 'Lamarr': [np.NaN, 276/2*15, 292/2*15, 300/2*15],
- 'Payne': [np.NaN, 254/2*15, 268/2*15, np.NaN]
- }
- # channels with highest theta power (and in MEC near units) across all sessions, 1 per animal
- theta_channel = {
- 'StickPin': 192,
- 'TopCoat': 183,
- 'TopHat': 177,
- 'AppleBottom': 159,
- 'BaggySweatpants': 159,
- 'StrappyReeboks': 155,
- 'Curie': 107,
- 'Lovelace': 59,
- 'Noether': 122,
- 'Franklin': 25,
- 'Lamarr': 161,
- 'Payne': 300
- }
- LOCAL_REMOTE_THRESH = 20
- # %% [markdown]
- # # Figure 1 & S1
- # %% [markdown]
- # ### Task performance over days
- # %%
- # set these values
- task_type = 'Single choice' #Single choice, Reversal or Cued
- n_sessions = 10 #10 days of Single choice or Reversal, 3 days of Cued
- # extract %corr into an array
- # NOTE: assumes list is in order by animal
- # this could be re-written to load values into a df where each col is an animal
- # and session indices are read from file names
- # but I am lazy and this works fine
- curr_animal = sessions['Animal'].iloc[0]
- animal_idx = 0
- session_idx = 0
- percent_correct = np.empty((n_sessions,n_animals))
- percent_correct[:] = np.NaN
- trials_per_min = np.empty((n_sessions,n_animals))
- trials_per_min[:] = np.NaN
- for i, row in sessions.iterrows():
- if row['Task'] == 'X Maze':
- behavior_output_path = join(row['Base_Directory'], 'Preprocessed_Data/Task')
- ecephys_path = join(row['Base_Directory'], 'Preprocessed_Data/Spikes')
- task_file = join(behavior_output_path, row['File']+'_task.txt')
- task = DoubleYMazeTask(name=task_file)
- start = 0
- end = task.trials['Start'].iloc[-1]
- if task.task_type == task_type:
- # advance to next column if next animal
- if not row['Animal'] == curr_animal:
- curr_animal = row['Animal']
- animal_idx += 1
- session_idx = 0
- percent_correct[session_idx, animal_idx] = task.percent_correct
- trials_per_min[session_idx, animal_idx] = task.ntrials/((end-start)/60)
- session_idx += 1
- # %%
- fig, ax = plt.subplots()
- ax.plot(np.arange(1,len(percent_correct)+1), percent_correct)
- ax.plot(np.arange(1,len(percent_correct)+1), np.nanmean(percent_correct,1), 'k', linewidth=3)
- ax.plot([0, 10], [50, 50], 'k--')
- ax.set_xlim([0, 10])
- ax.set_ylim([0, 100])
- ax.set_xlabel('Day')
- ax.set_ylabel('% Correct')
- fig.savefig(join(figure_path,'DY_percent_correct.pdf'), format='pdf')
- fig, ax = plt.subplots()
- ax.plot(np.arange(1, len(trials_per_min)+1), trials_per_min)
- ax.plot(np.arange(1,len(trials_per_min)+1), np.nanmean(trials_per_min,1), 'k', linewidth=3)
- ax.set_xlim([0, 10])
- ax.set_ylim([0, 8])
- ax.set_xlabel('Day')
- ax.set_ylabel('# Trials/Min')
- fig.savefig(join(figure_path, 'DY_trials_per_minute.pdf'), format='pdf')
- # %% [markdown]
- # ### Simultaneous cells recorded per day
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_full.csv')
- surgery_date_list = []
- n_sessions = 50 # placeholder, must be ># days post-op that recordings ran
- # get surgery dates
- for i, row in subjects.iterrows():
- # read surgery date from csv (Excel formats as MM/DD/YYYY)
- surgery_date_list.append(datetime.strptime(row['Surgery_Date'], '%m/%d/%Y'))
- # NOTE: assumes list is in order by animal
- # this could be re-written to load values into a df where each col is an animal
- # and session indices are read from file names
- # but I am lazy and this works fine
- curr_animal = sessions['Animal'].iloc[0]
- animal_idx = 0
- #n_units = np.zeros((n_sessions,n_animals))
- n_units_ca1 = np.full((n_sessions,n_animals), np.NaN)
- n_units_ca3 = np.full((n_sessions,n_animals), np.NaN)
- n_units_mec = np.full((n_sessions,n_animals), np.NaN)
- # count # of good & MUA units on each post-op day
- for i, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- (row['Task'] == 'X Maze' or row['Task'] == 'Linear Track' or \
- row['Epoch_Description']=='Environment A' or row['Epoch_Description']=='Open Field Test'):
- rec_date = datetime.strptime(re.findall('(\d{8})', row['File'])[0], '%Y%m%d')
- # advance to next column if next animal
- if not row['Animal'] == curr_animal:
- curr_animal = row['Animal']
- animal_idx += 1
- session_idx = (rec_date-surgery_date_list[animal_idx]).days
- #n_units[session_idx, animal_idx] += len(spikes.spikes)
- # subset by area
- if ("2023_spring" in row['Base_Directory']) or ("2024_winter" in row['Base_Directory']):
- if (row['Animal']=='Lamarr') and (int(row['Session'][-2:])>=8):
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- spikes_copy = deepcopy(spikes)
- spikes_copy.subset_by_channel(MEC_channels)
- n_units_mec[session_idx, animal_idx] = len(spikes_copy.spikes)
- else:
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- CA1_channels = electrodes.subset_by_location(regions=['CA1','alv','ccb'])
- spikes_copy = deepcopy(spikes)
- spikes_copy.subset_by_channel(CA1_channels)
- n_units_ca1[session_idx, animal_idx] = len(spikes_copy.spikes)
- CA3_channels = electrodes.subset_by_location(regions=['CA3','DG-po'])
- spikes_copy = deepcopy(spikes)
- spikes_copy.subset_by_channel(CA3_channels)
- n_units_ca3[session_idx, animal_idx] = len(spikes_copy.spikes)
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec1_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- spikes_copy = deepcopy(spikes)
- spikes_copy.subset_by_channel(MEC_channels)
- n_units_mec[session_idx, animal_idx] = len(spikes_copy.spikes)
- else:
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- spikes_copy = deepcopy(spikes)
- spikes_copy.subset_by_channel(channels)
- n_units_mec[session_idx, animal_idx] = len(spikes_copy.spikes)
- # %%
- # plot
- days = np.arange(0,50)
- fig, ax = plt.subplots(figsize=(10, 5))
- ind = ~np.isnan(np.asarray(n_units_ca1.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], n_units_ca1[ind[:,a], a])
- ax.plot(days, np.nanmean(n_units_ca1,1), 'k', linewidth=3)
- ax.set(xlabel='Days Post-op', ylabel='# CA1 Units')
- ax.set(xlim=[0, 50], ylim=[0, 250])
- fig.savefig(join(figure_path,'Units_per_day_CA1.pdf'), format='pdf')
- fig, ax = plt.subplots(figsize=(10, 5))
- ind = ~np.isnan(np.asarray(n_units_ca3.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], n_units_ca3[ind[:,a], a])
- ax.plot(days, np.nanmean(n_units_ca3,1), 'k', linewidth=3)
- ax.set(xlabel='Days Post-op', ylabel='# CA3 Units')
- ax.set(xlim=[0, 50], ylim=[0, 200])
- fig.savefig(join(figure_path,'Units_per_day_CA3.pdf'), format='pdf')
- fig, ax = plt.subplots(figsize=(10, 5))
- ind = ~np.isnan(np.asarray(n_units_mec.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], n_units_mec[ind[:,a], a])
- ax.plot(days, np.nanmean(n_units_mec,1), 'k', linewidth=3)
- ax.set(xlabel='Days Post-op', ylabel='# MEC Units')
- ax.set(xlim=[0, 50], ylim=[0, 525])
- fig.savefig(join(figure_path,'Units_per_day_MEC.pdf'), format='pdf')
- # %%
- days = np.arange(0,50)
- n_sites_ca1 = [np.NaN, np.NaN, 130, 202, 240, 152, 118, 208, np.NaN, np.NaN, np.NaN, np.NaN]
- n_sites_ca3 = [np.NaN, np.NaN, 30, 108, 102, 38, 92, 6, np.NaN, np.NaN, np.NaN, np.NaN]
- n_sites_mec = [144, 218, 364, 364, 304, 384, 364, 198, 202, 116, 194, 204] #192,
- fig, ax = plt.subplots(figsize=(10, 5))
- ind = ~np.isnan(np.asarray(n_units_ca1.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], (n_units_ca1[ind[:,a], a]+n_units_ca3[ind[:,a], a]) \
- /(n_sites_ca1[a]+n_sites_ca3[a]))
- ax.plot(days, np.nanmean(n_units_ca1/n_sites_ca1,1), 'k', linewidth=3)
- ax.set(xlabel='Days Post-op', ylabel='# Units/Site in CA1')
- ax.set(xlim=[0, 50], ylim=[0, 1.75], yticks=np.arange(0,1.75,0.25))
- fig.savefig(join(figure_path,'Units_per_site_CA1.pdf'), format='pdf')
- fig, ax = plt.subplots(figsize=(10, 5))
- ind = ~np.isnan(np.asarray(n_units_mec.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], n_units_mec[ind[:,a], a]/n_sites_mec[a])
- ax.plot(days, np.nanmean(n_units_mec/n_sites_mec,1), 'k', linewidth=3)
- ax.set(xlabel='Days Post-op', ylabel='# Units/Site in MEC')
- ax.set(xlim=[0, 50], ylim=[0, 1.75], yticks=np.arange(0,1.75,0.25))
- fig.savefig(join(figure_path,'Units_per_site_MEC.pdf'), format='pdf')
- # %% [markdown]
- # ### Example heatmaps & rasters
- # %%
- bin_cm = 2
- for i, row in sessions.iloc[[109]].iterrows(): #118
- print(row['File'])
- for probe in range(2):
- spikes = Spikes(name=join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec'+str(probe)+'_spikes.txt'))
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- if probe==0:
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- CA1_channels = electrodes.subset_by_location(regions=['CA1','alv','ccb'])
- spikes.subset_by_channel(CA1_channels)
- else:
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- spikes.subset_by_channel(MEC_channels)
- for u in range(len(spikes.spikes)):
- if probe==1:
- if u in [26,234,250]: #CA1 0,28,30; MEC 26,234,250
- fr_map, xbins, ybins, max_fr = calc_fr_map(spikes.spikes[u], position, bin_cm, smooth=True)
- if max_fr>1:
- print(f'Unit {u} Channel {spikes.spike_channel[u]} Max FR {max_fr}')
- f = position.plot_position(spikes=spikes.spikes[u])
- f.savefig(join(figure_path,f'Lovelace_DY01_MEC_{u}_raster.pdf'), format='pdf')
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,f'Lovelace_DY01_MEC_{u}_heatmap.pdf'), format='pdf')
- # %% [markdown]
- # ### Speed distribution over days and locations
- # %%
- n_days = 10
- n_bins = 50
- vel_bins = np.arange(0,n_bins*2+2,2)
- speed_hist = np.zeros(n_bins)
- session_count = 0
- speed_hist_by_days = np.zeros((n_days,n_bins))
- day_counts = np.zeros(n_days)
- speed_hist_by_mouse = np.zeros((n_animals,n_bins))
- animal_counts = np.zeros(n_animals)
- for i, row in sessions.iterrows():
- session_idx = int(row['Session'][-2:])-1
- if not row['Recording_Error'] and not row['Position_Error'] and row['Task'] == 'X Maze' and session_idx<10:
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- this_session_hist = (pd.cut(position.position.Velocity, bins=vel_bins).value_counts().sort_index()/len(position.position.Velocity)).values
- speed_hist += this_session_hist
- session_count += 1
- speed_hist_by_days[session_idx, :] += this_session_hist
- day_counts[session_idx] += 1
- animal_idx = animal_dict[row['Animal']]
- speed_hist_by_mouse[animal_idx,:] += this_session_hist
- animal_counts[animal_idx] += 1
- # %%
- fig, ax = plt.subplots()
- for a in range(n_animals):
- ax.stairs(speed_hist_by_mouse[a]/animal_counts[a]*100, vel_bins)
- ax.stairs(speed_hist/session_count*100, vel_bins, color='k', linewidth=3)
- ax.set_xlim([0,80])
- ax.set_ylim([0,35])
- ax.set_xlabel('Velocity (cm/s)')
- ax.set_ylabel('% Time Spent')
- fig.savefig(join(figure_path,'Velocity_hist.pdf'), format='pdf')
- # %%
- ## Heatmap of speed over 3 examples days
- row = sessions.iloc[155]
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- speed_by_2D_location, x_bins, y_bins = position.calc_feature_map(bin_cm=2)
- f = plot_heatmap(speed_by_2D_location, x_bins, y_bins)
- f.savefig(join(figure_path,f'Payne_DY01_speed_heatmap.pdf'), format='pdf')
- print(np.nanmax(speed_by_2D_location))
- row = sessions.iloc[222]
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- speed_by_2D_location, x_bins, y_bins = position.calc_feature_map(bin_cm=2)
- f = plot_heatmap(speed_by_2D_location, x_bins, y_bins)
- f.savefig(join(figure_path,f'TopCoat_DY05_speed_heatmap.pdf'), format='pdf')
- print(np.nanmax(speed_by_2D_location))
- row = sessions.iloc[9]
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- speed_by_2D_location, x_bins, y_bins = position.calc_feature_map(bin_cm=2)
- f = plot_heatmap(speed_by_2D_location, x_bins, y_bins)
- f.savefig(join(figure_path,f'AppleBottom_DY10_speed_heatmap.pdf'), format='pdf')
- print(np.nanmax(speed_by_2D_location))
- # %%
- ## immobility by location
- velocity_thresh = 2 # cm/s
- n_sessions = 10
- frac_immob = np.full((n_sessions,n_animals), np.NaN)
- frac_immob_at_reward = np.full((n_sessions,n_animals), np.NaN)
- frac_immob_outside_reward = np.full((n_sessions,n_animals), np.NaN)
- frac_immob_at_decision = np.full((n_sessions,n_animals), np.NaN)
- for i, row in sessions.iterrows():
- session_idx = int(row['Session'][-2:])-1
- animal_idx = animal_dict[row['Animal']]
- if not row['Recording_Error'] and not row['Position_Error'] and row['Task'] == 'X Maze' and session_idx<10:
- position = Position(join(row['Base_Directory'], 'Preprocessed_Data/Position', row['File']+'_position.txt'))
- dist_to_reward = position.arena.get_dist_to_nearest_poke(position.position.X, position.position.Y)
- frac_immob[session_idx, animal_idx] = np.mean((position.position.Velocity.values<velocity_thresh))
- frac_immob_at_reward[session_idx, animal_idx] = sum((position.position.Velocity.values<velocity_thresh) & (dist_to_reward<10))/sum(dist_to_reward<10)
- frac_immob_outside_reward[session_idx, animal_idx] = sum((position.position.Velocity.values<velocity_thresh) & (dist_to_reward>=10))/sum(dist_to_reward>=10)
- dist_to_decision = position.arena.get_dist_to_decision(position.position.X, position.position.Y)
- frac_immob_at_decision[session_idx, animal_idx] = sum((position.position.Velocity.values<velocity_thresh) & (dist_to_decision<10))/sum(dist_to_decision<10)
- # %%
- fig, ax = plt.subplots()
- days = np.arange(1, 11)
- ind = ~np.isnan(np.asarray(frac_immob.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], frac_immob[ind[:,a], a]*100, linewidth=0.5)
- ax.plot(days, np.nanmean(frac_immob,1)*100, 'k', linewidth=2)
- ax.set(xlabel='Day', ylabel='% Time Immobile', ylim=[0, 100])
- fig.savefig(join(figure_path,f'Immobility_time_over_days.pdf'), format='pdf')
- fig, ax = plt.subplots()
- days = np.arange(1, 11)
- ind = ~np.isnan(np.asarray(frac_immob_at_reward.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], frac_immob_at_reward[ind[:,a], a]*100, linewidth=0.5)
- ax.plot(days, np.nanmean(frac_immob_at_reward,1)*100, 'k', linewidth=2)
- ax.set(xlabel='Day', ylabel='% Time Immobile at Reward', ylim=[0, 100])
- fig.savefig(join(figure_path,f'Immobility_time_at_reward_over_days.pdf'), format='pdf')
- fig, ax = plt.subplots()
- days = np.arange(1, 11)
- ind = ~np.isnan(np.asarray(frac_immob_outside_reward.astype(float)))
- for a in range(n_animals):
- ax.plot(days[ind[:,a]], frac_immob_outside_reward[ind[:,a], a]*100, linewidth=0.5)
- ax.plot(days, np.nanmean(frac_immob_outside_reward,1)*100, 'k', linewidth=2)
- ax.set(xlabel='Day', ylabel='% Time Immobile >10cm from Reward', ylim=[0, 100])
- fig.savefig(join(figure_path,f'Immobility_time_outside_reward_over_days.pdf'), format='pdf')
- # %% [markdown]
- # ### No overrepresentation: example heatmap of summation of normalized firing rates, summation by location over days
- # %%
- bin_cm = 2
- for i, row in sessions.iloc[[109]].iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and row['Task'] == 'X Maze':
- print(row['File'])
- ca1_spikes = None
- mec_spikes = None
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- if ("2023_spring" in row['Base_Directory']) or ("2024_winter" in row['Base_Directory']):
- if (row['Animal']=='Lamarr') and (int(row['Session'][-2:])>=8):
- mec_spikes = Spikes(name=join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- mec_spikes.subset_by_channel(MEC_channels)
- else:
- ca1_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- CA1_channels = electrodes.subset_by_location(regions=['CA1','alv','ccb'])
- ca1_spikes.subset_by_channel(CA1_channels)
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec1_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- mec_spikes.subset_by_channel(MEC_channels)
- else:
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- mec_spikes.subset_by_channel(channels)
- fr_map, xbins, ybins, max_fr = calc_fr_map(mec_spikes.spikes[0], position, bin_cm, smooth=True)
- summed_mec_map = np.zeros(fr_map.shape)
- summed_ca1_map = np.zeros(fr_map.shape)
- if ca1_spikes is not None:
- for u in range(len(ca1_spikes.spikes)):
- fr_map, xbins, ybins, max_fr = calc_fr_map(ca1_spikes.spikes[u], position, bin_cm, smooth=False)
- summed_ca1_map += fr_map/np.max(fr_map)
- f = plot_heatmap(summed_ca1_map, xbins, ybins)
- f.savefig(join(figure_path,'Lovelace_DY01_CA1_heatmap.pdf'), format='pdf')
- if mec_spikes is not None:
- for u in range(len(mec_spikes.spikes)):
- fr_map, xbins, ybins, max_fr = calc_fr_map(mec_spikes.spikes[u], position, bin_cm, smooth=False)
- summed_mec_map += fr_map/np.max(fr_map)
- f = plot_heatmap(summed_mec_map, xbins, ybins)
- f.savefig(join(figure_path,'Lovelace_DY01_MEC_heatmap.pdf'), format='pdf')
- # %%
- # calculate normalized ratemap in each linearized position bin
- # using linearized data will make it easier to combine across sessions
- # arena borders were re-drawn for each of the 4 cohorts
- # thus each cohort has slightly different linear bins,
- # but these can be easily combined across segments
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- norm_fr_map = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # get linearized bin position of animal at each binned timestamp
- linear_to_bins = np.asarray(seq.classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position'])
- linear_pos = np.asarray(seq.binned_data.position["Linear"])
- animal_bins = np.argmin(np.abs(linear_to_bins[:,np.newaxis]-linear_pos), axis=0)
- animal_bins = animal_bins.astype(dtype=float)
- animal_bins[np.isnan(linear_pos)] = np.NaN
- # same as calc_occupancy, but for 1D position
- bins = np.arange(np.nanmax(animal_bins)+1)
- occupancy, _ = np.histogram(animal_bins, bins=bins)
- # convert to seconds
- occupancy = occupancy.astype(float)
- occupancy *= seq.position.us_per_frame/10**3
- # same as get_spike_map, but for 1D position
- spike_map = np.zeros((len(seq.binned_data.spikes), len(bins)-1))
- norm_fr_map[animal_idx][sess_idx] = np.zeros(len(bins)-1)
- for u in np.arange(len(seq.binned_data.spikes)):
- spikes_per_bin = []
- for n_spk in np.arange(1, np.max(seq.binned_data.spikes[u,:]) + 1):
- spikes_per_bin += animal_bins[seq.binned_data.spikes[u,:] == n_spk].tolist() * int(n_spk)
- spike_map[u,:], _ = np.histogram(spikes_per_bin, bins)
- unit_fr_map = get_fr_map(spike_map[u,:], occupancy)
- norm_fr_map[animal_idx][sess_idx] += unit_fr_map/np.nanmax(unit_fr_map)
- norm_fr_map[animal_idx][sess_idx] /= len(seq.binned_data.spikes)
- print(row['File'])
- with open(join(figure_path,'MEC_norm_fr_map.pkl'), 'wb') as file:
- pickle.dump(norm_fr_map, file)
- # %%
- with open(join(figure_path,'MEC_norm_fr_map.pkl'), 'rb') as file:
- norm_fr_map = pickle.load(file)
- norm_fr_map[6][6] = norm_fr_map[6][6][:123]
- norm_fr_map[6][4] = norm_fr_map[6][6][:123]
- norm_fr_map[6][18] = norm_fr_map[6][6][:123]
- # sum over sessions
- all_sessions_fr = np.full((n_animals,n_sessions,123), np.NaN)
- for a in range(n_animals):
- for s in range(n_sessions):
- if len(norm_fr_map[a][s])>0:
- # mask bins where occupancy was 0
- norm_fr_map[a][s][norm_fr_map[a][s]==0] = np.NaN
- all_sessions_fr[a,s,0:len(norm_fr_map[a][s])] = norm_fr_map[a][s]
- sum_over_sessions_fr = np.nanmean(all_sessions_fr, axis=1)
- # mask out bins with too few sessions
- empty_bins = []
- for a in range(n_animals):
- empty_bins.extend(np.where(np.isnan(sum_over_sessions_fr[a]))[0])
- n_empty, _ = np.histogram(empty_bins, bins=np.arange(0,124))
- keep_locs = np.arange(0,123)[n_empty<=1]
- # plot over spatial bins
- spatial_bins = np.arange(1,len(keep_locs)+1)
- sum_over_sessions_fr = sum_over_sessions_fr[:,keep_locs]
- fig, ax = plt.subplots()
- for a in range(n_animals):
- ax.plot(spatial_bins[~np.isnan(sum_over_sessions_fr[a,:])], \
- sum_over_sessions_fr[a,~np.isnan(sum_over_sessions_fr[a,:])], linewidth=0.5)
- ax.plot(spatial_bins, np.nanmean(sum_over_sessions_fr, axis=0), 'k', linewidth=2)
- ax.set(xlabel='Spatial Bin', ylabel='Summed Normalized FR', ylim=[0, 0.5])
- fig.savefig(join(figure_path,f'MEC_norm_fr_per_spatial_bin.pdf'), format='pdf')
- # %%
- # repeat for CA1
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- norm_fr_map = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_CA1_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # get linearized bin position of animal at each binned timestamp
- linear_to_bins = np.asarray(seq.classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position'])
- linear_pos = np.asarray(seq.binned_data.position["Linear"])
- animal_bins = np.argmin(np.abs(linear_to_bins[:,np.newaxis]-linear_pos), axis=0)
- animal_bins = animal_bins.astype(dtype=float)
- animal_bins[np.isnan(linear_pos)] = np.NaN
- # same as calc_occupancy, but for 1D position
- bins = np.arange(np.nanmax(animal_bins)+1)
- occupancy, _ = np.histogram(animal_bins, bins=bins)
- # convert to seconds
- occupancy = occupancy.astype(float)
- occupancy *= seq.position.us_per_frame/10**3
- # same as get_spike_map, but for 1D position
- spike_map = np.zeros((len(seq.binned_data.spikes), len(bins)-1))
- norm_fr_map[animal_idx][sess_idx] = np.zeros(len(bins)-1)
- for u in np.arange(len(seq.binned_data.spikes)):
- spikes_per_bin = []
- for n_spk in np.arange(1, np.max(seq.binned_data.spikes[u,:]) + 1):
- spikes_per_bin += animal_bins[seq.binned_data.spikes[u,:] == n_spk].tolist() * int(n_spk)
- spike_map[u,:], _ = np.histogram(spikes_per_bin, bins)
- unit_fr_map = get_fr_map(spike_map[u,:], occupancy)
- norm_fr_map[animal_idx][sess_idx] += unit_fr_map/np.nanmax(unit_fr_map)
- norm_fr_map[animal_idx][sess_idx] /= len(seq.binned_data.spikes)
- with open(join(figure_path,'CA1_norm_fr_map.pkl'), 'wb') as file:
- pickle.dump(norm_fr_map, file)
- # %%
- with open(join(figure_path,'CA1_norm_fr_map.pkl'), 'rb') as file:
- norm_fr_map = pickle.load(file)
- norm_fr_map[6][6] = norm_fr_map[6][6][:123]
- norm_fr_map[6][4] = norm_fr_map[6][6][:123]
- norm_fr_map[6][18] = norm_fr_map[6][6][:123]
- # sum over sessions
- all_sessions_fr = np.full((n_animals,n_sessions,123), np.NaN)
- for a in range(n_animals):
- for s in range(n_sessions):
- if len(norm_fr_map[a][s])>0:
- # mask bins where occupancy was 0
- norm_fr_map[a][s][norm_fr_map[a][s]==0] = np.NaN
- all_sessions_fr[a,s,0:len(norm_fr_map[a][s])] = norm_fr_map[a][s]
- sum_over_sessions_fr = np.nanmean(all_sessions_fr, axis=1)
- # mask out bins with too few sessions
- empty_bins = []
- for a in range(n_animals):
- empty_bins.extend(np.where(np.isnan(sum_over_sessions_fr[a]))[0])
- n_empty, _ = np.histogram(empty_bins, bins=np.arange(0,124))
- keep_locs = np.arange(0,123)[n_empty<=6+1]
- # plot over spatial bins
- spatial_bins = np.arange(1,len(keep_locs)+1)
- sum_over_sessions_fr = sum_over_sessions_fr[:,keep_locs]
- fig, ax = plt.subplots()
- for a in range(n_animals):
- ax.plot(spatial_bins[~np.isnan(sum_over_sessions_fr[a,:])], \
- sum_over_sessions_fr[a,~np.isnan(sum_over_sessions_fr[a,:])], linewidth=0.5)
- ax.plot(spatial_bins, np.nanmean(sum_over_sessions_fr, axis=0), 'k', linewidth=2)
- ax.set(xlabel='Spatial Bin', ylabel='Summed Normalized FR', ylim=[0, 0.5])
- fig.savefig(join(figure_path,f'CA1_norm_fr_per_spatial_bin.pdf'), format='pdf')
- # %% [markdown]
- # # Figure 2
- # %% [markdown]
- # ### Example decode
- # %%
- # open example
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- row = sessions.iloc[133] #109 #141
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- print(row['File'])
- # %%
- # plot spikes, position, decoded position, decode distance, and speed for snippet of data
- # subset data
- start_time = 1260
- end_time = 1290
- start_idx = np.argmin(np.abs(seq.binned_data.timestamps-start_time))
- end_idx = np.argmin(np.abs(seq.binned_data.timestamps-end_time))
- subset_timestamps = seq.binned_data.timestamps[start_idx:end_idx]
- f, ax = plt.subplots(4, 1, constrained_layout=True, sharex=False,
- gridspec_kw={"height_ratios": [3,3,1,1]})
- # order cells by peak location along track and plot raster
- cell_order = order_cells_by_field(seq.classifier.classifier)
- neuron_ind, spike_time_ind = np.nonzero(seq.binned_data.spikes[cell_order,start_idx:end_idx])
- ax[0].scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- neuron_ind, color='black', zorder=1,
- marker='|', linewidth=1)
- n_active_cells = len(np.unique(neuron_ind))
- # label spikes during non-local immobility
- time_slice = slice(start_time,end_time)
- dist = seq.calc_dist_from_decode(ts_to_include=seq.binned_data.position.loc[time_slice].index)
- ds_factor = 5
- binned_ds_dist = np.nanmean(np.reshape(dist[:-1],(-1,ds_factor)), axis=1)
- nonlocal_neuron_ind = np.empty(0, dtype=int)
- nonlocal_intervals = pos.filtered_timestamps_to_intervals(np.arange(0,3000), binned_ds_dist>20)
- for i in range(4,len(nonlocal_intervals)):
- neuron_ind, spike_time_ind = np.nonzero(seq.binned_data.spikes[:,
- int(start_idx+nonlocal_intervals[i][0]*5):int(start_idx+nonlocal_intervals[i][1]*5)])
- # ax[1].scatter(1000*(subset_timestamps[nonlocal_intervals[i][0]*5+spike_time_ind]-start_time),
- # neuron_ind, color='darkorange', zorder=1,
- # marker='|', linewidth=1)
- nonlocal_neuron_ind = np.hstack((nonlocal_neuron_ind, neuron_ind))
- nonlocal_neuron_ind = np.unique(nonlocal_neuron_ind)
- neuron_ind, spike_time_ind = np.nonzero(seq.binned_data.spikes[nonlocal_neuron_ind,start_idx:end_idx])
- # map onto cell order
- for n in range(len(neuron_ind)):
- neuron_ind[n] = np.argmin(np.abs(cell_order-nonlocal_neuron_ind[neuron_ind[n]]))
- # ax[0].scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- # neuron_ind, color='darkorange', zorder=1,
- # marker='|', linewidth=1)
- ax[0].set(xlim=[0,30000], ylabel='Neuron')
- # add classifier
- results = seq.classifier.classifier_results.sel(time=time_slice)
- time = (results.time-start_time) * 1000
- max_time = time.max()
- cmap = copy.copy(plt.cm.get_cmap('bone_r'))
- cmap.set_bad(color="lightgrey", alpha=1.0)
- (
- results
- .assign_coords(time=time)
- .acausal_posterior.sum("state")
- .plot(
- x="time",
- y="position",
- robust=True,
- add_colorbar=False,
- zorder=0,
- rasterized=True,
- cmap=cmap,
- ax=ax[1]
- )
- )
- seq_position = seq.binned_data.position['Linear'].loc[time_slice]
- max_position = int(
- np.ceil(seq.binned_data.position['Linear'].max()))
- ax[1].plot(time, seq_position, linestyle="--", linewidth=2,
- color="magenta", clip_on=False)
- rtc.plot_graph_as_1D(seq.position.arena.track_graph,
- edge_spacing=seq.position.arena.edge_spacing,
- ax=ax[1], axis="y", other_axis_start=max_time+50)
- # overlay: distance between decode and real positions
- ax[2].plot(pd.DataFrame(binned_ds_dist).interpolate())
- ax[2].set(xlim=[0,3000], ylabel='Distance from decoded position (cm)')
- # highlight nonlocal times
- for i in range(len(nonlocal_intervals)):
- ax[2].axvspan(nonlocal_intervals[i][0], nonlocal_intervals[i][1], alpha=0.4, zorder=2, color='darkorange')
- # overlay: velocity
- velocity = seq.binned_data.position['Velocity'].iloc[start_idx:end_idx]
- ds_factor = 5
- binned_ds_vel = np.nanmean(np.reshape(velocity.values,(-1,ds_factor)), axis=1)
- ax[3].plot(pd.DataFrame(binned_ds_vel).interpolate())
- ax[3].set(xlim=[0,3000], ylabel='Speed (cm/s)')
- # highlight immobility times
- immobility_intervals = pos.filtered_timestamps_to_intervals(np.arange(0,3000), binned_ds_vel<2)
- for i in range(len(immobility_intervals)):
- ax[3].axvspan(immobility_intervals[i][0], immobility_intervals[i][1], alpha=0.3, zorder=2)
- f.savefig(join(figure_path,'Noether_DY02_decode_snippet.pdf'), format='pdf')
- print(f"{len(nonlocal_neuron_ind)} of {n_active_cells} cells active during nonlocal immobility")
- # %% [markdown]
- # ### Decoder error vs velocity bins & # of cells
- # %%
- distance, velocity, session, animal, n_units = [np.array([]) for _ in range(5)]
- for i, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and row['Task'] == 'X Maze':
- # load any sequences file, doesn't matter which interval (we're just using the
- # classifier & binned data associated with the file, which is the same for
- # immobility, movement, and SWR sequences)
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- # exclude times when the decode is fragmented
- cr = seq.classifier.classifier_results
- non_frag = cr.acausal_posterior.sum('position').argmax('state')!=1
- non_frag_ts = non_frag.coords['time'].values[np.where(non_frag)]
- # calculate distance between animal and decoded position
- dist = seq.calc_dist_from_decode(ts_to_include=non_frag_ts)
- # remove times when position couldn't be tracked
- vel = np.asarray(seq.binned_data.position["Velocity"].loc[non_frag_ts])
- dist = dist[~np.isnan(vel)]
- vel = vel[~np.isnan(vel)]
- # append
- distance = np.append(distance, dist)
- velocity = np.append(velocity, vel)
- session = np.append(session, [int(row['Session'][-2:])-1] * len(dist))
- animal = np.append(animal, [animal_dict[row['Animal']]] * len(dist))
- n_units = np.append(n_units, [seq.binned_data.spikes.shape[0]] * len(dist))
- df = pd.DataFrame({'Velocity': velocity, 'Distance': distance,
- 'Session': session, 'Animal': animal,
- 'N_Units': n_units})
- # %%
- df.to_csv(join(figure_path,'Decoded_distance_binned.csv'), index=False)
- #df = pd.read_csv(join(figure_path,'Decoded_distance_binned.csv'))
- # %%
- heatmap, xedges, yedges = np.histogram2d(df['Velocity'], df['Distance'], bins=[35,26])
- norm_heatmap = heatmap.T/np.sum(heatmap, axis=1)
- extent = [yedges[0], yedges[-2], xedges[0], xedges[-19]]
- cmap = mpl.cm.get_cmap("viridis").copy()
- #cmap.set_under('k')
- fig, ax = plt.subplots()
- hmap = ax.imshow(np.transpose(norm_heatmap[0:-2,0:-19]), extent=extent, origin='lower', cmap=cmap, norm=mpl.colors.LogNorm(0.01, 0.05))
- fig.colorbar(hmap, extend='max')
- ax.set(ylabel='Speed (cm/s)', xlabel='Distance from Animal (cm)')
- fig.savefig(join(figure_path,'Decode_distance_vs_velocity_heatmap.pdf'), format='pdf')
- # %%
- heatmap, xedges, yedges = np.histogram2d(df['Velocity'], df['Distance'], bins=[35,26])
- extent = [xedges[0], xedges[-19], yedges[0], yedges[-1]]
- fig, ax = plt.subplots()
- h, edges = np.histogram(df.Distance[df.Velocity<2], bins=np.arange(0,yedges[-1]+5,5))
- ax.stairs(h/h.sum()*100, edges, color='grey')
- frac_local_immob = np.sum(h[0:4]/h.sum())*100
- h, edges = np.histogram(df.Distance[df.Velocity>=2], bins=np.arange(0,yedges[-1]+5,5))
- ax.stairs(h/h.sum()*100, edges, color='black')
- frac_local_move = np.sum(h[0:4]/h.sum())*100
- ax.set(xlim=[edges[0],edges[-2]+1], ylim=[0,50], xlabel='Distance from decoded position', ylabel='% of Time')
- print(f"{frac_local_move:0.2f}% local during movement and {frac_local_immob:0.2f}% local during immobility")
- fig.savefig(join(figure_path,'Decode_distance_immob_vs_move.pdf'), format='pdf')
- fig, ax = plt.subplots()
- h, edges = np.histogram(df.Distance[df.Velocity<2], bins=np.arange(0,yedges[-1]+5,5))
- ax.stairs(h/h.sum()*100, edges, color='grey')
- h, edges = np.histogram(df.Distance[df.Velocity>=2], bins=np.arange(0,yedges[-1]+5,5))
- ax.stairs(h/h.sum()*100, edges, color='black')
- ax.set(xlim=[20,edges[-2]+1], ylim=[0,4], xlabel='Distance from decoded position', ylabel='% of Time')
- fig.savefig(join(figure_path,'Decode_distance_immob_vs_move_inset.pdf'), format='pdf')
- # %% [markdown]
- # ### Example raster, 1D & 2D decodes of immobility bouts with nonlocal coding
- # %%
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- print(seq.name)
- # %%
- seq.plot_sequence(indices=[1,33,41,305], figure_path=f"{figure_path}/Noether_DY02_MEC")
- # %%
- # repeat raster with color coding by local/nonlocal
- # first, load the interval
- start_time = seq.intervals.intervals.iloc[1].start_time
- end_time = seq.intervals.intervals.iloc[1].end_time
- start_idx = np.argmin(np.abs(seq.binned_data.timestamps-start_time))
- end_idx = np.argmin(np.abs(seq.binned_data.timestamps-end_time))
- subset_timestamps = seq.binned_data.timestamps[start_idx:end_idx]
- # order cells by peak location along track and plot raster
- cell_order, max_bin = order_cells_by_field(seq.classifier.classifier)
- # %%
- # then, determine which spatial bins are local & nonlocal
- cr = seq.classifier.classifier_results.sel(time=slice(start_time, end_time))
- map_position_ind = cr.sum("state").acausal_posterior.argmax("position").values
- plt.plot(map_position_ind)
- print(np.unique(map_position_ind))
- # %%
- # then, identify cells that have significant activity at the nonlocal (contributing_cells) and local (noncontributing_cells) positions
- # set decoded_bin manually for each interval
- # this method finds cells which have firing at the target spatial bin(s) that is >95th percentile of their firing across all spatial bins
- # also tried >mean across all spatial bins
- # also tried nonspatial approach: identify cells whose firing during this particular interval > mean or 95th percentile of shuffle across all immobility
- # this mainly identified high FR cells, as low FR cells are less likely to participate in any given interval
- # 1: local 59, nonlocal 29, 92-96
- # 33: local 0, nonlocal 27
- # 41: local 49-51 (58, 60); nonlocal 29, 78-79
- # 305: local 121, nonlocal 101,102
- field_locs, field_peaks, field_sizes, field_spacing = seq.find_fields()
- pf = seq.classifier.classifier.place_fields_[('', 0)].sel(neuron=cell_order)
- field_locs_ordered = [field_locs[i] for i in cell_order]
- n_cells = pf.shape[1]
- decoded_bin = [59]
- local_cells = []
- for u in range(n_cells):
- # if np.any(pf.sel(neuron=u).values[decoded_bin] - np.nanpercentile(pf.sel(neuron=u).values, 95) > 0): # Old Method
- for f in field_locs_ordered[u]:
- if np.any(np.isin(decoded_bin, f)):
- local_cells.append(u)
- local_cells = np.unique(np.asarray(local_cells))
- decoded_bin = [29,92,93,94,95,96]
- nonlocal_cells = []
- for u in range(n_cells):
- for f in field_locs_ordered[u]:
- if np.any(np.isin(decoded_bin, f)):
- nonlocal_cells.append(u)
- nonlocal_cells = np.unique(np.asarray(nonlocal_cells))
- # %%
- f, ax = plt.subplots(2, 1, constrained_layout=True, sharex=False,
- gridspec_kw={"height_ratios": [5,5]})
- # label spikes during non-local immobility
- time_slice = slice(start_time,end_time)
- dist = seq.calc_dist_from_decode(ts_to_include=seq.binned_data.position.loc[time_slice].index)
- ds_factor = 5
- binned_ds_dist = np.nanmean(np.reshape(dist,(-1,ds_factor)), axis=1)
- nonlocal_neuron_ind = np.empty(0, dtype=int)
- nonlocal_intervals = pos.filtered_timestamps_to_intervals(np.arange(0,len(binned_ds_dist)), binned_ds_dist>20)
- interval_spikes = seq.binned_data.spikes[cell_order,start_idx:end_idx]
- neuron_ind, spike_time_ind = np.nonzero(interval_spikes)
- ax[0].scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- neuron_ind, color='grey', zorder=1,
- marker='|', linewidth=1)
- # plot spikes from cells contributing to decode (over all time) in black
- neuron_ind, spike_time_ind = np.nonzero(interval_spikes[nonlocal_cells, :])
- neuron_ind = nonlocal_cells[neuron_ind]
- ax[0].scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- neuron_ind, color='black', zorder=1,
- marker='|', linewidth=1)
- neuron_ind, spike_time_ind = np.nonzero(interval_spikes[local_cells, :])
- neuron_ind = local_cells[neuron_ind]
- ax[0].scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- neuron_ind, color='black', zorder=1,
- marker='|', linewidth=1)
- # plot spikes contributing to nonlocal decode in cyan during non-local times
- for i in range(len(nonlocal_intervals)):
- interval_spikes = seq.binned_data.spikes[cell_order,int(start_idx+nonlocal_intervals[i][0]*5):int(start_idx+nonlocal_intervals[i][1]*5)]
- neuron_ind_nl, spike_time_ind_nl = np.nonzero(interval_spikes[nonlocal_cells, :])
- neuron_ind_nl = nonlocal_cells[neuron_ind_nl]
- ax[0].scatter(1000*(subset_timestamps[nonlocal_intervals[i][0]*5+spike_time_ind_nl]-start_time),
- neuron_ind_nl, color='cyan', zorder=1,
- marker='|', linewidth=2)
- # plot spikes contributing to local decode in magenta during local times
- # before and after last nonlocal interval
- interval_spikes_l = seq.binned_data.spikes[cell_order,start_idx:int(start_idx+nonlocal_intervals[0][0]*5)]
- neuron_ind_l, spike_time_ind_l = np.nonzero(interval_spikes_l[local_cells, :])
- neuron_ind_l = local_cells[neuron_ind_l]
- ax[0].scatter(1000*(subset_timestamps[spike_time_ind_l]-start_time),
- neuron_ind_l, color='magenta', zorder=1,
- marker='|', linewidth=2)
- interval_spikes_l = seq.binned_data.spikes[cell_order,int(start_idx+nonlocal_intervals[-1][1]*5):end_idx]
- neuron_ind_l, spike_time_ind_l = np.nonzero(interval_spikes_l[local_cells, :])
- neuron_ind_l = local_cells[neuron_ind_l]
- ax[0].scatter(1000*(subset_timestamps[nonlocal_intervals[i][1]*5+spike_time_ind_l]-start_time),
- neuron_ind_l, color='magenta', zorder=1,
- marker='|', linewidth=2)
- # between nonlocal lintervals
- if len(nonlocal_intervals)>1:
- for i in range(1,len(nonlocal_intervals)):
- interval_spikes_l = seq.binned_data.spikes[cell_order,int(start_idx+nonlocal_intervals[i-1][1]*5):int(start_idx+nonlocal_intervals[i][0]*5)]
- neuron_ind_l, spike_time_ind_l = np.nonzero(interval_spikes_l[local_cells, :])
- neuron_ind_l = local_cells[neuron_ind_l]
- ax[0].scatter(1000*(subset_timestamps[nonlocal_intervals[i-1][1]*5+spike_time_ind_l]-start_time),
- neuron_ind_l, color='magenta', zorder=1,
- marker='|', linewidth=2)
- ax[0].set(xlim=[0,int((end_time-start_time)*1000)], ylabel='Neuron')
- f.savefig(join(figure_path,'Noether_DY02_decode_snippet_pf_percentile_1.pdf'), format='pdf')
- # %% [markdown]
- # ### Nonlocal decoding per immobility bout and total % of immobility nonlocal
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session, immob_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility')
- local_data_by_session, local_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_local_immobility')
- nonlocal_data_by_session, nonlocal_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_nonlocal_immobility')
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- SWR_data_by_session, SWR_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'CA1_SWR')
- HSE_data_by_session, HSE_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'CA1_HSE')
- # %%
- plot_seq_metrics_over_events(immob_data_by_seq.Animal, immob_data_by_seq.Percent_non_local_content, figure_path,
- 'perc_immob_content_nl_per_bout', '% of Each Immobility Bout Decoded Non-Locally', [0,1])
- # %%
- print(f"{np.nanmean(immob_data_by_session['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- # %%
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session['non_local'], figure_path,
- 'immob_with_nl', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session['frac_non_local'], figure_path,
- 'perc_immob_content_nl', '% Immobility Time with NonLocal Decode', [0,100])
- # %% [markdown]
- # ### Duration of non-local coding
- # %%
- mean_dur = np.mean(nonlocal_data_by_seq.groupby(['Animal'])['Duration'].mean().values)
- sem_dur = stats.sem(nonlocal_data_by_seq.groupby(['Animal'])['Duration'].mean().values)
- print(f"Periods of non-local coding during immobility last on average "+
- f"{mean_dur:.03f} +/- {sem_dur:.03f} seconds.")
- # %%
- mean_dur = np.mean(SWR_data_by_seq.groupby(['Animal'])['Duration'].mean().values)
- sem_dur = stats.sem(SWR_data_by_seq.groupby(['Animal'])['Duration'].mean().values)
- print(f"SWRs last on average "+
- f"{mean_dur:.03f} +/- {sem_dur:.03f} seconds.")
- # %%
- plot_seq_metrics_over_events(nonlocal_data_by_seq.Animal, nonlocal_data_by_seq.Duration, figure_path,
- 'nl_dur', 'Length of Non-Local Decodes (s)', [0,1])
- # %% [markdown]
- # ### Immobility duration vs decode distance
- # %%
- # Non-local coding is more common during longer bouts of immobility
- plot_seq_metrics_comparison_over_events(immob_data_by_seq, 'Duration', 'Non_local',
- figure_path, 'immob_local_vs_nonlocal_duration', 'Duration (s)', [0,10], [0,4])
- # %% [markdown]
- # # Figure S3
- # %% [markdown]
- # ### Confusion Matrix: actual vs decoded position in MEC during movement
- # %%
- actual_pos = np.array([])
- decoded_pos = np.array([])
- start_time = time.time()
- for _, row in sessions.iterrows():
- sess_idx = int(row['Session'][-2:])-1
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and sess_idx<=10:
- animal_idx = animal_dict[row['Animal']]
- binned_data = Binned_Data(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Binned_Data',
- row['File']+'_MEC_binned_data.txt'))
- classifier = Classifier_Model(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Classifier_Model',
- row['File']+'_MEC_classifier_model.txt'))
- # get movement times
- move_ts = binned_data.position.index[binned_data.position.Velocity>=2].values
- # get current position
- actual_pos = np.append(actual_pos, binned_data.position.Linear[move_ts])
- # get decoded linearized bins and map to linearized position
- cr = classifier.classifier_results.sel(time=move_ts)
- decoded_bins = cr.sum("state").acausal_posterior.argmax("position").values
- bins_to_linear = classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position']
- decoded_pos = np.append(decoded_pos, bins_to_linear[decoded_bins])
- print(f"{row['File']} {time.time()-start_time}")
- df = pd.DataFrame({'actual_position': actual_pos,
- 'MEC_decode_position': decoded_pos})
- # %%
- df.to_csv(join(figure_path,'position_vs_MEC_decode_during_movement.csv'), index=False)
- # %%
- # heatmap of actual vs decoded positions
- heatmap, xedges, yedges = np.histogram2d(df.loc[:,'actual_position'], df.loc[:,'MEC_decode_position'], bins=[26,26])
- extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
- cmap = mpl.cm.get_cmap("viridis").copy()
- fig, ax = plt.subplots()
- norm_heatmap = heatmap.T/np.sum(heatmap, axis=1)
- hmap = ax.imshow(norm_heatmap, extent=extent, origin='lower', cmap=cmap, vmax=0.5)
- fig.colorbar(hmap)
- ax.set(xlabel='Actual Linearized Position (cm)', ylabel='MEC Decoded Linearized Position (cm)')
- fig.savefig(join(figure_path,'position_vs_MEC_decode_during_movement_positionnorm.pdf'), format='pdf')
- # %% [markdown]
- # ### non-local coding is common across days
- # %%
- days = np.arange(1,11)
- fig, ax = plt.subplots()
- for _, animal_metric in enumerate(immob_data_by_session['non_local']):
- animal_metric = animal_metric[:10]
- ax.plot(days[~np.isnan(animal_metric)], animal_metric[~np.isnan(animal_metric)])
- ax.plot(np.arange(1,11), np.nanmean(immob_data_by_session['non_local'].T[:10],1), 'k', linewidth=2)
- ax.set(xlabel='Day', ylabel='% Immobility Bouts with NonLocal Decode', ylim=[0, 100])
- fig.savefig(join(figure_path,f'immob_with_nl_over_days.pdf'), format='pdf')
- fig, ax = plt.subplots()
- for _, animal_metric in enumerate(immob_data_by_session['frac_non_local']):
- animal_metric = animal_metric[:10]
- ax.plot(days[~np.isnan(animal_metric)], animal_metric[~np.isnan(animal_metric)])
- ax.plot(np.arange(1,11), np.nanmean(immob_data_by_session['frac_non_local'].T[:10],1), 'k', linewidth=2)
- ax.set(xlabel='Day', ylabel='% Immobility Time with NonLocal Decode', ylim=[0, 100])
- fig.savefig(join(figure_path,f'perc_immob_content_nl.pdf'), format='pdf')
- # %% [markdown]
- # ### pie chart: % of local & non-local immobility classified as stationary, continuous, fragmented
- # %%
- f, ax = plt.subplots(1,3)
- ax[0].pie([np.sum(immob_data_by_seq['Percent_stationary']*immob_data_by_seq['Duration']), \
- np.sum(immob_data_by_seq['Percent_continuous']*immob_data_by_seq['Duration']), \
- np.sum(immob_data_by_seq['Percent_fragmented']*immob_data_by_seq['Duration'])], \
- labels=['stat','cont','frag'])
- ax[1].pie([np.sum(local_data_by_seq['Percent_stationary']*local_data_by_seq['Duration']), \
- np.sum(local_data_by_seq['Percent_continuous']*local_data_by_seq['Duration']), \
- np.sum(local_data_by_seq['Percent_fragmented']*local_data_by_seq['Duration'])], \
- labels=['stat','cont','frag'])
- ax[2].pie([np.sum(nonlocal_data_by_seq['Percent_stationary']*nonlocal_data_by_seq['Duration']), \
- np.sum(nonlocal_data_by_seq['Percent_continuous']*nonlocal_data_by_seq['Duration']), \
- np.sum(nonlocal_data_by_seq['Percent_fragmented']*nonlocal_data_by_seq['Duration'])], \
- labels=['stat','cont','frag'])
- print(f"{np.sum(immob_data_by_seq['Percent_fragmented']*immob_data_by_seq['Duration'])/np.sum(immob_data_by_seq['Duration']):.02f}% of all immobility, " +
- f"{np.sum(local_data_by_seq['Percent_fragmented']*local_data_by_seq['Duration'])/np.sum(local_data_by_seq['Duration']):.02f}% of local immobility, " +
- f"and {np.sum(nonlocal_data_by_seq['Percent_fragmented']*nonlocal_data_by_seq['Duration'])/np.sum(nonlocal_data_by_seq['Duration']):.02f}% of nonlocal immobility " +
- "is fragmented.")
- f.savefig(join(figure_path,'classification.pdf'), format='pdf')
- # %% [markdown]
- # ### local vs nonlocal quality check: variance of posteriors
- # %%
- # match durations
- nonlocal_equivalent = []
- for a in local_data_by_seq.Animal.unique():
- start_idx = np.min(np.where(nonlocal_data_by_seq.Animal==a))
- for __, dur in local_data_by_seq.loc[local_data_by_seq.Animal==a].Duration.items():
- idx = np.abs(nonlocal_data_by_seq.loc[nonlocal_data_by_seq.Animal==a].Duration - dur).argmin()
- nonlocal_equivalent.append(start_idx + idx)
- is_non_local = []
- is_non_local.extend([False] * len(local_data_by_seq))
- is_non_local.extend([True] * len(nonlocal_data_by_seq.iloc[nonlocal_equivalent]))
- local_nonlocal_equivalent_data_by_seq = pd.concat([local_data_by_seq, nonlocal_data_by_seq.iloc[nonlocal_equivalent]], ignore_index=True)
- local_nonlocal_equivalent_data_by_seq.Non_local = is_non_local
- local_nonlocal_equivalent_data_by_seq['Posterior_density_spread_percent_corrected'] = \
- local_nonlocal_equivalent_data_by_seq.Posterior_density_spread_percent/local_nonlocal_equivalent_data_by_seq.Spatial_coverage_percent
- # %%
- plot_seq_metrics_comparison_over_events(local_nonlocal_equivalent_data_by_seq, 'Posterior_density_spread_percent_corrected', 'Non_local', figure_path,
- 'local_vs_nonlocal_posterior_density_corrected', '% Track Covered by Posterior Density >0.95% Per % Track Covered', [0,100])
- # %%
- # these data structures are generated in Figure 3
- with open(join(figure_path,'nonlocal_fields_data_by_seq2.pkl'), 'rb') as file:
- nonlocal_fields_data_by_seq2 = pickle.load(file)
- with open(join(figure_path,'local_fields_data_by_seq2.pkl'), 'rb') as file:
- local_fields_data_by_seq2 = pickle.load(file)
- # %%
- # add posterior variance and spatial coverage
- posterior_variance = []
- spatial_coverage = []
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_local_immobility_sequences.txt'))
- posterior_variance.extend(seq.stats.Posterior_density_spread_percent)
- spatial_coverage.extend(seq.stats.Spatial_coverage_percent)
- local_fields_data_by_seq2['Posterior_density_spread_percent'] = posterior_variance
- local_fields_data_by_seq2['Spatial_coverage_percent'] = spatial_coverage
- # repeat for nonlocal
- posterior_variance = []
- spatial_coverage = []
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'))
- posterior_variance.extend(seq.stats.Posterior_density_spread_percent)
- spatial_coverage.extend(seq.stats.Spatial_coverage_percent)
- nonlocal_fields_data_by_seq2['Posterior_density_spread_percent'] = posterior_variance
- nonlocal_fields_data_by_seq2['Spatial_coverage_percent'] = spatial_coverage
- # %%
- # match durations
- nonlocal_equivalent = []
- for a in local_fields_data_by_seq2.Animal.unique():
- start_idx = np.min(np.where(nonlocal_fields_data_by_seq2.Animal==a))
- for __, dur in local_fields_data_by_seq2.loc[local_fields_data_by_seq2.Animal==a].Duration.items():
- idx = np.abs(nonlocal_fields_data_by_seq2.loc[nonlocal_fields_data_by_seq2.Animal==a].Duration - dur).argmin()
- nonlocal_equivalent.append(start_idx + idx)
- is_non_local = []
- is_non_local.extend([False] * len(local_fields_data_by_seq2))
- is_non_local.extend([True] * len(nonlocal_fields_data_by_seq2.iloc[nonlocal_equivalent]))
- local_nonlocal_fields_equivalent_data_by_seq = pd.concat([local_fields_data_by_seq2, nonlocal_fields_data_by_seq2.iloc[nonlocal_equivalent]], ignore_index=True)
- local_nonlocal_fields_equivalent_data_by_seq['Non_local'] = is_non_local
- local_nonlocal_fields_equivalent_data_by_seq['Posterior_density_spread_percent_corrected'] = \
- local_nonlocal_fields_equivalent_data_by_seq.Posterior_density_spread_percent/local_nonlocal_fields_equivalent_data_by_seq.Spatial_coverage_percent
- # %%
- # calculate mean over 2D bins
- local_fields_df = local_nonlocal_fields_equivalent_data_by_seq[~local_nonlocal_fields_equivalent_data_by_seq.Non_local]
- local_cells = pd.cut(local_fields_df['Local_percent_cells']*100, bins=np.arange(0,110,10))
- nonlocal_cells = pd.cut(local_fields_df['Nonlocal_percent_cells']*100, bins=np.arange(0,110,10))
- local_fields_ppv = local_fields_df.groupby([local_cells, nonlocal_cells])['Posterior_density_spread_percent_corrected'].mean().unstack().T
- # repeat for nonlocal coding events
- nonlocal_fields_df = local_nonlocal_fields_equivalent_data_by_seq[local_nonlocal_fields_equivalent_data_by_seq.Non_local]
- local_cells = pd.cut(nonlocal_fields_df['Local_percent_cells']*100, bins=np.arange(0,110,10))
- nonlocal_cells = pd.cut(nonlocal_fields_df['Nonlocal_percent_cells']*100, bins=np.arange(0,110,10))
- nonlocal_fields_ppv = nonlocal_fields_df.groupby([local_cells, nonlocal_cells])['Posterior_density_spread_percent_corrected'].mean().unstack().T
- # %%
- # heatmap over coding events, local vs nonlocal: x=% local cells, y=% nonlocal cells, z/color= mean corrected posterior probability variance
- cmap = mpl.cm.get_cmap("viridis").copy()
- cmap.set_bad(color='lightgrey')
- fig, ax = plt.subplots()
- sns.heatmap(local_fields_ppv, fmt=".2f", cmap=cmap, vmax=100, cbar_kws={'label': '% Track Covered by Posterior Density'})
- plt.gca().invert_yaxis()
- ax.set(xlabel='% Local Units', ylabel='% Non-Local Units', xticklabels=np.arange(0,100,10), yticklabels=np.arange(0,100,10))
- fig.savefig(join(figure_path,'ppv_heatmap_local.pdf'), format='pdf')
- fig, ax = plt.subplots()
- sns.heatmap(nonlocal_fields_ppv, fmt=".2f", cmap=cmap, vmax=100, cbar_kws={'label': '% Track Covered by Posterior Density'})
- plt.gca().invert_yaxis()
- ax.set(xlabel='% Local Units', ylabel='% Non-Local Units', xticklabels=np.arange(0,100,10), yticklabels=np.arange(0,100,10))
- fig.savefig(join(figure_path,'ppv_heatmap_nonlocal.pdf'), format='pdf')
- cmap = mpl.cm.get_cmap("seismic").copy()
- cmap.set_bad(color='lightgrey')
- fig, ax = plt.subplots()
- sns.heatmap((local_fields_ppv-nonlocal_fields_ppv), fmt=".2f", vmin=-50, vmax=50, cmap=cmap, cbar_kws={'label': '% Track Covered by Posterior Density: Local Events Minus Non-Local Events'})
- plt.gca().invert_yaxis()
- ax.set(xlabel='% Local Units', ylabel='% Non-Local Units', xticklabels=np.arange(0,100,10), yticklabels=np.arange(0,100,10))
- fig.savefig(join(figure_path,'ppv_heatmap_delta.pdf'), format='pdf')
- # %% [markdown]
- # ### local vs nonlocal quality check: changes in # spikes, # active cells, or spatial info
- # %%
- is_non_local = []
- is_non_local.extend([False] * len(local_data_by_seq))
- is_non_local.extend([True] * len(nonlocal_data_by_seq))
- local_nonlocal_data_by_seq = pd.concat([local_data_by_seq, nonlocal_data_by_seq], ignore_index=True)
- local_nonlocal_data_by_seq.Non_local = is_non_local
- # %%
- # match durations
- nonlocal_equivalent = []
- for a in local_data_by_seq.Animal.unique():
- start_idx = np.min(np.where(nonlocal_data_by_seq.Animal==a))
- for __, dur in local_data_by_seq.loc[local_data_by_seq.Animal==a].Duration.items():
- idx = np.abs(nonlocal_data_by_seq.loc[nonlocal_data_by_seq.Animal==a].Duration - dur).argmin()
- nonlocal_equivalent.append(start_idx + idx)
- is_non_local = []
- is_non_local.extend([False] * len(local_data_by_seq))
- is_non_local.extend([True] * len(nonlocal_data_by_seq.iloc[nonlocal_equivalent]))
- local_nonlocal_equivalent_data_by_seq = pd.concat([local_data_by_seq, nonlocal_data_by_seq.iloc[nonlocal_equivalent]], ignore_index=True)
- local_nonlocal_equivalent_data_by_seq.Non_local = is_non_local
- # %%
- plot_seq_metrics_comparison_over_events(local_nonlocal_equivalent_data_by_seq, 'Percent_units', 'Non_local', figure_path,
- 'local_vs_nonlocal_active_units', '% Active Units', [0,100])
- plot_seq_metrics_comparison_over_events(local_nonlocal_equivalent_data_by_seq, 'FR', 'Non_local', figure_path,
- 'local_vs_nonlocal_FR_matched', 'FR', [0,50])
- plot_seq_metrics_comparison_over_events(local_nonlocal_equivalent_data_by_seq, 'Spatial_information', 'Non_local', figure_path,
- 'local_vs_nonlocal_spatial_info_matched', 'Spatial Information (bits/sec)', [0,1.5])
- # %% [markdown]
- # ### Non-local content with different decoders
- # %%
- # decoder trained on movement + immobility
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session_alt_decoder, _ = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility', modifier='_cv')
- print(f"{np.nanmean(immob_data_by_session_alt_decoder['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session_alt_decoder['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['non_local'], figure_path,
- 'immob_with_nl_alt_decoder_cv', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['frac_non_local'], figure_path,
- 'perc_immob_content_nl_alt_decoder_cv', '% Immobility Time with NonLocal Decode', [0,100])
- # %%
- # plot position and decoded position for snippet of data
- # open example
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences_cv.txt'),
- load_objects=True)
- seq.plot_sequence(indices=[1,33,41], figure_path=f"{figure_path}/Noether_DY02_MEC_alt_decoder_CV")
- # %%
- # decoder trained on movement variance = 6 instead of 1
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session_alt_decoder, _ = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility', modifier='_var6')
- print(f"{np.nanmean(immob_data_by_session_alt_decoder['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session_alt_decoder['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['non_local'], figure_path,
- 'immob_with_nl_alt_decoder_var6', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['frac_non_local'], figure_path,
- 'perc_immob_content_nl_alt_decoder_var6', '% Immobility Time with NonLocal Decode', [0,100])
- # %%
- # plot position and decoded position for snippet of data
- # open example
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences_var6.txt'),
- load_objects=True)
- seq.plot_sequence(indices=[1,33,41], figure_path=f"{figure_path}/Noether_DY02_MEC_alt_decoder_var6")
- # %%
- # Bayesian decoder
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session_alt_decoder, _ = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility', modifier='_bayes')
- print(f"{np.nanmean(immob_data_by_session_alt_decoder['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session_alt_decoder['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['non_local'], figure_path,
- 'immob_with_nl_alt_decoder_bayes', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['frac_non_local'], figure_path,
- 'perc_immob_content_nl_alt_decoder_bayes', '% Immobility Time with NonLocal Decode', [0,100])
- # %%
- # plot position and decoded position for snippet of data
- # open example
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences_bayes.txt'),
- load_objects=True)
- # subset data
- start_time = 1260
- end_time = 1290
- start_idx = np.argmin(np.abs(seq.binned_data.timestamps-start_time))
- end_idx = np.argmin(np.abs(seq.binned_data.timestamps-end_time))
- subset_timestamps = seq.binned_data.timestamps[start_idx:end_idx]
- f, ax = plt.subplots()
- time_slice = slice(start_time,end_time)
- # add classifier
- results = seq.classifier.classifier_results.sel(time=time_slice)
- time = (results.time-start_time) * 1000
- max_time = time.max()
- cmap = copy.copy(plt.cm.get_cmap('bone_r'))
- cmap.set_bad(color="lightgrey", alpha=1.0)
- (
- results
- .assign_coords(time=time)
- .acausal_posterior.sum("state")
- .plot(
- x="time",
- y="position",
- robust=True,
- add_colorbar=False,
- zorder=0,
- rasterized=True,
- cmap=cmap,
- ax=ax
- )
- )
- seq_position = seq.binned_data.position['Linear'].loc[time_slice]
- max_position = int(
- np.ceil(seq.binned_data.position['Linear'].max()))
- ax.plot(time, seq_position, linestyle="--", linewidth=2,
- color="magenta", clip_on=False)
- rtc.plot_graph_as_1D(seq.position.arena.track_graph,
- edge_spacing=seq.position.arena.edge_spacing,
- ax=ax, axis="y", other_axis_start=max_time+50)
- f.savefig(join(figure_path,'Noether_DY02_decode_snippet_alt_decoder_bayes.pdf'), format='pdf')
- # %%
- # 2D decoder
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session_alt_decoder, _ = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility', modifier='_2D')
- print(f"{np.nanmean(immob_data_by_session_alt_decoder['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session_alt_decoder['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_alt_decoder['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['non_local'], figure_path,
- 'immob_with_nl_alt_decoder_2D', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_alt_decoder['frac_non_local'], figure_path,
- 'perc_immob_content_nl_alt_decoder_2D', '% Immobility Time with NonLocal Decode', [0,100])
- # %%
- # plot position and decoded position for snippet of data
- # open example
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences_2D.txt'),
- load_objects=True)
- # subset data
- start_time = 1260
- end_time = 1290
- start_idx = np.argmin(np.abs(seq.binned_data.timestamps-start_time))
- end_idx = np.argmin(np.abs(seq.binned_data.timestamps-end_time))
- subset_timestamps = seq.binned_data.timestamps[start_idx:end_idx]
- f, ax = plt.subplots()
- time_slice = slice(start_time,end_time)
- # add classifier
- results = seq.classifier.classifier_results.sel(time=time_slice)
- time = (results.time-start_time) * 1000
- max_time = time.max()
- cmap = copy.copy(plt.cm.get_cmap('bone_r'))
- cmap.set_bad(color="lightgrey", alpha=1.0)
- (
- results
- .assign_coords(time=time)
- .acausal_posterior.sum("state")
- .plot(
- x="time",
- y="position",
- robust=True,
- add_colorbar=False,
- zorder=0,
- rasterized=True,
- cmap=cmap,
- ax=ax
- )
- )
- seq_position = seq.binned_data.position['Linear'].loc[time_slice]
- max_position = int(
- np.ceil(seq.binned_data.position['Linear'].max()))
- ax.plot(time, seq_position, linestyle="--", linewidth=2,
- color="magenta", clip_on=False)
- rtc.plot_graph_as_1D(seq.position.arena.track_graph,
- edge_spacing=seq.position.arena.edge_spacing,
- ax=ax, axis="y", other_axis_start=max_time+50)
- f.savefig(join(figure_path,'Noether_DY02_decode_snippet_alt_decoder_2D.pdf'), format='pdf')
- # %% [markdown]
- # # Figure 3 & S4
- # %% [markdown]
- # ### example cells with fields at local and non-local positions
- # %%
- # repeat raster with color coding by local/nonlocal
- # first, load the interval
- row = sessions.iloc[133]
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- print(seq.name)
- start_time = seq.intervals.intervals.iloc[1].start_time
- end_time = seq.intervals.intervals.iloc[1].end_time
- start_idx = np.argmin(np.abs(seq.binned_data.timestamps-start_time))
- end_idx = np.argmin(np.abs(seq.binned_data.timestamps-end_time))
- subset_timestamps = seq.binned_data.timestamps[start_idx:end_idx]
- # %%
- # rasters: single cells
- field_locs, field_peaks, field_sizes, field_spacing = seq.find_fields()
- pf = seq.classifier.classifier.place_fields_[('', 0)]
- n_cells = pf.shape[1]
- decoded_bin = [59]
- local_cells = []
- for u in range(n_cells):
- for f in field_locs[u]:
- if np.any(np.isin(decoded_bin, f)):
- local_cells.append(u)
- local_cells = np.unique(np.asarray(local_cells))
- decoded_bin = [29,92,93,94,95,96]
- nonlocal_cells = []
- for u in range(n_cells):
- for f in field_locs[u]:
- if np.any(np.isin(decoded_bin, f)):
- nonlocal_cells.append(u)
- nonlocal_cells = np.unique(np.asarray(nonlocal_cells))
- # %%
- for ex_cell in [20, 53, 30]:
- interval_spikes = seq.binned_data.spikes[:,start_idx:end_idx]
- f, ax = plt.subplots(1, figsize=(8,3))
- # plot spikes from cells contributing to decode (over all time) in black
- spike_time_ind = np.nonzero(interval_spikes[ex_cell, :])[0]
- ax.scatter(1000*(subset_timestamps[spike_time_ind]-start_time),
- np.ones(len(spike_time_ind)), color='black', zorder=1,
- marker='|', linewidth=1)
- # plot spikes contributing to nonlocal decode in cyan during non-local times
- for i in range(len(nonlocal_intervals)):
- interval_spikes = seq.binned_data.spikes[:,int(start_idx+nonlocal_intervals[i][0]*5):int(start_idx+nonlocal_intervals[i][1]*5)]
- spike_time_ind_nl = np.nonzero(interval_spikes[ex_cell, :])[0]
- ax.scatter(1000*(subset_timestamps[nonlocal_intervals[i][0]*5+spike_time_ind_nl]-start_time),
- np.ones(len(spike_time_ind_nl)), color='cyan', zorder=1,
- marker='|', linewidth=2)
- ax.set(xlim=[0,int((end_time-start_time)*1000)], ylabel='Neuron')
- f.savefig(join(figure_path,f'Noether_DY02_MEC_{ex_cell}_raster.pdf'), format='pdf')
- # %%
- bin_cm = 2
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- seq.spikes.subset_by_channel(MEC_channels)
- for u in [20, 53, 30]:
- fr_map, xbins, ybins, max_fr = calc_fr_map(seq.spikes.spikes[u], seq.position, bin_cm, smooth=True)
- print(f'Unit {u} Max FR {max_fr}')
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,f'Noether_DY02_MEC_{u}_heatmap.pdf'), format='pdf')
- # %% [markdown]
- # ### Cells that decode to non-local vs local positions during non-local vs local times
- # %%
- # participation of L vs NL coding cells during L vs NL intervals (L + NL multi-field cells?, L always active?)
- #### for non-local times
- nl_perc_cells, nl_perc_spikes, l_perc_cells, l_perc_spikes, lnl_perc_cells, lnl_perc_spikes, \
- animal, session, dur = [[] for _ in range(9)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- animal.extend([animal_idx] * len(seq.stats))
- session.extend([sess_idx] * len(seq.stats))
- dur.extend(seq.stats.Duration)
- linear_to_bins = np.array(seq.classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position'])
- pf = seq.classifier.classifier.place_fields_[('', 0)]
- n_cells = pf.shape[1]
- for s, interval in seq.intervals.intervals.iterrows():
- cr = seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- map_position_ind = cr.sum("state").acausal_posterior.argmax("position").values
- decoded_bins = np.unique(map_position_ind)
- linear_pos = np.asarray(seq.binned_data.position["Linear"].loc[interval.start_time:interval.end_time])
- animal_bins = np.unique(np.argmin(np.abs(linear_to_bins[:,np.newaxis]-linear_pos), axis=0))
- idx = seq.intervals.indices.iloc[s]
- # find cells with significant fields at decoded locations
- field_cells = []
- for u in range(n_cells):
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(decoded_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- nl_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- nl_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- # repeat for cells with fields at current location
- field_cells = []
- for u in range(n_cells):
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(animal_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- l_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- l_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- # repeat for cells with fields at current AND decoded location
- local_cells = field_cells
- field_cells = []
- for u in local_cells:
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(decoded_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- lnl_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- lnl_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- print(row['File'])
- # append onto larger data_seq
- nonlocal_fields_data_by_seq2 = pd.DataFrame({'Animal': animal, 'Session': session, 'Duration': dur,
- 'Nonlocal_percent_cells': nl_perc_cells,
- 'Nonlocal_percent_spikes': nl_perc_spikes,
- 'Local_percent_cells': l_perc_cells,
- 'Local_percent_spikes': l_perc_spikes,
- 'Both_percent_cells': lnl_perc_cells,
- 'Both_percent_spikes': lnl_perc_spikes})
- # %%
- #### for local times
- nl_perc_cells, nl_perc_spikes, l_perc_cells, l_perc_spikes, lnl_perc_cells, lnl_perc_spikes, \
- animal, session, dur = [[] for _ in range(9)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_local_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- animal.extend([animal_idx] * len(seq.stats))
- session.extend([sess_idx] * len(seq.stats))
- dur.extend(seq.stats.Duration)
- linear_to_bins = np.array(seq.classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position'])
- pf = seq.classifier.classifier.place_fields_[('', 0)]
- n_cells = pf.shape[1]
- for s, interval in seq.intervals.intervals.iterrows():
- cr = seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- map_position_ind = cr.sum("state").acausal_posterior.argmax("position").values
- decoded_bins = np.unique(map_position_ind)
- linear_pos = np.asarray(seq.binned_data.position["Linear"].loc[interval.start_time:interval.end_time])
- animal_bins = np.unique(np.argmin(np.abs(linear_to_bins[:,np.newaxis]-linear_pos), axis=0))
- idx = seq.intervals.indices.iloc[s]
- # find cells with significant fields at decoded locations
- field_cells = []
- for u in range(n_cells):
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(decoded_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- nl_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- nl_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- # repeat for cells with fields at current location
- field_cells = []
- for u in range(n_cells):
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(animal_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- l_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- l_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- # repeat for cells with fields at current AND decoded location
- local_cells = field_cells
- field_cells = []
- for u in local_cells:
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(decoded_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # calculate proportion of all cells with fields,
- # and of those: proportion active, fr, number of fields per cell, and size and spacing of those fields
- seq_spikes = seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']]
- lnl_perc_cells.append(np.sum(np.sum(seq_spikes, axis=1)>0)/seq.stats.Num_units[s])
- lnl_perc_spikes.append(np.sum(seq_spikes)/seq.stats.Num_spikes[s])
- print(row['File'])
- # append onto larger data_seq
- local_fields_data_by_seq2 = pd.DataFrame({'Animal': animal, 'Session': session, 'Duration': dur,
- 'Nonlocal_percent_cells': nl_perc_cells,
- 'Nonlocal_percent_spikes': nl_perc_spikes,
- 'Local_percent_cells': l_perc_cells,
- 'Local_percent_spikes': l_perc_spikes,
- 'Both_percent_cells': lnl_perc_cells,
- 'Both_percent_spikes': lnl_perc_spikes})
- # %%
- with open(join(figure_path,'nonlocal_fields_data_by_seq2.pkl'), 'wb') as file:
- pickle.dump(nonlocal_fields_data_by_seq2, file)
- with open(join(figure_path,'local_fields_data_by_seq2.pkl'), 'wb') as file:
- pickle.dump(local_fields_data_by_seq2, file)
- # %%
- plot_compare_paired_metrics('Local_percent_cells', 'Nonlocal_percent_cells', nonlocal_fields_data_by_seq2, figure_path,
- 'nonlocal_l_vs_nl_field_cells', '% Active Cells That Have Fields at Location', [0,1])
- plot_compare_paired_metrics('Nonlocal_percent_cells', 'Both_percent_cells', nonlocal_fields_data_by_seq2, figure_path,
- 'nonlocal_both_vs_nl_field_cells', '% Active Cells That Have Fields at Location', [0,1])
- plot_compare_paired_metrics('Local_percent_spikes', 'Nonlocal_percent_spikes', nonlocal_fields_data_by_seq2, figure_path,
- 'nonlocal_l_vs_nl_field_spikes', '% Spikes from Cells That Have Fields at Location', [0,1])
- plot_compare_paired_metrics('Nonlocal_percent_spikes', 'Both_percent_spikes', nonlocal_fields_data_by_seq2, figure_path,
- 'nonlocal_both_vs_nl_field_spikes', '% Spikes from Cells That Have Fields at Location', [0,1])
- # plot_compare_paired_metrics('Local_percent_cells', 'Nonlocal_percent_cells', local_fields_data_by_seq2, figure_path,
- # 'local_l_vs_nl_field_cells', '% Active Cells That Have Fields at Location', [0,1])
- # plot_compare_paired_metrics('Nonlocal_percent_cells', 'Both_percent_cells', local_fields_data_by_seq2, figure_path,
- # 'local_both_vs_nl_field_cells', '% Active Cells That Have Fields at Location', [0,1])
- # plot_compare_paired_metrics('Local_percent_spikes', 'Nonlocal_percent_spikes', local_fields_data_by_seq2, figure_path,
- # 'local_l_vs_nl_field_spikes', '% Spikes from Cells That Have Fields at Location', [0,1])
- # plot_compare_paired_metrics('Nonlocal_percent_spikes', 'Both_percent_spikes', local_fields_data_by_seq2, figure_path,
- # 'local_both_vs_nl_field_spikes', '% Spikes from Cells That Have Fields at Location', [0,1])
- # %%
- is_non_local = []
- is_non_local.extend([False] * len(local_fields_data_by_seq2))
- is_non_local.extend([True] * len(nonlocal_fields_data_by_seq2))
- local_nonlocal_fields_equivalent_data_by_seq2 = pd.concat([local_fields_data_by_seq2, nonlocal_fields_data_by_seq2], ignore_index=True)
- local_nonlocal_fields_equivalent_data_by_seq2.loc[:,'Non_local'] = is_non_local
- plot_seq_metrics_comparison_over_events(local_nonlocal_fields_equivalent_data_by_seq2, 'Local_percent_cells', 'Non_local', figure_path,
- 'local_vs_nonlocal_l_perc_cells', '% Active Cells That Have Fields at Location', [0,1])
- plot_seq_metrics_comparison_over_events(local_nonlocal_fields_equivalent_data_by_seq2, 'Local_percent_spikes', 'Non_local', figure_path,
- 'local_vs_nonlocal_l_perc_spikes', '% Spikes from Cells That Have Fields at Location', [0,1])
- # %% [markdown]
- # ### are decodes less non-local without non-local spiking
- # %%
- # remove these spikes from test set to show now decodes are only local
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- linear_to_bins = np.array(seq.classifier.classifier.environments[0].place_bin_centers_nodes_df_['linear_position'])
- pf = seq.classifier.classifier.place_fields_[('', 0)]
- n_cells = pf.shape[1]
- for s, interval in seq.intervals.intervals.iterrows():
- cr = seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- map_position_ind = cr.sum("state").acausal_posterior.argmax("position").values
- decoded_bins = np.unique(map_position_ind)
- idx = seq.intervals.indices.iloc[s]
- # find cells with significant fields at decoded locations
- field_cells = []
- for u in range(n_cells):
- for f in field_locs[animal_idx][sess_idx][u]:
- if np.any(np.isin(decoded_bins, f)):
- field_cells.append(u)
- field_cells = np.unique(np.asarray(field_cells, dtype=int))
- # remove non-local decode spikes
- seq.binned_data.spikes[field_cells, idx['start_index']:idx['end_index']] = 0
- # save binned data
- binned_data = Binned_Data(seq.binned_data.name)
- binned_data.spikes = seq.binned_data.spikes
- binned_data.name = seq.binned_data.name[:-4]+'_NLspikesremoved.txt'
- binned_data.save()
- print(row['File'])
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- immob_data_by_session_CLtest, immob_data_by_seq_CLtest = combine_metrics_over_sessions(sessions, animal_dict, 'MEC_immobility_NLspikesremoved')
- # %%
- print(f"{np.nanmean(immob_data_by_session_CLtest['non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_CLtest['non_local'],axis=1)):.02f}" +\
- f"% of immobility bouts have nonlocal coding,\n" +\
- f"and {np.nanmean(immob_data_by_session_CLtest['frac_non_local']):.02f} +/- {stats.sem(np.nanmean(immob_data_by_session_CLtest['frac_non_local'],axis=1)):.02f}" +\
- f"% of time during immobility "+\
- "is spent representing nonlocal positions.")
- # %%
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_CLtest['non_local'], figure_path,
- 'immob_with_nl_CLtest', '% Immobility Bouts with NonLocal Decode', [0,100])
- plot_seq_metrics_over_sessions(n_animals, immob_data_by_session_CLtest['frac_non_local'], figure_path,
- 'perc_immob_content_nl_CLtest', '% Immobility Time with NonLocal Decode', [0,100])
- # %% [markdown]
- # ### Preferentially enriched cells
- # %%
- seq_type = 'MEC_nonlocal_immobility'
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_shuffles = 1000
- n_sessions = 20
- n_animals = len(animal_dict)
- over_fr = np.full((n_animals, n_sessions), np.NaN)
- over_fr_list = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- over_percent_intervals = np.full((n_animals, n_sessions), np.NaN)
- over_percent_intervals_list = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- # load spikes and intervals
- binned_data = Binned_Data(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Binned_Data',
- row['File']+'_MEC_binned_data.txt'))
- intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_'+seq_type+'_intervals.txt'))
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_'+seq_type+'_sequences.txt'))
- interval_dur = intervals.intervals.end_time-intervals.intervals.start_time
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- shuffled_fr = np.zeros((n_shuffles, binned_data.spikes.shape[0]))
- shuffled_percent_intervals = np.zeros((n_shuffles, binned_data.spikes.shape[0]))
- for s in range(n_shuffles):
- # shuffle each cell separately
- shuffled_spikes = binned_data.spikes[:, np.random.permutation(binned_data.spikes.shape[1])]
- # calculate fr during intervals & participation in intervals
- # (same code as calc_cell_metrics in Sequences class)
- fr = []
- percent_intervals = []
- for c in range(binned_data.spikes.shape[0]):
- fr_by_interval = 0
- participating_seq = 0
- for i, idx in intervals.indices.iterrows():
- num_spikes = np.sum(shuffled_spikes[c, idx['start_index']:idx['end_index']])
- fr_by_interval += num_spikes/interval_dur.iloc[i]
- if num_spikes>0:
- participating_seq += 1
- fr.append(fr_by_interval/intervals.n_seq)
- percent_intervals.append(participating_seq/intervals.n_seq)
- # append to shuffle distribution
- shuffled_fr[s,:] = fr
- shuffled_percent_intervals[s,:] = percent_intervals
- # calculate 95th percentile
- fr_95_percentile = np.percentile(shuffled_fr, 95, axis=0)
- percent_intervals_95_percentile = np.percentile(shuffled_percent_intervals, 95, axis=0)
- # count how many cells are above this threshold
- over_fr[animal_idx, sess_idx] = np.nanmean(seq.stats_by_cell.FR>fr_95_percentile)
- over_fr_list[animal_idx][sess_idx] = np.where(seq.stats_by_cell.FR>fr_95_percentile)[0].tolist()
- over_percent_intervals[animal_idx, sess_idx] = \
- np.nanmean(seq.stats_by_cell.Percent_intervals>percent_intervals_95_percentile)
- over_percent_intervals_list[animal_idx][sess_idx] = \
- np.where(seq.stats_by_cell.Percent_intervals>percent_intervals_95_percentile)[0].tolist()
- print(row['File'])
- # %%
- with open(join(figure_path,'over_fr.pkl'), 'wb') as file:
- pickle.dump(over_fr, file)
- with open(join(figure_path,'over_percent_intervals.pkl'), 'wb') as file:
- pickle.dump(over_percent_intervals, file)
- with open(join(figure_path,'over_fr_list.pkl'), 'wb') as file:
- pickle.dump(over_fr_list, file)
- with open(join(figure_path,'over_percent_intervals_list.pkl'), 'wb') as file:
- pickle.dump(over_percent_intervals_list, file)
- # %%
- print(f"{np.nanmean(over_fr)*100:.02f} +/- {stats.sem(np.nanmean(over_fr,axis=1))*100:.02f}" +\
- f"% of cells have > 95th percentile of shuffled FR during nonlocal coding.")
- # %%
- # plot
- plot_seq_metrics_over_sessions(n_animals, over_fr*100, figure_path,
- 'recruited_fr', '% Units with FR > 95th Percentile', [0,100])
- # %% [markdown]
- # ### DV axis
- # %%
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 10
- n_animals = len(animal_dict)
- dist_from_border = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'))
- if ('2021_pilot' in row['Base_Directory']) or ('2022_winter' in row['Base_Directory']):
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- spikes = Spikes(join(row['Base_Directory'],
- 'Preprocessed_Data/Spikes/g1',
- row['File']+'_imec0_spikes.txt'))
- spikes.subset_by_channel(channels)
- dist_from_border[animal_idx][sess_idx] = [depth - border_dict[row['Animal']] for depth in electrodes.electrodes.Rel_Z.iloc[spikes.spike_channel].values.tolist()]
- else:
- if (row['Animal']=='Lamarr') and (sess_idx>=7):
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- else:
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec1_spikes.txt'))
- channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- spikes.subset_by_channel(channels)
- shanks = (electrodes.electrodes.Rel_Y.iloc[spikes.spike_channel].values/250).astype(int)
- depths = electrodes.electrodes.Rel_Z.iloc[spikes.spike_channel].values
- for i, d in enumerate(depths):
- dist_from_border[animal_idx][sess_idx].append(border_dict[row['Animal']][shanks[i]] - d)
- # %%
- with open(join(figure_path,'dist_from_border.pkl'), 'wb') as file:
- pickle.dump(dist_from_border, file)
- # %%
- # bin cells by DV depth
- n_sessions = 10
- dv_bin1, dv_bin2, dv_bin3, dv_bin4 = [[[[] for _ in range(n_sessions)] for _ in range(n_animals)] for _ in range(4)]
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- dv_bin1[animal_idx][sess_idx] = np.where([i<500 for i in dist_from_border[animal_idx][sess_idx]])[0]
- dv_bin2[animal_idx][sess_idx] = np.where([i>=500 and i<1000 for i in dist_from_border[animal_idx][sess_idx]])[0]
- dv_bin3[animal_idx][sess_idx] = np.where([i>=1000 and i<1500 for i in dist_from_border[animal_idx][sess_idx]])[0]
- dv_bin4[animal_idx][sess_idx] = np.where([i>=1500 for i in dist_from_border[animal_idx][sess_idx]])[0]
- # %%
- # compare DV depths of enriched vs unenriched cells
- sess_idx = 0
- percentile = over_fr_list
- enriched_cells = []
- enriched_animals = []
- unenriched_cells = []
- unenriched_animals = []
- for animal_idx in range(len(animal_dict)):
- unenriched_cells.extend([dist_from_border[animal_idx][sess_idx][i] for i in range(len(dist_from_border[animal_idx][sess_idx])) \
- if i not in percentile[animal_idx][sess_idx]])
- unenriched_animals.extend([animal_idx]*(len(dist_from_border[animal_idx][sess_idx]) - len(percentile[animal_idx][sess_idx])))
- enriched_cells.extend([dist_from_border[animal_idx][sess_idx][i] for i in percentile[animal_idx][sess_idx]])
- enriched_animals.extend([animal_idx]*len(percentile[animal_idx][sess_idx]))
- data_df = pd.DataFrame({'Animal': unenriched_animals + enriched_animals,
- 'Session_Unique': [sess_idx]*len(unenriched_cells + enriched_cells),
- 'Condition': [0]*len(unenriched_cells) + [1]*len(enriched_cells),
- 'Indep_Var': unenriched_cells + enriched_cells})
- data_df.loc[data_df.Indep_Var<0,'Indep_Var'] = 0
- plot_compare_unpaired_metrics(unenriched_cells, enriched_cells, data_df, figure_path, \
- 'nonlocal_enriched_cells_by_fr', 'Recruited > 95th percentile', [0, 3000])
- # %%
- # enrichment: what proportion of cells from each depth bin are on the enrichment lists?
- enriched_cells = over_fr_list
- enriched_dv_bin1, enriched_dv_bin2, enriched_dv_bin3, enriched_dv_bin4 = \
- [np.full((len(animal_dict),n_sessions), np.NaN) for _ in range(4)]
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- # proportion of cells in enrichment list
- enriched_dv_bin1[animal_idx][sess_idx] = len(np.intersect1d(dv_bin1[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(dv_bin1[animal_idx][sess_idx]) if len(dv_bin1[animal_idx][sess_idx])>0 else np.NaN
- enriched_dv_bin2[animal_idx][sess_idx] = len(np.intersect1d(dv_bin2[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(dv_bin2[animal_idx][sess_idx]) if len(dv_bin2[animal_idx][sess_idx])>0 else np.NaN
- enriched_dv_bin3[animal_idx][sess_idx] = len(np.intersect1d(dv_bin3[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(dv_bin3[animal_idx][sess_idx]) if len(dv_bin3[animal_idx][sess_idx])>0 else np.NaN
- enriched_dv_bin4[animal_idx][sess_idx] = len(np.intersect1d(dv_bin4[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(dv_bin4[animal_idx][sess_idx]) if len(dv_bin4[animal_idx][sess_idx])>0 else np.NaN
- plot_feature_by_depth_bin(enriched_dv_bin1, enriched_dv_bin2, enriched_dv_bin3, enriched_dv_bin4, \
- figure_path, 'proportion_enriched_by_depth_bin_fr', '% Units with Recruitment > 95th Percentile', [0,1])
- # %%
- # calculate field sizes and spacing
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 10
- n_animals = len(animal_dict)
- field_locs = np.empty((n_animals, n_sessions), dtype=object)
- field_peaks = np.empty((n_animals, n_sessions), dtype=object)
- field_sizes = np.empty((n_animals, n_sessions), dtype=object)
- field_spacing = np.empty((n_animals, n_sessions), dtype=object)
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- # any sequence will do; we're just using its contained objects
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- try:
- field_locs[animal_idx, sess_idx], field_peaks[animal_idx, sess_idx], \
- field_sizes[animal_idx, sess_idx], field_spacing[animal_idx, sess_idx] = seq.find_fields()
- print(row['File'])
- except:
- print(f"ERROR: {row['File']}")
- # %%
- with open(join(figure_path,'field_locs.pkl'), 'wb') as file:
- pickle.dump(field_locs, file)
- with open(join(figure_path,'field_peaks.pkl'), 'wb') as file:
- pickle.dump(field_peaks, file)
- with open(join(figure_path,'field_sizes.pkl'), 'wb') as file:
- pickle.dump(field_sizes, file)
- with open(join(figure_path,'field_spacing.pkl'), 'wb') as file:
- pickle.dump(field_spacing, file)
- # %%
- # is this due to enriched cells having higher field sizes?
- # repeat with FR
- percentile = over_fr_list
- sess_idx = 0
- # suppress the "Mean of an empty slice" warning that will occur thousands of times
- # (due to cells with single fields having empty arrays for field_spacing)
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore", category=RuntimeWarning)
- enriched_cells = []
- enriched_animals = []
- unenriched_cells = []
- unenriched_animals = []
- for animal_idx in range(len(animal_dict)):
- if field_sizes[animal_idx][sess_idx] is not None:
- unenriched_cells.extend([np.nanmean(field_sizes[animal_idx][sess_idx][i]) for i in range(len(field_sizes[animal_idx][sess_idx])) \
- if i not in percentile[animal_idx][sess_idx]])
- unenriched_animals.extend([animal_idx]*(len(field_sizes[animal_idx][sess_idx]) - len(percentile[animal_idx][sess_idx])))
- enriched_cells.extend([np.nanmean(field_sizes[animal_idx][sess_idx][i]) for i in percentile[animal_idx][sess_idx]])
- enriched_animals.extend([animal_idx]*len(percentile[animal_idx][sess_idx]))
- data_df = pd.DataFrame({'Animal': unenriched_animals + enriched_animals,
- 'Session_Unique': [sess_idx]*len(unenriched_cells + enriched_cells),
- 'Condition': [0]*len(unenriched_cells) + [1]*len(enriched_cells),
- 'Indep_Var': unenriched_cells + enriched_cells})
- data_df.loc[data_df.Indep_Var<0,'Indep_Var'] = 0
- plot_compare_unpaired_metrics(unenriched_cells, enriched_cells, data_df, figure_path, \
- 'field_sizes_nonlocal_enriched_cells_by_fr', 'Recruited > 95th percentile', [0, 100])
- # %%
- # bin cells by field size
- n_sessions = 10
- fs_bin1, fs_bin2, fs_bin3, fs_bin4 = [[[[] for _ in range(n_sessions)] for _ in range(n_animals)] for _ in range(4)]
- # suppress the "Mean of an empty slice" warning that will occur thousands of times
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore", category=RuntimeWarning)
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- if field_sizes[animal_idx][sess_idx] is not None:
- fs = [np.nanmean(field_sizes[animal_idx][sess_idx][i]) for i in range(len(field_sizes[animal_idx][sess_idx]))]
- fs_bin1[animal_idx][sess_idx] = np.where([i<22 for i in fs])[0]
- fs_bin2[animal_idx][sess_idx] = np.where([i>=22 and i<28 for i in fs])[0]
- fs_bin3[animal_idx][sess_idx] = np.where([i>=28 and i<34 for i in fs])[0]
- fs_bin4[animal_idx][sess_idx] = np.where([i>=34 for i in fs])[0]
- # %%
- # what proportion of cells from each field size bin are on the enrichment lists?
- enriched_cells = over_fr_list
- enriched_fs_bin1, enriched_fs_bin2, enriched_fs_bin3, enriched_fs_bin4 = \
- [np.full((len(animal_dict),n_sessions), np.NaN) for _ in range(4)]
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- # proportion of cells in enrichment list
- enriched_fs_bin1[animal_idx][sess_idx] = len(np.intersect1d(fs_bin1[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(fs_bin1[animal_idx][sess_idx]) if len(fs_bin1[animal_idx][sess_idx])>0 else np.NaN
- enriched_fs_bin2[animal_idx][sess_idx] = len(np.intersect1d(fs_bin2[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(fs_bin2[animal_idx][sess_idx]) if len(fs_bin2[animal_idx][sess_idx])>0 else np.NaN
- enriched_fs_bin3[animal_idx][sess_idx] = len(np.intersect1d(fs_bin3[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(fs_bin3[animal_idx][sess_idx]) if len(fs_bin3[animal_idx][sess_idx])>0 else np.NaN
- enriched_fs_bin4[animal_idx][sess_idx] = len(np.intersect1d(fs_bin4[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(fs_bin4[animal_idx][sess_idx]) if len(fs_bin4[animal_idx][sess_idx])>0 else np.NaN
- plot_feature_by_depth_bin(enriched_fs_bin1, enriched_fs_bin2, enriched_fs_bin3, enriched_fs_bin4, \
- figure_path, 'proportion_enriched_by_field_size_fr', '% Units with Recruitment > 95th Percentile', [0,1])
- # %% [markdown]
- # ### Spatial variables
- # %%
- # calculate enrichment during Xmaze non-local coding using Xmaze+OF-sorted sessions
- start_time = time.time()
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze_celltypes_g1.csv')
- n_shuffles = 1000
- n_sessions = 10
- n_animals = len(animal_dict)
- over_fr = np.full((n_animals, n_sessions), np.NaN)
- over_fr_list = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=10:
- # load spikes and intervals
- binned_data = Binned_Data(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Binned_Data',
- row['File']+'_MEC_g1+3_binned_data.txt'))
- intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_g1+3_nonlocal_immobility_sequences.txt'))
- interval_dur = intervals.intervals.end_time-intervals.intervals.start_time
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- shuffled_fr = np.zeros((n_shuffles, binned_data.spikes.shape[0]))
- for s in range(n_shuffles):
- # shuffle each cell separately
- shuffled_spikes = binned_data.spikes[:, np.random.permutation(binned_data.spikes.shape[1])]
- # calculate fr during intervals & participation in intervals
- # (same code as calc_cell_metrics in Sequences class)
- fr = []
- for c in range(binned_data.spikes.shape[0]):
- fr_by_interval = 0
- for i, idx in intervals.indices.iterrows():
- num_spikes = np.sum(shuffled_spikes[c, idx['start_index']:idx['end_index']])
- fr_by_interval += num_spikes/interval_dur.iloc[i]
- fr.append(fr_by_interval/intervals.n_seq)
- # append to shuffle distribution
- shuffled_fr[s,:] = fr
- # calculate 95th percentile
- fr_95_percentile = np.percentile(shuffled_fr, 95, axis=0)
- # count how many cells are above this threshold
- over_fr[animal_idx, sess_idx] = np.nanmean(seq.stats_by_cell.FR>fr_95_percentile)
- over_fr_list[animal_idx][sess_idx] = np.where(seq.stats_by_cell.FR>fr_95_percentile)[0].tolist()
- print(f"{row['File']} {time.time() - start_time} seconds")
- # %%
- with open(join(figure_path,'over_fr_OF.pkl'), 'wb') as file:
- pickle.dump(over_fr, file)
- with open(join(figure_path,'over_fr_list_OF.pkl'), 'wb') as file:
- pickle.dump(over_fr_list, file)
- # %%
- # refs: border (Solstad 2008), speed (Kropff 2015), HD (Taube 1990), grid (Hafting 2005), spatial aperiodic (Diehl 2017)
- start_time = time.time()
- bin_cm = 2.5
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_celltypes.csv')
- n_sessions = 10
- n_animals = len(animal_dict)
- spatial_cells, spatial_aperiodic_cells, grid_cells, border_cells, speed_cells, hd_cells = \
- [[[[] for _ in range(n_sessions)] for _ in range(n_animals)] for _ in range(6)]
- for i, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error']:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- position.position = position.position[position.position.Velocity>2]
- if ("2023_spring" in row['Base_Directory']) or ("2024_winter" in row['Base_Directory']):
- if (row['Animal']=='Lamarr') and (int(row['Session'][-2:])>=8):
- mec_spikes = Spikes(name=join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- else:
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec1_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- mec_spikes.subset_by_channel(MEC_channels)
- else:
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- mec_spikes.subset_by_channel(channels)
- spatial_sig, stability_sig, grid_sig, border_sig, speed_sig, HD_sig = \
- [np.full(len(mec_spikes.spikes), np.NaN) for _ in range(6)]
- for u in range(len(mec_spikes.spikes)):
- fr = bin_spikes(mec_spikes.spikes[u], position.position.Timestamp)
- _, spatial_sig[u] = permutation_test_spatial_info(fr, position, bin_cm)
- # _, stability_sig[u] = permutation_test_spatial_stability(fr, position, bin_cm)
- try: # sometimes causes timeout error
- _, grid_sig[u], _, _, _ = permutation_test_grid_score(fr, position, bin_cm)
- except:
- pass
- _, border_sig[u] = permutation_test_border_score(fr, position, bin_cm)
- _, speed_sig[u] = speed_score_traditional(position.position.Velocity, fr)
- _, HD_sig[u], _, _, _, _ = angle_score_traditional(position.position.HD, fr)
- spatial_cells[animal_idx][sess_idx] = np.where(spatial_sig<0.05)[0]
- #np.intersect1d(np.where(spatial_sig<0.05)[0], np.where(stability_sig<0.05)[0])
- grid_cells[animal_idx][sess_idx] = np.where(grid_sig<0.05)[0]
- border_cells[animal_idx][sess_idx] = np.where(border_sig<0.05)[0]
- spatial_aperiodic_cells[animal_idx][sess_idx] = np.array(list(set(spatial_cells[animal_idx][sess_idx]) - \
- set(grid_cells[animal_idx][sess_idx]) - \
- set(border_cells[animal_idx][sess_idx])))
- speed_cells[animal_idx][sess_idx] = np.where(speed_sig<0.05)[0]
- hd_cells[animal_idx][sess_idx] = np.where(HD_sig<0.05)[0]
- print(f"{row['File']} {time.time() - start_time} seconds")
- # %%
- # enrichment: are any of these cells on the enrichment lists?
- enriched_cells = over_fr_list
- enriched_spatial, enriched_grid, enriched_border, enriched_spatial_aperiodic, \
- enriched_speed, enriched_hd = [np.full((len(animal_dict),len(session_range)), np.NaN) for _ in range(6)]
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- # proportion of cells in enrichment list
- enriched_spatial[animal_idx][sess_idx] = len(np.intersect1d(spatial_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(spatial_cells[animal_idx][sess_idx]) if len(spatial_cells[animal_idx][sess_idx])>0 else np.NaN
- enriched_grid[animal_idx][sess_idx] = len(np.intersect1d(grid_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(grid_cells[animal_idx][sess_idx]) if len(grid_cells[animal_idx][sess_idx])>0 else np.NaN
- enriched_border[animal_idx][sess_idx] = len(np.intersect1d(border_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(border_cells[animal_idx][sess_idx]) if len(border_cells[animal_idx][sess_idx])>0 else np.NaN
- enriched_spatial_aperiodic[animal_idx][sess_idx] = len(np.intersect1d(spatial_aperiodic_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(spatial_aperiodic_cells[animal_idx][sess_idx]) if len(spatial_aperiodic_cells[animal_idx][sess_idx])>0 else np.NaN
- enriched_speed[animal_idx][sess_idx] = len(np.intersect1d(speed_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(speed_cells[animal_idx][sess_idx]) if len(speed_cells[animal_idx][sess_idx])>0 else np.NaN
- enriched_hd[animal_idx][sess_idx] = len(np.intersect1d(hd_cells[animal_idx][sess_idx], enriched_cells[animal_idx][sess_idx]))/ \
- len(hd_cells[animal_idx][sess_idx]) if len(hd_cells[animal_idx][sess_idx])>0 else np.NaN
- plot_feature_by_cell_type(enriched_spatial, enriched_grid, enriched_border, enriched_spatial_aperiodic, enriched_speed, enriched_hd, \
- figure_path, 'proportion_enriched_by_cell_type_fr', '% Units with Recruitment > 95th Percentile', [0,1])
- plot_feature_by_cell_type_3types(enriched_spatial, enriched_speed, enriched_hd, \
- figure_path, 'proportion_enriched_by_cell_type_3categories_fr', '% Units with Recruitment > 95th Percentile', [0,1])
- plot_feature_by_cell_type_3types(enriched_grid, enriched_border, enriched_spatial_aperiodic, \
- figure_path, 'proportion_enriched_by_cell_type_3spatialcategories_fr', '% Units with Recruitment > 95th Percentile', [0,1])
- # %%
- # pie chart of categorzied % of enriched cells that represent each cell type (including overlaps)
- # pie chart of % of categorized cells open field that represent each cell type (including overlaps)
- from functools import reduce
- enriched_cells = over_fr_list
- enriched_frac = over_fr
- enriched_spatial, enriched_grid, enriched_border, enriched_spatial_aperiodic, \
- enriched_speed, enriched_hd, enriched_spatial_speed, enriched_spatial_hd, enriched_speed_hd, \
- enriched_spatial_speed_hd, \
- spatial, grid, border, spatial_aperiodic, \
- speed, hd, spatial_speed, spatial_hd, speed_hd, \
- spatial_speed_hd, = \
- [np.full((len(animal_dict),n_sessions), np.NaN) for _ in range(20)]
- for a in range(n_animals):
- for s in range(n_sessions):
- n_cells = len(over_fr_list[a][s])/over_fr[a][s]
- if len(enriched_cells[a][s])>0:
- # proportion of enriched cells of each type
- enriched_grid[a][s] = len(np.intersect1d(grid_cells[a][s], enriched_cells[a][s]))/ \
- len(enriched_cells[a][s])
- enriched_border[a][s] = len(np.intersect1d(border_cells[a][s], enriched_cells[a][s]))/ \
- len(enriched_cells[a][s])
- enriched_spatial_aperiodic[a][s] = len(np.intersect1d(spatial_aperiodic_cells[a][s], enriched_cells[a][s]))/ \
- len(enriched_cells[a][s])
- enriched_spatial_speed_hd[a][s] = len(reduce(np.intersect1d, (spatial_cells[a][s], speed_cells[a][s], hd_cells[a][s], enriched_cells[a][s])))/ \
- len(enriched_cells[a][s])
- enriched_spatial_speed[a][s] = len(reduce(np.intersect1d, (spatial_cells[a][s], speed_cells[a][s], enriched_cells[a][s])))/ \
- len(enriched_cells[a][s]) - enriched_spatial_speed_hd[a][s]
- enriched_spatial_hd[a][s] = len(reduce(np.intersect1d, (spatial_cells[a][s], hd_cells[a][s], enriched_cells[a][s])))/ \
- len(enriched_cells[a][s]) - enriched_spatial_speed_hd[a][s]
- enriched_speed_hd[a][s] = len(reduce(np.intersect1d, (speed_cells[a][s], hd_cells[a][s], enriched_cells[a][s])))/ \
- len(enriched_cells[a][s]) - enriched_spatial_speed_hd[a][s]
- enriched_spatial[a][s] = len(np.intersect1d(spatial_cells[a][s], enriched_cells[a][s]))/len(enriched_cells[a][s]) \
- - enriched_spatial_speed_hd[a][s] - enriched_spatial_speed[a][s] - enriched_spatial_hd[a][s]
- enriched_speed[a][s] = len(np.intersect1d(speed_cells[a][s], enriched_cells[a][s]))/len(enriched_cells[a][s]) \
- - enriched_spatial_speed_hd[a][s] - enriched_spatial_speed[a][s] - enriched_speed_hd[a][s]
- enriched_hd[a][s] = len(np.intersect1d(hd_cells[a][s], enriched_cells[a][s]))/len(enriched_cells[a][s]) \
- - enriched_spatial_speed_hd[a][s] - enriched_spatial_hd[a][s] - enriched_spatial_hd[a][s]
- # proportion of all cells of each type
- grid[a][s] = len(grid_cells[a][s])/n_cells
- border[a][s] = len(border_cells[a][s])/n_cells
- spatial_aperiodic[a][s] = len(spatial_aperiodic_cells[a][s])/n_cells
- spatial_speed_hd[a][s] = len(reduce(np.intersect1d, (spatial_cells[a][s], speed_cells[a][s], hd_cells[a][s])))/ \
- n_cells
- spatial_speed[a][s] = len(np.intersect1d(spatial_cells[a][s], speed_cells[a][s]))/ \
- n_cells - spatial_speed_hd[a][s]
- spatial_hd[a][s] = len(np.intersect1d(spatial_cells[a][s], hd_cells[a][s]))/ \
- n_cells - spatial_speed_hd[a][s]
- speed_hd[a][s] = len(np.intersect1d(speed_cells[a][s], hd_cells[a][s]))/ \
- n_cells - spatial_speed_hd[a][s]
- spatial[a][s] = len(spatial_cells[a][s])/n_cells \
- - spatial_speed_hd[a][s] - spatial_speed[a][s] - spatial_hd[a][s]
- speed[a][s] = len(speed_cells[a][s])/n_cells \
- - spatial_speed_hd[a][s] - spatial_speed[a][s] - speed_hd[a][s]
- hd[a][s] = len(hd_cells[a][s])/n_cells \
- - spatial_speed_hd[a][s] - spatial_hd[a][s] - spatial_hd[a][s]
- f, ax = plt.subplots(4)
- ax[0].pie([np.nansum(enriched_spatial), np.nansum(enriched_speed), np.nansum(enriched_hd), \
- np.nansum(enriched_spatial_speed), np.nansum(enriched_spatial_hd), np.nansum(enriched_speed_hd), \
- np.nansum(enriched_spatial_speed_hd)], \
- labels=['Position','Speed','HD','Position x Speed', 'Position x HD', 'Speed x HD', 'Position x Speed x HD'])
- ax[1].pie([np.nansum(enriched_spatial_aperiodic), \
- np.nansum(enriched_grid), \
- np.nansum(enriched_border)], \
- labels=['Spatial Aperiodic', 'Grid', 'Border'])
- ax[2].pie([np.nansum(spatial), np.nansum(speed), np.nansum(hd), \
- np.nansum(spatial_speed), np.nansum(spatial_hd), np.nansum(speed_hd), \
- np.nansum(spatial_speed_hd)], \
- labels=['Position','Speed','HD','Position x Speed', 'Position x HD', 'Speed x HD', 'Position x Speed x HD'])
- ax[3].pie([np.nansum(spatial_aperiodic), \
- np.nansum(grid), \
- np.nansum(border)], \
- labels=['Spatial Aperiodic', 'Grid', 'Border'])
- f.savefig(join(figure_path,'cell_types_pie_chart.pdf'), format='pdf')
- # %%
- # representative plots of spatial variable coding
- # pick a session
- row = sessions.iloc[17]
- print(row['File'])
- position = Position(name=join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- if ("2023_spring" in row['Base_Directory']) or ("2024_winter" in row['Base_Directory']):
- if (row['Animal']=='Lamarr') and (int(row['Session'][-2:])>=8):
- mec_spikes = Spikes(name=join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- else:
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec1_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- MEC_channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- mec_spikes.subset_by_channel(MEC_channels)
- else:
- mec_spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1_3',
- row['File']+'_imec0_spikes.txt'))
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- mec_spikes.subset_by_channel(channels)
- sess = "BaggySweatpants_DY08"
- # spatial firing
- unit = 67
- #[ 0, 136, 149] #[ 63, 67, 76, 95, 111, 163] #[70, 72, 43, 44, 46, 48, 54, 89, 27, 94]
- #0, 2, 8, 117, 125, 136, 141, 149, 156, 180
- fr_map, xbins, ybins, max_fr = calc_fr_map(mec_spikes.spikes[unit], position, bin_cm, smooth=True)
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,sess+'_grid_example.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- print(max_fr)
- unit = 46
- #28, 33, 63, 67, 76, 93, 95, 99, 100, 108, 111, 123, 130, 139, 147, 164, 169, 173, 179
- fr_map, xbins, ybins, max_fr = calc_fr_map(mec_spikes.spikes[unit], position, bin_cm, smooth=True)
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,sess+'_border_example.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- print(max_fr)
- unit = 94
- #[ 11, 140, 142, 14, 22, 153, 26, 27, 25, 29, 161, 38, 43, 44, 45, 46, 48, 52, 54, 55, 58, 64, 70, 72, 78, 89, 91, 94, 107, 115]
- fr_map, xbins, ybins, max_fr = calc_fr_map(mec_spikes.spikes[unit], position, bin_cm, smooth=True)
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,sess+'_spatial_aperiodic_example.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- print(max_fr)
- # stability
- fr = bin_spikes(mec_spikes.spikes[unit], position.position.Timestamp)
- n_samps = len(fr)
- split_idx = int(n_samps/2)
- first_half_pos = deepcopy(position)
- first_half_pos.position = first_half_pos.position.iloc[:split_idx]
- second_half_pos = deepcopy(position)
- second_half_pos.position = second_half_pos.position.iloc[split_idx:]
- fr_map, xbins, ybins, max_fr = calc_fr_map(fr[:split_idx], first_half_pos, bin_cm, smooth=True, spikes_are_binned=True)
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,sess+'_spatial_aperiodic_example_first_half.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- fr_map, xbins, ybins, max_fr = calc_fr_map(fr[split_idx:], second_half_pos, bin_cm, smooth=True, spikes_are_binned=True)
- f = plot_heatmap(fr_map, xbins, ybins)
- f.savefig(join(figure_path,sess+'_spatial_aperiodic_example_second_half.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # speed
- unit = 29 #[ 12, 29, 30, 48, 50, 53, 69, 72, 87, 98, 103, 126, 133, 137, 144, 146, 148, 161, 166, 171, 182, 192]
- fr = bin_spikes(mec_spikes.spikes[unit], position.position.Timestamp)*60
- bins = np.arange(0,100,5)
- fr_by_speed = pd.DataFrame({'FR': fr, 'Speed': pd.cut(position.position.Velocity, bins=bins)})
- fr_by_speed_mean = fr_by_speed.groupby(['Speed']).mean().reset_index()
- fr_by_speed_sem = fr_by_speed.groupby(['Speed']).sem().reset_index()
- f, ax = plt.subplots()
- ax.plot(bins[:-1], fr_by_speed_mean.FR)
- ax.fill_between(bins[:-1], fr_by_speed_mean.FR - fr_by_speed_sem.FR, fr_by_speed_mean.FR + fr_by_speed_sem.FR, \
- color='grey', alpha=0.5, rasterized=True)
- ax.set(xlim=[0,50])
- f.savefig(join(figure_path,sess+'_speed_example.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # HD
- unit = 32 #[ 10, 11, 14, 16, 19, 20, 22, 24, 26, 28, 32, 47, 49,
- #53, 55, 62, 65, 66, 79, 90, 103, 107, 111, 121, 130, 139,
- #150, 156, 164, 167, 175, 193, 194, 197]
- fr = bin_spikes(mec_spikes.spikes[unit], position.position.Timestamp)*60
- bins = np.linspace(-1*math.pi,math.pi,18)
- fr_by_hd = pd.DataFrame({'FR': fr, 'HD': pd.cut(position.position.HD, bins=bins)})
- fr_by_hd_mean = fr_by_hd.groupby(['HD']).mean().reset_index()
- fr_by_hd_sem = fr_by_hd.groupby(['HD']).sem().reset_index()
- means = np.append(fr_by_hd_mean.FR,fr_by_hd_mean.FR[0])
- sems = np.append(fr_by_hd_sem.FR,fr_by_hd_sem.FR[0])
- f, ax = plt.subplots(subplot_kw={'projection': 'polar'})
- ax.plot(bins, means)
- ax.fill_between(bins, means - sems, means + sems, \
- color='grey', alpha=0.5, rasterized=True)
- f.savefig(join(figure_path,sess+'_HD_example.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # %% [markdown]
- # ### Reward coding
- # %%
- # find cells whose firing rates are significantly increased at every reward location
- sessions = pd.read_csv('//oak-smb-giocomo.stanford.edu/groups/giocomo/emijones/WT_Sequences/all_sessions_Xmaze.csv')
- n_shuffles = 1000
- n_sessions = 20
- n_animals = len(animal_dict)
- all_rewards = np.full((n_animals, n_sessions), np.NaN)
- reward_increase = np.full((n_animals, n_sessions), np.NaN)
- all_rewards_list = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- reward_increase_list = [[[] for _ in range(n_sessions)] for _ in range(n_animals)]
- for _, row in sessions.iterrows():
- sess_idx = int(row['Session'][-2:])-1
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and sess_idx<=10:
- # load spikes
- binned_data = Binned_Data(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Binned_Data',
- row['File']+'_MEC_binned_data.txt'))
- position = Position(join(row['Base_Directory'], 'Preprocessed_Data/Position',
- row['File']+'_position.txt'))
- task = DoubleYMazeTask(join(row['Base_Directory'], 'Preprocessed_Data/Task',
- row['File']+'_task.txt'))
- hd_shift = position.position.HD+math.pi
- animal_idx = animal_dict[row['Animal']]
- # calculate reward FR for each cell at each rewarded position
- # set start and end indices and reward locations for later shuffles
- # loop over reward visits
- true_fr_by_loc = np.zeros((binned_data.spikes.shape[0],4))
- true_fr_rew_delta = np.zeros(binned_data.spikes.shape[0])
- reward_location, reward_start_idx, reward_end_idx = [np.zeros(len(task.trials), dtype=int) for _ in range(3)]
- num_spikes_by_loc = np.zeros((binned_data.spikes.shape[0],4))
- reward_dur_by_loc = np.zeros(4)
- num_spikes_rew_or_not = np.zeros((binned_data.spikes.shape[0],2))
- reward_dur_rew_or_not = np.zeros(2)
- for t, trial in task.trials.iterrows():
- # find timepoints of first entering poke + turning around to leave poke
- reward_start_idx[t] = np.argmin(np.abs(position.position.Timestamp-trial.Start))
- # if recording ended before mouse left reward, take last index
- if (np.where(np.abs(hd_shift[reward_start_idx[t]:]-hd_shift[reward_start_idx[t]])>math.pi/2)[0]).size==0:
- reward_end_idx[t] = len(hd_shift)-1
- else:
- reward_end_idx[t] = np.where(np.abs(hd_shift[reward_start_idx[t]:]-hd_shift[reward_start_idx[t]])>math.pi/2)[0][0] + reward_start_idx[t]
- # which reward location
- # TL, BL, TR, BR
- if (trial['Inbound/Outbound']=='Outbound') and (trial['Trajectory']=='Top'):
- reward_location[t] = 0
- elif (trial['Inbound/Outbound']=='Outbound') and (trial['Trajectory']=='Bottom'):
- reward_location[t] = 1
- elif (trial['Inbound/Outbound']=='Inbound') and (trial['Trajectory']=='Top'):
- reward_location[t] = 2
- else:
- reward_location[t] = 3
- num_spikes_by_loc[:, reward_location[t]] += np.sum(binned_data.spikes[:, reward_start_idx[t]:reward_end_idx[t]], axis=1)
- reward_dur_by_loc[reward_location[t]] += position.position.Timestamp[reward_end_idx[t]] - position.position.Timestamp[reward_start_idx[t]]
- # choice reward, which could be rewarded or not
- if (reward_location[t]==2) or (reward_location[t]==3):
- if trial['Correct']:
- num_spikes_rew_or_not[:,0] += num_spikes_by_loc[:, reward_location[t]]
- reward_dur_rew_or_not[0] += reward_dur_by_loc[reward_location[t]]
- else:
- num_spikes_rew_or_not[:,1] += num_spikes_by_loc[:, reward_location[t]]
- reward_dur_rew_or_not[1] += reward_dur_by_loc[reward_location[t]]
- for r in range(4):
- true_fr_by_loc[:,r] = num_spikes_by_loc[:,r]/reward_dur_by_loc[r]
- true_fr_rew_delta = num_spikes_rew_or_not[:,0]/reward_dur_rew_or_not[0] - num_spikes_rew_or_not[:,1]/reward_dur_rew_or_not[1]
- # loop over shuffles
- shuffled_fr_list_by_loc = np.zeros((n_shuffles, binned_data.spikes.shape[0], 4))
- shuffled_fr_list_rew_delta = np.zeros((n_shuffles, binned_data.spikes.shape[0]))
- for s in range(n_shuffles):
- # shuffle each cell separately
- shuffled_spikes = binned_data.spikes[:, np.random.permutation(binned_data.spikes.shape[1])]
- # calculate shuffled fr during rewards
- num_spikes_by_loc = np.zeros((binned_data.spikes.shape[0],4))
- reward_dur_by_loc = np.zeros(4)
- num_spikes_rew_or_not = np.zeros((binned_data.spikes.shape[0],2))
- reward_dur_rew_or_not = np.zeros(2)
- for t, trial in task.trials.iterrows():
- num_spikes_by_loc[:, reward_location[t]] += np.sum(shuffled_spikes[:, reward_start_idx[t]:reward_end_idx[t]], axis=1)
- reward_dur_by_loc[reward_location[t]] += position.position.Timestamp[reward_end_idx[t]] - position.position.Timestamp[reward_start_idx[t]]
- # choice reward, which could be rewarded or not
- if (reward_location[t]==2) or (reward_location[t]==3):
- if trial['Correct']:
- num_spikes_rew_or_not[:,0] += num_spikes_by_loc[:, reward_location[t]]
- reward_dur_rew_or_not[0] += reward_dur_by_loc[reward_location[t]]
- else:
- num_spikes_rew_or_not[:,1] += num_spikes_by_loc[:, reward_location[t]]
- reward_dur_rew_or_not[1] += reward_dur_by_loc[reward_location[t]]
- # append to shuffle distribution
- for r in range(4):
- shuffled_fr_list_by_loc[s,:,r] = num_spikes_by_loc[:,r]/reward_dur_by_loc[r]
- shuffled_fr_list_rew_delta[s,:] = num_spikes_rew_or_not[:,0]/reward_dur_rew_or_not[0] - num_spikes_rew_or_not[:,1]/reward_dur_rew_or_not[1]
- # calculate 95th percentile
- fr_95_percentile_by_loc = np.zeros((binned_data.spikes.shape[0],4))
- fr_95_percentile_rew_delta = np.zeros((binned_data.spikes.shape[0]))
- for r in range(4):
- fr_95_percentile_by_loc[:,r] = np.percentile(shuffled_fr_list_by_loc[:,:,r], 95, axis=0)
- fr_95_percentile_rew_delta = np.percentile(shuffled_fr_list_rew_delta, 95, axis=0)
- # count how many cells are above this threshold for all 4 rewards or delta FR (rewarded vs not)
- all_rewards[animal_idx, sess_idx] = np.nanmean((true_fr_by_loc[:,0]>fr_95_percentile_by_loc[:,0]) &
- (true_fr_by_loc[:,1]>fr_95_percentile_by_loc[:,1]) &
- (true_fr_by_loc[:,2]>fr_95_percentile_by_loc[:,2]) &
- (true_fr_by_loc[:,3]>fr_95_percentile_by_loc[:,3]))
- all_rewards_list[animal_idx][sess_idx] = np.where((true_fr_by_loc[:,0]>fr_95_percentile_by_loc[:,0]) &
- (true_fr_by_loc[:,1]>fr_95_percentile_by_loc[:,1]) &
- (true_fr_by_loc[:,2]>fr_95_percentile_by_loc[:,2]) &
- (true_fr_by_loc[:,3]>fr_95_percentile_by_loc[:,3]))[0].tolist()
- reward_increase[animal_idx][sess_idx] = np.nanmean(true_fr_rew_delta>fr_95_percentile_rew_delta)
- reward_increase_list[animal_idx][sess_idx] = np.where(true_fr_rew_delta>fr_95_percentile_rew_delta)[0].tolist()
- print(row['File'])
- # %%
- with open(join(figure_path,'all_rewards.pkl'), 'wb') as file:
- pickle.dump(all_rewards, file)
- with open(join(figure_path,'all_rewards_list.pkl'), 'wb') as file:
- pickle.dump(all_rewards_list, file)
- with open(join(figure_path,'reward_increase.pkl'), 'wb') as file:
- pickle.dump(reward_increase, file)
- with open(join(figure_path,'reward_increase_list.pkl'), 'wb') as file:
- pickle.dump(reward_increase_list, file)
- # %%
- print(f"{np.nanmean(all_rewards)*100:.02f} +/- {stats.sem(np.nanmean(all_rewards,axis=1))*100:.02f}" +\
- f"% of cells have > 95th percentile of shuffled FR during all rewards,\n" +\
- f"and {np.nanmean(reward_increase)*100:.02f} +/- {stats.sem(np.nanmean(reward_increase,axis=1))*100:.02f}" +\
- f"% of cells have > 95th percentile of shuffled increase in FR during reward consumption vs no reward.")
- # %%
- with open(join(figure_path,'over_fr_list.pkl'), 'rb') as file:
- over_fr_list = pickle.load(file)
- # %%
- # are preferentially recruited cells more likely to be reward coding?
- n_sessions = 10
- reward_enriched, reward_inc_enriched, reward_unenriched, reward_inc_unenriched = \
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(4)]
- for animal_idx in range(n_animals):
- for sess_idx in range(n_sessions):
- # what proportion of recruited cells are reward coding
- # number of reward coding cells in enriched list divided by number of total cells in enriched list
- reward_enriched[animal_idx][sess_idx] = len(np.intersect1d(over_fr_list[animal_idx][sess_idx], all_rewards_list[animal_idx][sess_idx]))/ \
- len(over_fr_list[animal_idx][sess_idx]) if len(over_fr_list[animal_idx][sess_idx])>0 else np.NaN
- reward_inc_enriched[animal_idx][sess_idx] = len(np.intersect1d(over_fr_list[animal_idx][sess_idx], reward_increase_list[animal_idx][sess_idx]))/ \
- len(over_fr_list[animal_idx][sess_idx]) if len(over_fr_list[animal_idx][sess_idx])>0 else np.NaN
- # what proportion of non-recruited cells are reward coding
- # number of reward coding cells not in enriched list divided by number of total cells not in enriched list
- reward_unenriched[animal_idx][sess_idx] = np.sum(~np.isin(all_rewards_list[animal_idx][sess_idx], over_fr_list[animal_idx][sess_idx]))/ \
- (len(all_rewards_list[animal_idx][sess_idx])/all_rewards[animal_idx][sess_idx]) if len(over_fr_list[animal_idx][sess_idx])>0 else np.NaN
- reward_inc_unenriched[animal_idx][sess_idx] = np.sum(~np.isin(reward_increase_list[animal_idx][sess_idx], over_fr_list[animal_idx][sess_idx]))/ \
- (len(all_rewards_list[animal_idx][sess_idx])/all_rewards[animal_idx][sess_idx]) if len(over_fr_list[animal_idx][sess_idx])>0 else np.NaN
- # %%
- # compare
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Reward_enriched': reward_enriched.flatten()*100,
- 'Reward_unenriched': reward_unenriched.flatten()*100,
- 'Reward_inc_enriched': reward_inc_enriched.flatten()*100,
- 'Reward_inc_unenriched': reward_inc_unenriched.flatten()*100})
- plot_compare_paired_metrics('Reward_enriched', 'Reward_unenriched', data_by_session, \
- figure_path, 'percent_rew_coding_recruited_vs_not', '% of Cells that Represent Reward', [0,100])
- plot_compare_paired_metrics('Reward_inc_enriched', 'Reward_inc_unenriched', data_by_session, \
- figure_path, 'percent_rew_inc_recruited_vs_not', '% of Cells that Represent Reward Consumption', [0,100])
- # %% [markdown]
- # # Figure S5
- # %% [markdown]
- # ### Decode with SWR trace
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze.csv')
- row = sessions.iloc[156] #64
- print(row['File'])
- seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- CA1_seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_CA1_immobility_sequences.txt'),
- load_objects=True)
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_SWR_intervals.txt'))
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP',
- row['File']+'_CA1_SWR_channel_lfp.txt'))
- ripple_trace = lf.bandpass_filter(lfp.lfp, lfp.rate, lf.RIPPLE[0], lf.RIPPLE[1], lf.RIPPLE[2])
- #seq.stats[seq.stats['Non_local'] & (seq.stats['Duration']<5)]
- #SWR_intervals.intervals
- # %%
- # plot decode
- idx = 108
- seq.plot_sequence(indices=[idx], figure_path=f"{figure_path}/Payne_DY02_MEC")
- CA1_seq.plot_sequence(indices=[idx], figure_path=f"{figure_path}/Payne_DY02_CA1")
- # plot SWR trace
- f, ax = plt.subplots(figsize=(6.3, 3))
- ax.plot(lfp.timestamps, ripple_trace)
- ax.set(xlabel='Time (s)', ylabel='Amplitude')
- # label SWRs
- for ripple in SWR_intervals.intervals.itertuples():
- ax.axvspan(ripple.start_time, ripple.end_time, alpha=0.3, zorder=2)
- # display only overlap with sequence
- start_time = seq.intervals.intervals['start_time'].iloc[idx]
- end_time = seq.intervals.intervals['end_time'].iloc[idx]
- ax.set(xlim=[start_time, end_time])
- f.savefig(join(figure_path,'Payne_DY02_SWR_example_ripple_trace_immobinterval108.pdf'), format='pdf')
- # %% [markdown]
- # ### % of nonlocal coding overlapping with SWRs and vice versa
- # SWRs are not enriched during nonlocal coding. Nonlocal coding is equally likely to occur during an SWR as it is during an immobility bout. SWRs only overlap with a small fraction of nonlocal content.
- # %%
- # averaged over sessions
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- ripple_overlap = np.zeros((n_animals, n_sessions))
- ripple_time = np.full((n_animals, n_sessions), np.NaN)
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # load intervals
- nonlocal_immobility_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- immobility_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_immobility_intervals.txt'))
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_SWR_intervals.txt'))
- # iterate over nonlocal intervals, then SWRs
- for nl_immob in nonlocal_immobility_intervals.intervals.itertuples():
- # find overlaps
- for ripple in SWR_intervals.intervals.itertuples():
- if ripple.start_time<nl_immob.end_time and ripple.end_time>nl_immob.start_time:
- if ripple.start_time<=nl_immob.start_time:
- ripple_overlap[animal_idx,sess_idx] += ripple.end_time-nl_immob.start_time
- elif ripple.end_time<=nl_immob.end_time:
- ripple_overlap[animal_idx,sess_idx] += ripple.end_time-ripple.start_time
- else:
- ripple_overlap[animal_idx,sess_idx] += nl_immob.end_time-ripple.start_time
- elif ripple.end_time>end_time:
- break
- ripple_overlap[animal_idx,sess_idx] /= np.sum(nonlocal_immobility_intervals.intervals.end_time -\
- nonlocal_immobility_intervals.intervals.start_time)
- ripple_time[animal_idx,sess_idx] = (np.sum(SWR_intervals.intervals.end_time - SWR_intervals.intervals.start_time))/ \
- (np.sum(immobility_intervals.intervals.end_time -\
- immobility_intervals.intervals.start_time))
- # remove sessions that don't have SWRs (e.g. no CA1 data)
- ripple_overlap = np.where(ripple_overlap==0, np.nan, ripple_overlap)
- ripple_overlap *= 100
- ripple_time *=100
- # %%
- print(f"{np.nanmean(np.nanmean(SWR_data_by_session['non_local'])):.02f} +/- {stats.sem(np.nanmean(SWR_data_by_session['non_local'],axis=1), nan_policy='omit'):.02f}" +\
- f"% of SWRs have nonlocal coding in MEC,\n" +\
- f"and {np.nanmean(np.nanmean(ripple_overlap)):.02f} +/- {stats.sem(np.nanmean(ripple_overlap,axis=1), nan_policy='omit'):.02f}" +\
- f"% of nonlocal decoded time overlaps with SWRs, \n" +\
- f"and {np.nanmean(np.nanmean(ripple_time)):.02f} +/- {stats.sem(np.nanmean(ripple_time,axis=1), nan_policy='omit'):.02f}" +\
- f"% of time during immobility is spent having SWRs.")
- # %%
- # plot
- plot_seq_metrics_over_sessions(n_animals, ripple_overlap, figure_path,
- 'nl_overlap_with_swr', '% NonLocal Decode Overlapping with SWRs', [0,100])
- plot_seq_metrics_over_sessions(n_animals, SWR_data_by_session['non_local'], figure_path,
- 'swr_overlap_with_nl', '% SWRs with NonLocal Decode', [0,100])
- # %% [markdown]
- # ### compare to shuffle: % nonlocal coding overlapping with SWRs and vice versa
- # %%
- n_shuffles = 1000
- rng = np.random.default_rng()
- n_sessions = 20
- n_animals = len(animal_dict)
- nonlocal_contain_SWRs_5, nonlocal_contain_SWRs_95, nonlocal_contain_SWRs_median, \
- SWRs_contain_nonlocal_5, SWRs_contain_nonlocal_95, SWRs_contain_nonlocal_median =\
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(6)]
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- dist = seq.calc_dist_from_decode()
- ts = seq.binned_data.timestamps
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_SWR_intervals.txt'))
- # 1000 shuffles
- perc_SWRs_contain_nonlocal = np.zeros(1000)
- perc_nonlocal_contain_SWRs = np.zeros(1000)
- for b in range(n_shuffles):
- ts_nonlocal = np.array([])
- for ripple in SWR_intervals.indices.itertuples():
- # pick a random immobility interval
- seq_idx = int(rng.random()*len(seq.stats))
- selected_interval = seq.intervals.indices.iloc[seq_idx]
- # pick a random time within that interval of the same duration as the SWR
- SWR_idx_len = ripple.end_index-ripple.start_index
- index_range = selected_interval.end_index-selected_interval.start_index-SWR_idx_len
- shuffled_start_idx = int(rng.random()*index_range)
- ts_subset = ts[shuffled_start_idx:shuffled_start_idx+SWR_idx_len]
- is_nonlocal = dist[shuffled_start_idx:shuffled_start_idx+SWR_idx_len]>20
- count_nonlocal = np.nansum(is_nonlocal)
- ts_nonlocal = np.concatenate((ts_nonlocal, ts_subset[is_nonlocal]))
- if count_nonlocal>0:
- perc_SWRs_contain_nonlocal[b] += 1
- perc_nonlocal_contain_SWRs[b] = len(ts_nonlocal) #len(np.unique(ts_nonlocal))
- perc_SWRs_contain_nonlocal = perc_SWRs_contain_nonlocal/len(SWR_intervals.intervals) * 100
- perc_nonlocal_contain_SWRs = perc_nonlocal_contain_SWRs / \
- (np.sum(nonlocal_immobility_intervals.indices.end_index -\
- nonlocal_immobility_intervals.indices.start_index)) * 100
- SWRs_contain_nonlocal_5[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 5)
- SWRs_contain_nonlocal_95[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 95)
- SWRs_contain_nonlocal_median[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 50)
- nonlocal_contain_SWRs_5[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 5)
- nonlocal_contain_SWRs_95[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 95)
- nonlocal_contain_SWRs_median[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 50)
- # %%
- # % NonLocal Decode Overlapping with SWRs
- n_nonnan = np.count_nonzero(~np.isnan(ripple_overlap))
- n_more_than_95 = np.nansum(nonlocal_contain_SWRs_95 < ripple_overlap)
- print(f"{n_more_than_95} of {n_nonnan} sessions ({n_more_than_95/n_nonnan*100:0.2f}%) had SWRs during non-local content than if SWRs were randomly allocated across immobility.")
- # % SWRs with NonLocal Decode
- n_more_than_95 = np.nansum(SWRs_contain_nonlocal_95 < SWR_data_by_session['non_local'])
- n_nonnan = np.count_nonzero(~np.isnan(SWR_data_by_session['non_local']))
- print(f"{n_more_than_95} of {n_nonnan} sessions ({n_more_than_95/n_nonnan*100:0.2f}%) had more non-local content during SWRs than if SWRs were randomly allocated across immobility.")
- # %%
- f, ax = plt.subplots(1, figsize=(4,4))
- sns.kdeplot(nonlocal_contain_SWRs_95.flatten(), bw_adjust=0.75, color='red')
- ax.set(xlabel='% SWRs with NonLocal Decode', ylabel='Proportion', xlim=[0,100])
- f.savefig(join(figure_path,'swr_overlap_with_nl_over_events_shuffle.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- f, ax = plt.subplots(1, figsize=(4,4))
- sns.kdeplot(SWRs_contain_nonlocal_95.flatten(), bw_adjust=0.75, color='red')
- ax.set(xlabel='% NonLocal Decode Overlapping with SWRs', ylabel='Proportion', xlim=[0,100])
- f.savefig(join(figure_path,'nl_overlap_with_swr_over_events_shuffle.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # %% [markdown]
- # ### SWR rate during immobility intervals with any nonlocal content vs only local content
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- animal = []
- session = []
- ripple_rate = []
- seq_stats = None
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # load intervals
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'))
- intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_immobility_intervals.txt'))
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_SWR_intervals.txt'))
- ripple_rate_session = np.zeros(len(seq.stats))
- # iterate over nonlocal intervals, then SWRs
- if len(SWR_intervals.intervals>0):
- for nl in range(len(seq.stats)):
- # find overlaps
- for ripple in SWR_intervals.intervals.itertuples():
- if ripple.start_time<intervals.intervals.iloc[nl].end_time and \
- ripple.end_time>intervals.intervals.iloc[nl].start_time:
- ripple_rate_session[nl] +=1
- elif ripple.end_time>end_time:
- break
- ripple_rate_session[nl] /= seq.stats.Duration.iloc[nl]
- # build arrays over all sequences
- animal_idx = animal_dict[row['Animal']]
- animal.extend([animal_idx] * len(seq.stats))
- session_idx = int(row['Session'][-2:])-1
- session.extend([session_idx] * len(seq.stats))
- ripple_rate.extend(ripple_rate_session)
- if seq_stats is not None:
- seq_stats = pd.concat([seq_stats, seq.stats], axis=0, ignore_index=True)
- else:
- seq_stats = seq.stats
- # build full df
- ripple_rate_by_seq = pd.DataFrame({'Animal': animal, 'Session': session, 'SWR_rate': ripple_rate})
- ripple_rate_by_seq = pd.concat([ripple_rate_by_seq, seq_stats], axis=1)
- # %%
- plot_seq_metrics_comparison_over_events(ripple_rate_by_seq, 'SWR_rate', 'Non_local',
- figure_path, 'local_vs_nonlocal_SWR_rate', 'SWR rate (Hz)', [0,4])
- # %% [markdown]
- # ### Distance between decoded positions in MEC and CA1 during SWRs
- # %%
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- n_shuffles = 1000
- start_time = time.time()
- loc_dist, loc_dist_vs_shuffle = \
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(2)]
- # subset data
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- # load seq objects (any seq, we're just using its objects)
- MEC_seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_SWR_sequences.txt'),
- load_objects=True)
- CA1_seq = Sequences(join(row['Base_Directory'], 'Preprocessed_Data/Sequences',
- row['File']+'_CA1_SWR_sequences.txt'),
- load_objects=True)
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # collect all CA1 decoded positions for shuffling
- all_SWR_CA1_decoded_pos = np.array([])
- for i, interval in CA1_seq.intervals.intervals.iterrows():
- cr = CA1_seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- all_SWR_CA1_decoded_pos = np.append(all_SWR_CA1_decoded_pos, cr.sum("state").acausal_posterior.argmax("position").values)
- # calculate distance between decoded positions during each interval
- loc_dist_by_seq, loc_dist_by_seq_sig = \
- [np.full(len(CA1_seq.intervals.intervals), np.NaN) for _ in range(2)]
- n_samps = len(all_SWR_CA1_decoded_pos)
- for i, interval in CA1_seq.intervals.intervals.iterrows():
- cr = MEC_seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- MEC_decoded_pos = cr.sum("state").acausal_posterior.argmax("position").values
- cr = CA1_seq.classifier.classifier_results.sel(time=slice(interval.start_time, interval.end_time))
- CA1_decoded_pos = cr.sum("state").acausal_posterior.argmax("position").values
- loc_dist_by_seq[i] = np.nanmean(np.abs(MEC_decoded_pos-CA1_decoded_pos))
- # circularly shuffle decoded positions
- loc_dist_shuffle = np.full(n_shuffles, np.NaN)
- for s in range(n_shuffles):
- CA1_decoded_pos_shuffle = np.roll(all_SWR_CA1_decoded_pos, np.random.randint(n_samps))
- loc_dist_shuffle[s] = np.nanmean(np.abs(MEC_decoded_pos-CA1_decoded_pos_shuffle[0:len(MEC_decoded_pos)]))
- loc_dist_by_seq_sig[i] = np.nanmean(loc_dist_by_seq[i]<loc_dist_shuffle)
- loc_dist[animal_idx][sess_idx] = np.nanmean(loc_dist_by_seq)
- loc_dist_vs_shuffle[animal_idx][sess_idx] = np.nanmean(loc_dist_by_seq_sig<0.05)
- print(f"{row['File']} {time.time()-start_time}")
- # %%
- with open(join(figure_path,'SWR_loc_dist.pkl'), 'wb') as file:
- pickle.dump(loc_dist, file)
- with open(join(figure_path,'SWR_loc_dist_vs_shuffle.pkl'), 'wb') as file:
- pickle.dump(loc_dist_vs_shuffle, file)
- # %%
- # plot: KDE of distance between decodes
- printf(f"Decodes in MEC and CA1 were {np.nanmean(loc_dist):.02f} +/- {stats.sem(np.nanmean(loc_dist,axis=1), nan_policy='omit'):.02f}cm apart from each other during SWRs, " +\
- f"and {np.nanmean(loc_dist_vs_shuffle)*100:.02f} +/- {stats.sem(np.nanmean(loc_dist_vs_shuffle,axis=1), nan_policy='omit'):.02f}% " +\
- "of SWRs had distances below shuffle.")
- plot_seq_metrics_over_sessions(n_animals, loc_dist, figure_path,
- 'MEC_vs_CA1_decode_dist_during_SWRs', 'Distance between MEC and CA1 Decoded Positions (cm)', [0,130])
- plot_seq_metrics_over_sessions(n_animals, loc_dist_vs_shuffle*100, figure_path,
- 'MEC_vs_CA1_decode_dist_during_SWRs', 'Percent of Distances < 95th Percentile', [0,100])
- # %% [markdown]
- # # Figure S6
- # %% [markdown]
- # ### Repeat with HSEs
- # %%
- HSE_data_by_session, HSE_data_by_seq = combine_metrics_over_sessions(sessions, animal_dict, 'CA1_HSE')
- # %%
- # averaged over sessions
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- hse_overlap = np.zeros((n_animals, n_sessions))
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # load intervals
- nonlocal_immobility_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- HSE_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_HSE_intervals.txt'))
- # iterate over nonlocal intervals, then SWRs
- for nl_immob in nonlocal_immobility_intervals.intervals.itertuples():
- # find overlaps
- for ripple in HSE_intervals.intervals.itertuples():
- if ripple.start_time<nl_immob.end_time and ripple.end_time>nl_immob.start_time:
- if ripple.start_time<=nl_immob.start_time:
- hse_overlap[animal_idx,sess_idx] += ripple.end_time-nl_immob.start_time
- elif ripple.end_time<=nl_immob.end_time:
- hse_overlap[animal_idx,sess_idx] += ripple.end_time-ripple.start_time
- else:
- hse_overlap[animal_idx,sess_idx] += nl_immob.end_time-ripple.start_time
- elif ripple.end_time>end_time:
- break
- hse_overlap[animal_idx,sess_idx] /= np.sum(nonlocal_immobility_intervals.intervals.end_time -\
- nonlocal_immobility_intervals.intervals.start_time)
- # remove sessions that don't have SWRs (e.g. no CA1 data)
- hse_overlap = np.where(hse_overlap==0, np.nan, hse_overlap)
- hse_overlap *= 100
- # %%
- print(f"{np.nanmean(np.nanmean(HSE_data_by_session['non_local'])):.02f} +/- {stats.sem(np.nanmean(HSE_data_by_session['non_local'],axis=1), nan_policy='omit'):.02f}" +\
- f"% of HSEs have nonlocal coding in MEC,\n" +\
- f"and {np.nanmean(np.nanmean(hse_overlap)):.02f} +/- {stats.sem(np.nanmean(hse_overlap,axis=1), nan_policy='omit'):.02f}" +\
- f"% of nonlocal decoded time overlaps with HSEs.")
- # %%
- # plot
- plot_seq_metrics_over_sessions(n_animals, hse_overlap, figure_path,
- 'nl_overlap_with_hse', '% NonLocal Decode Overlapping with HSEs', [0,100])
- plot_seq_metrics_over_sessions(n_animals, HSE_data_by_session['non_local'], figure_path,
- 'hse_overlap_with_nl', '% HSEs with NonLocal Decode', [0,100])
- # %% [markdown]
- # ### compare to shuffle: % nonlocal coding overlapping with HSEs and vice versa
- # %%
- n_shuffles = 1000
- rng = np.random.default_rng()
- n_sessions = 20
- n_animals = len(animal_dict)
- nonlocal_contain_HSEs_5, nonlocal_contain_HSEs_95, nonlocal_contain_HSEs_median, \
- HSEs_contain_nonlocal_5, HSEs_contain_nonlocal_95, HSEs_contain_nonlocal_median =\
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(6)]
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_immobility_sequences.txt'),
- load_objects=True)
- dist = seq.calc_dist_from_decode()
- ts = seq.binned_data.timestamps
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_HSE_intervals.txt'))
- # 1000 shuffles
- perc_SWRs_contain_nonlocal = np.zeros(1000)
- perc_nonlocal_contain_SWRs = np.zeros(1000)
- for b in range(n_shuffles):
- ts_nonlocal = np.array([])
- for ripple in SWR_intervals.indices.itertuples():
- # pick a random immobility interval
- seq_idx = int(rng.random()*len(seq.stats))
- selected_interval = seq.intervals.indices.iloc[seq_idx]
- # pick a random time within that interval of the same duration as the SWR
- SWR_idx_len = ripple.end_index-ripple.start_index
- index_range = selected_interval.end_index-selected_interval.start_index-SWR_idx_len
- shuffled_start_idx = int(rng.random()*index_range)
- ts_subset = ts[shuffled_start_idx:shuffled_start_idx+SWR_idx_len]
- is_nonlocal = dist[shuffled_start_idx:shuffled_start_idx+SWR_idx_len]>20
- count_nonlocal = np.nansum(is_nonlocal)
- ts_nonlocal = np.concatenate((ts_nonlocal, ts_subset[is_nonlocal]))
- if count_nonlocal>0:
- perc_SWRs_contain_nonlocal[b] += 1
- perc_nonlocal_contain_SWRs[b] = len(ts_nonlocal) #len(np.unique(ts_nonlocal))
- perc_SWRs_contain_nonlocal = perc_SWRs_contain_nonlocal/len(SWR_intervals.intervals) * 100
- perc_nonlocal_contain_SWRs = perc_nonlocal_contain_SWRs / \
- (np.sum(nonlocal_immobility_intervals.indices.end_index -\
- nonlocal_immobility_intervals.indices.start_index)) * 100
- HSEs_contain_nonlocal_5[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 5)
- HSEs_contain_nonlocal_95[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 95)
- HSEs_contain_nonlocal_median[animal_idx, sess_idx] = np.percentile(perc_SWRs_contain_nonlocal, 50)
- nonlocal_contain_HSEs_5[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 5)
- nonlocal_contain_HSEs_95[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 95)
- nonlocal_contain_HSEs_median[animal_idx, sess_idx] = np.percentile(perc_nonlocal_contain_SWRs, 50)
- # %%
- # % NonLocal Decode Overlapping with SWRs
- n_nonnan = np.count_nonzero(~np.isnan(hse_overlap))
- n_more_than_95 = np.nansum(nonlocal_contain_HSEs_95 < hse_overlap)
- print(f"{n_more_than_95} of {n_nonnan} sessions ({n_more_than_95/n_nonnan*100:0.2f}%) had HSEs during non-local content than if SWRs were randomly allocated across immobility.")
- # % SWRs with NonLocal Decode
- n_nonnan = np.count_nonzero(~np.isnan(HSE_data_by_session['non_local']))
- n_more_than_95 = np.nansum(HSEs_contain_nonlocal_95 < HSE_data_by_session['non_local'])
- print(f"{n_more_than_95} of {n_nonnan} sessions ({n_more_than_95/n_nonnan*100:0.2f}%) had more non-local content during HSEs than if SWRs were randomly allocated across immobility.")
- # %%
- f, ax = plt.subplots(1, figsize=(4,4))
- sns.kdeplot(nonlocal_contain_HSEs_95.flatten(), bw_adjust=0.75, color='red')
- ax.set(xlabel='% HSEs with NonLocal Decode', ylabel='Proportion', xlim=[0,100])
- f.savefig(join(figure_path,'hse_overlap_with_nl_over_events_shuffle.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- f, ax = plt.subplots(1, figsize=(4,4))
- sns.kdeplot(HSEs_contain_nonlocal_95.flatten(), bw_adjust=0.75, color='red')
- ax.set(xlabel='% NonLocal Decode Overlapping with HSEs', ylabel='Proportion', xlim=[0,100])
- f.savefig(join(figure_path,'nl_overlap_with_hse_over_events_shuffle.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # %% [markdown]
- # ### Non-local content that overlaps with SWRs vs not
- # %%
- sessions = pd.read_csv('Z:/WT_Sequences/all_sessions_Xmaze_CA1.csv')
- animal = []
- session = []
- nl_ripple_overlap = []
- seq_stats = None
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and \
- row['Task'] == 'X Maze' and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # load intervals
- seq = Sequences(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences',
- row['File']+'_MEC_nonlocal_immobility_sequences.txt'))
- intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- SWR_intervals = Sequence_Intervals(join(row['Base_Directory'],
- 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_CA1_SWR_intervals.txt'))
- nl_ripple_overlap_session = np.full(len(seq.stats), False)
- # iterate over nonlocal intervals, then SWRs
- if len(SWR_intervals.intervals>0):
- for nl in range(len(seq.stats)):
- # find overlaps
- for ripple in SWR_intervals.intervals.itertuples():
- if ripple.start_time<intervals.intervals.iloc[nl].end_time and \
- ripple.end_time>intervals.intervals.iloc[nl].start_time:
- nl_ripple_overlap_session[nl] = True
- break
- elif ripple.end_time>end_time:
- break
- # build arrays over all sequences
- animal_idx = animal_dict[row['Animal']]
- animal.extend([animal_idx] * len(seq.stats))
- session_idx = int(row['Session'][-2:])-1
- session.extend([session_idx] * len(seq.stats))
- nl_ripple_overlap.extend(nl_ripple_overlap_session)
- if seq_stats is not None:
- seq_stats = pd.concat([seq_stats, seq.stats], axis=0, ignore_index=True)
- else:
- seq_stats = seq.stats
- # build full df
- ripple_overlap_by_seq = pd.DataFrame({'Animal': animal, 'Session': session, 'Ripple_overlap': nl_ripple_overlap})
- ripple_overlap_by_seq = pd.concat([ripple_overlap_by_seq, seq_stats], axis=1)
- # %%
- # match durations
- ripple_equivalent = []
- yesripple_data_by_seq = ripple_overlap_by_seq.loc[ripple_overlap_by_seq.Ripple_overlap]
- noripple_data_by_seq = ripple_overlap_by_seq.loc[~ripple_overlap_by_seq.Ripple_overlap]
- for a in noripple_data_by_seq.Animal.unique():
- start_idx = np.min(np.where(yesripple_data_by_seq.Animal==a))
- for __, dur in noripple_data_by_seq.loc[noripple_data_by_seq.Animal==a].Duration.items():
- idx = np.abs(yesripple_data_by_seq.loc[yesripple_data_by_seq.Animal==a].Duration - dur).argmin()
- ripple_equivalent.append(start_idx + idx)
- # %%
- nl_ripple_overlap = []
- nl_ripple_overlap.extend([False] * len(noripple_data_by_seq))
- nl_ripple_overlap.extend([True] * len(yesripple_data_by_seq.iloc[ripple_equivalent]))
- ripple_overlap_equivalent_by_seq = pd.concat([noripple_data_by_seq, yesripple_data_by_seq.iloc[ripple_equivalent]], ignore_index=True)
- ripple_overlap_equivalent_by_seq.Ripple_overlap = nl_ripple_overlap
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'FR', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_fr_matched', 'FR (Hz)', [0,50])
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'Percent_units', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_percent_units_matched', '% Active Units', [0,100])
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'Spatial_information', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_spatial_info_matched', 'Spatial information (bit/s)', [0,1.5])
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'Duration', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_duration_matched', 'Duration (s)', [0,1])
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'Max_distance_from_animal', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_lookahead_matched', 'Lookahead distance (cm)', [0,130])
- plot_seq_metrics_comparison_over_events(ripple_overlap_equivalent_by_seq, 'Spatial_coverage_percent', 'Ripple_overlap',
- figure_path, 'Nonlocal_SWR_vs_not_spatial_coverage_matched', '% Spatial coverage', [0,100])
- # %% [markdown]
- # ### SWRs that contain nonlocal content in MEC vs not
- # %%
- # match durations
- nonlocal_SWR_equivalent = []
- local_SWR_data_by_seq = SWR_data_by_seq.loc[~SWR_data_by_seq.Non_local]
- nonlocal_SWR_data_by_seq = SWR_data_by_seq.loc[SWR_data_by_seq.Non_local]
- for a in local_SWR_data_by_seq.Animal.unique():
- start_idx = np.min(np.where(nonlocal_SWR_data_by_seq.Animal==a))
- for __, dur in local_SWR_data_by_seq.loc[local_SWR_data_by_seq.Animal==a].Duration.items():
- idx = np.abs(nonlocal_SWR_data_by_seq.loc[nonlocal_SWR_data_by_seq.Animal==a].Duration - dur).argmin()
- nonlocal_SWR_equivalent.append(start_idx + idx)
- # %%
- non_local = []
- non_local.extend([False] * len(local_SWR_data_by_seq))
- non_local.extend([True] * len(nonlocal_SWR_data_by_seq.iloc[nonlocal_SWR_equivalent]))
- SWR_data_equivalent_by_seq = pd.concat([local_SWR_data_by_seq, nonlocal_SWR_data_by_seq.iloc[nonlocal_SWR_equivalent]], ignore_index=True)
- SWR_data_equivalent_by_seq.Non_local = non_local
- plot_seq_metrics_comparison_over_events(SWR_data_equivalent_by_seq, 'FR', 'Non_local',
- figure_path, 'SWR_local_vs_nonlocal_fr_matched', 'FR (Hz)', [0,50])
- plot_seq_metrics_comparison_over_events(SWR_data_equivalent_by_seq, 'Percent_units', 'Non_local',
- figure_path, 'SWR_local_vs_nonlocal_percent_units_matched', '% Active Units', [0,20])
- plot_seq_metrics_comparison_over_events(SWR_data_equivalent_by_seq, 'Spatial_information', 'Non_local',
- figure_path, 'SWR_local_vs_nonlocal_spatial_info_matched', 'Spatial information (bit/s)', [0,1.5])
- plot_seq_metrics_comparison_over_events(SWR_data_equivalent_by_seq, 'Duration', 'Non_local',
- figure_path, 'SWR_local_vs_nonlocal_duration_matched', 'Duration (s)', [0,0.2])
- plot_seq_metrics_comparison_over_events(SWR_data_equivalent_by_seq, 'Animal_spatial_bin', 'Non_local',
- figure_path, 'SWR_local_vs_nonlocal_animal_location_matched', 'Animal linearized position (cm)', [0,123])
- # %% [markdown]
- # # Figure S6 - part 2
- # %% [markdown]
- # ### example raw & filtered traces
- # %%
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- row = sessions.iloc[243]
- nonlocal_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- local_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_local_immobility_intervals.txt'))
- move_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_movement_intervals.txt'))
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP', row['File']+'_MEC_theta_channel_lfp.txt'))
- lfp_move = deepcopy(lfp)
- lfp_move.subset_by_time(move_intervals.intervals.values)
- lfp_nonlocal = deepcopy(lfp)
- lfp_nonlocal.subset_by_time(nonlocal_intervals.intervals.values)
- lfp_local = deepcopy(lfp)
- lfp_local.subset_by_time(local_intervals.intervals.values)
- # %%
- print(lfp_move.name)
- f, ax = plt.subplots(3)
- high_theta_lfp = lf.bandpass_filter(lfp_local.lfp, low=lf.HIGH_THETA[0], high=lf.HIGH_THETA[1], pass_band=lf.HIGH_THETA[2])
- low_theta_lfp = lf.bandpass_filter(lfp_local.lfp, low=lf.LOW_THETA[0], high=lf.LOW_THETA[1], pass_band=lf.LOW_THETA[2])
- ax[0].plot(low_theta_lfp.squeeze(), color='b')
- ax[0].plot(high_theta_lfp.squeeze(), color='r')
- ax[0].plot(lfp_local.lfp)
- ax[0].set(xlim=[1958,1958+625], ylim=[-150,150])
- high_theta_lfp = lf.bandpass_filter(lfp_nonlocal.lfp, low=lf.HIGH_THETA[0], high=lf.HIGH_THETA[1], pass_band=lf.HIGH_THETA[2])
- low_theta_lfp = lf.bandpass_filter(lfp_nonlocal.lfp, low=lf.LOW_THETA[0], high=lf.LOW_THETA[1], pass_band=lf.LOW_THETA[2])
- ax[1].plot(low_theta_lfp.squeeze(), color='b')
- ax[1].plot(high_theta_lfp.squeeze(), color='r')
- ax[1].plot(lfp_nonlocal.lfp)
- ax[1].set(xlim=[37798,37798+625], ylim=[-150,150])
- high_theta_lfp = lf.bandpass_filter(lfp_move.lfp, low=lf.HIGH_THETA[0], high=lf.HIGH_THETA[1], pass_band=lf.HIGH_THETA[2])
- low_theta_lfp = lf.bandpass_filter(lfp_move.lfp, low=lf.LOW_THETA[0], high=lf.LOW_THETA[1], pass_band=lf.LOW_THETA[2])
- ax[2].plot(low_theta_lfp.squeeze(), color='b')
- ax[2].plot(high_theta_lfp.squeeze(), color='r')
- ax[2].plot(lfp_move.lfp)
- ax[2].set(xlim=[625,2*625], ylim=[-150,150])
- f.savefig(join(figure_path,'TopHat_DY06_theta_traces.pdf'), format='pdf', transparent=True,
- dpi=300, bbox_inches='tight')
- # %% [markdown]
- # ### PSD in theta range
- # %%
- # PSD over movement vs immobiilty times
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- rate = 625
- n_freqs = 129
- immob_psd = np.full((n_animals, n_sessions, n_freqs), np.NaN)
- move_psd = np.full((n_animals, n_sessions, n_freqs), np.NaN)
- start_time = time.time()
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- immob_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_immobility_intervals.txt'))
- move_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_movement_intervals.txt'))
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP', row['File']+'_MEC_theta_channel_lfp.txt'))
- lfp_immob = deepcopy(lfp)
- lfp_immob.subset_by_time(immob_intervals.intervals.values)
- freqs, immob_psd[animal_idx, sess_idx, :] = signal.welch(np.squeeze(lfp_immob.lfp), rate)
- lfp_move = deepcopy(lfp)
- lfp_move.subset_by_time(move_intervals.intervals.values)
- _, move_psd[animal_idx, sess_idx, :] = signal.welch(np.squeeze(lfp_move.lfp), rate)
- print(f"{row['File']} {time.time()-start_time}")
- # %%
- np.save(join(figure_path,'immob_psd.npy'), immob_psd)
- np.save(join(figure_path,'move_psd.npy'), move_psd)
- nonlocal_psd = np.load(join(figure_path,'nonlocal_psd.npy'))
- local_psd = np.load(join(figure_path,'local_psd.npy'))
- for a in range(n_animals):
- for s in range(n_sessions):
- immob_psd[a][s] /= np.nansum(immob_psd[a][s])
- move_psd[a][s] /= np.nansum(move_psd[a][s])
- nonlocal_psd[a][s] /= np.nansum(nonlocal_psd[a][s])
- local_psd[a][s] /= np.nansum(local_psd[a][s])
- freqs = freqs + (freqs[1]-freqs[0])/2 # plot at bin centers, not edges
- # %%
- # sum & plot over sessions
- immob_psd_summed = np.nanmean(immob_psd, axis=1)
- move_psd_summed = np.nanmean(move_psd, axis=1)
- nonlocal_psd_summed = np.nanmean(nonlocal_psd, axis=1)
- local_psd_summed = np.nanmean(local_psd, axis=1)
- # comparison: mean + sem over animals
- f, ax = plt.subplots()
- ax.plot(freqs, np.nanmean(local_psd_summed, axis=0), color='black')
- sem = stats.sem(local_psd_summed, nan_policy='omit')
- ax.fill_between(freqs, np.nanmean(local_psd_summed, axis=0)-sem, \
- np.nanmean(local_psd_summed, axis=0)+sem, color='grey', alpha=0.5, rasterized=True)
- ax.plot(freqs, np.nanmean(nonlocal_psd_summed, axis=0), color='#1C968B')
- sem = stats.sem(nonlocal_psd_summed, nan_policy='omit')
- ax.fill_between(freqs, np.nanmean(nonlocal_psd_summed, axis=0)-sem, \
- np.nanmean(nonlocal_psd_summed, axis=0)+sem, color='#1C968B', alpha=0.5, rasterized=True)
- ax.plot(freqs, np.nanmean(move_psd_summed, axis=0), color='magenta')
- sem = stats.sem(move_psd_summed, nan_policy='omit')
- ax.fill_between(freqs, np.nanmean(move_psd_summed, axis=0)-sem, \
- np.nanmean(move_psd_summed, axis=0)+sem, color='magenta', alpha=0.5, rasterized=True)
- ax.set(xlabel='Frequency', ylabel='PSD')
- f.savefig(join(figure_path,'local_nonlocal_move_psd.pdf'), format='pdf')
- ax.set(xlim=[0,20])
- f.savefig(join(figure_path,'local_nonlocal_move_psd_inset.pdf'), format='pdf')
- # %% [markdown]
- # ### Instantaneous frequency
- # %%
- # inst freq
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- nonlocal_freqs, local_freqs, move_freqs = \
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(3)]
- start_time = time.time()
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- nonlocal_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- local_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_local_immobility_intervals.txt'))
- move_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_movement_intervals.txt'))
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP', row['File']+'_MEC_theta_channel_lfp.txt'))
- lfp_nonlocal = deepcopy(lfp)
- lfp_nonlocal.subset_by_time(nonlocal_intervals.intervals.values)
- _, _, inst_freqs = lf.hilbert_envelope_phase_freq(lf.bandpass_filter(lfp_nonlocal.lfp, low=lf.THETA[0], high=lf.THETA[1], pass_band=lf.THETA[2]))
- inst_freqs = inst_freqs.squeeze()
- nonlocal_freqs[animal_idx, sess_idx] = np.mean(inst_freqs[inst_freqs<20])
- lfp_local = deepcopy(lfp)
- lfp_local.subset_by_time(local_intervals.intervals.values)
- _, _, inst_freqs = lf.hilbert_envelope_phase_freq(lf.bandpass_filter(lfp_local.lfp, low=lf.THETA[0], high=lf.THETA[1], pass_band=lf.THETA[2]))
- inst_freqs = inst_freqs.squeeze()
- local_freqs[animal_idx, sess_idx] = np.mean(inst_freqs[inst_freqs<20])
- lfp_move = deepcopy(lfp)
- lfp_move.subset_by_time(move_intervals.intervals.values)
- _, _, inst_freqs = lf.hilbert_envelope_phase_freq(lf.bandpass_filter(lfp_move.lfp, low=lf.THETA[0], high=lf.THETA[1], pass_band=lf.THETA[2]))
- inst_freqs = inst_freqs.squeeze()
- move_freqs[animal_idx, sess_idx] = np.mean(inst_freqs[inst_freqs<20])
- print(f"{row['File']} {time.time()-start_time}")
- # %%
- delta_freqs = local_freqs - nonlocal_freqs
- print(f"Instantaneous frequency decreases by {np.mean(np.nanmean(delta_freqs, axis=1)):.02f} +/- {stats.sem(np.nanmean(delta_freqs, axis=1)):.02f} Hz")
- print(f"Instantaneous frequencies: {np.mean(np.nanmean(local_freqs, axis=1)):.02f} +/- {stats.sem(np.nanmean(local_freqs, axis=1)):.02f} Hz\n" + \
- f"{np.mean(np.nanmean(nonlocal_freqs, axis=1)):.02f} +/- {stats.sem(np.nanmean(nonlocal_freqs, axis=1)):.02f} Hz\n" + \
- f"{np.mean(np.nanmean(move_freqs, axis=1)):.02f} +/- {stats.sem(np.nanmean(move_freqs, axis=1)):.02f} Hz")
- # %%
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': local_freqs.flatten(),
- 'Feature_nl': nonlocal_freqs.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'theta_inst_freq_l_vs_nl', 'Instantaneous Frequency (Hz)', [6,9])
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': nonlocal_freqs.flatten(),
- 'Feature_nl': move_freqs.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'theta_inst_freq_nl_vs_move', 'Instantaneous Frequency (Hz)', [6,9])
- # %% [markdown]
- # ### Power in theta bands
- # %%
- # Z-score of low and high theta bands
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- window = 0.5
- nl_oldmethod_theta, nl_newmethod_theta, l_oldmethod_theta, l_newmethod_theta = \
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(4)]
- start_time = time.time()
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- nonlocal_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- local_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_local_immobility_intervals.txt'))
- immob_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_immobility_intervals.txt'))
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP', row['File']+'_MEC_theta_channel_lfp.txt'))
- lfp_nonlocal = deepcopy(lfp)
- lfp_nonlocal.subset_by_time(nonlocal_intervals.intervals.values)
- lfp_local = deepcopy(lfp)
- lfp_local.subset_by_time(local_intervals.intervals.values)
- lfp_immob = deepcopy(lfp)
- lfp_immob.subset_by_time(immob_intervals.intervals.values)
- oldmethod_immob_theta, oldmethod_theta_mean = lf.multitaper_filtered_power(lfp_immob.lfp, low=lf.NONLOCAL[0], high=lf.NONLOCAL[1], window=1)
- oldmethod_theta_std = np.nanstd(oldmethod_immob_theta)
- _, nl_oldmethod_theta_power = lf.multitaper_filtered_power(lfp_nonlocal.lfp, low=lf.NONLOCAL[0], high=lf.NONLOCAL[1], window=1)
- nl_oldmethod_theta[animal_idx, sess_idx] = (nl_oldmethod_theta_power-oldmethod_theta_mean)/oldmethod_theta_std
- _, l_oldmethod_theta_power = lf.multitaper_filtered_power(lfp_local.lfp, low=lf.NONLOCAL[0], high=lf.NONLOCAL[1], window=1)
- l_oldmethod_theta[animal_idx, sess_idx] = (l_oldmethod_theta_power-oldmethod_theta_mean)/oldmethod_theta_std
- nl_newmethod_theta_power, l_newmethod_theta_power = \
- [[] for _ in range(2)]
- # subset on intervals that are at least the size of the window
- intervals = nonlocal_intervals.intervals.values
- idx = np.where((intervals[:,1]-intervals[:,0])>window)[0]
- for _, i in enumerate(idx):
- power, _ = lf.multitaper_filtered_power(lfp.lfp[np.where((lfp.timestamps >= intervals[i, 0]) \
- & (lfp.timestamps <= intervals[i, 1]))[0]], \
- low=lf.NONLOCAL[0], high=lf.NONLOCAL[1], window=window)
- nl_newmethod_theta_power.extend(power)
- # repeat for local
- intervals = local_intervals.intervals.values
- idx = np.where((intervals[:,1]-intervals[:,0])>window)[0]
- for _, i in enumerate(idx):
- power, _ = lf.multitaper_filtered_power(lfp.lfp[np.where((lfp.timestamps >= intervals[i, 0]) \
- & (lfp.timestamps <= intervals[i, 1]))[0]], \
- low=lf.NONLOCAL[0], high=lf.NONLOCAL[1], window=window)
- l_newmethod_theta_power.extend(power)
- # z-score and add to per-session calculation
- newmethod_theta_mean = np.mean(nl_newmethod_theta_power+l_newmethod_theta_power)
- newmethod_theta_std = np.std(nl_newmethod_theta_power+l_newmethod_theta_power)
- nl_newmethod_theta[animal_idx, sess_idx] = (np.mean(nl_newmethod_theta_power)-theta_mean)/theta_std
- l_newmethod_theta[animal_idx, sess_idx] = (np.mean(l_newmethod_theta_power)-theta_mean)/theta_std
- print(f"{row['File']} {time.time()-start_time}")
- # %%
- print(f"Type II theta power changes by {np.mean(np.nanmean(nl_oldmethod_theta-l_oldmethod_theta, axis=1)):.02f}" +\
- f" +/- {stats.sem(np.nanmean(nl_oldmethod_theta-l_oldmethod_theta, axis=1)):.04f}")
- print(f"Z-score Power: {np.mean(np.nanmean(l_oldmethod_theta, axis=1)):.02f} +/- {stats.sem(np.nanmean(l_oldmethod_theta, axis=1)):.04f}\n" + \
- f"{np.mean(np.nanmean(nl_oldmethod_theta, axis=1)):.02f} +/- {stats.sem(np.nanmean(nl_oldmethod_theta, axis=1)):.04f}")
- # %%
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': l_oldmethod_theta.flatten(),
- 'Feature_nl': nl_oldmethod_theta.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'low_theta_zscore_l_vs_nl', '3-7 Hz Power (Z-score)', [-1,1])
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': l_newmethod_theta.flatten(),
- 'Feature_nl': nl_newmethod_theta.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'high_theta_zscore_l_vs_nl', '3-7 Hz Power (Z-score)', [-1,1])
- # %% [markdown]
- # ### Spike-field coherence in theta band
- # %%
- # calculate
- sessions = pd.read_csv(r'Z:/WT_Sequences/all_sessions_Xmaze.csv')
- n_sessions = 20
- n_animals = len(animal_dict)
- nl_low_theta_coh, nl_high_theta_coh, l_low_theta_coh, l_high_theta_coh, \
- delta_low_theta_coh, delta_high_theta_coh = \
- [np.full((n_animals, n_sessions), np.NaN) for _ in range(6)]
- start_time = time.time()
- for _, row in sessions.iterrows():
- if not row['Recording_Error'] and not row['Position_Error'] and int(row['Session'][-2:])<=20:
- animal_idx = animal_dict[row['Animal']]
- sess_idx = int(row['Session'][-2:])-1
- # load intervals
- nonlocal_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_nonlocal_immobility_intervals.txt'))
- local_intervals = Sequence_Intervals(join(row['Base_Directory'], 'Preprocessed_Data/Sequences/Intervals',
- row['File']+'_MEC_local_immobility_intervals.txt'))
- # load LFP and subset on intervals
- lfp = LFP(join(row['Base_Directory'], 'Preprocessed_Data/LFP', row['File']+'_MEC_theta_channel_lfp.txt'))
- lfp_nonlocal = deepcopy(lfp)
- lfp_nonlocal.subset_by_time(nonlocal_intervals.intervals.values)
- lfp_local = deepcopy(lfp)
- lfp_local.subset_by_time(local_intervals.intervals.values)
- # load spikes
- if ('2021_pilot' in row['Base_Directory']) or ('2022_winter' in row['Base_Directory']):
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_electrodes.txt'))
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes/g1', row['File']+'_imec0_spikes.txt'))
- channels = electrodes.subset_by_location(regions=['Entorhinal area medial part dorsal zone'])
- else:
- if (row['Animal']=='Lamarr') and (sess_idx>=7):
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec0_electrodes.txt'))
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec0_spikes.txt'))
- else:
- electrodes = Electrodes(join(row['Base_Directory'], 'Preprocessed_Data/Electrodes',
- row['File']+'_imec1_electrodes.txt'))
- spikes = Spikes(join(row['Base_Directory'], 'Preprocessed_Data/Spikes',
- row['File']+'_imec1_spikes.txt'))
- channels = electrodes.subset_by_location(regions=['ENTm1','ENTm2','ENTm3','ENTm4','ENTm5','ENTm6'])
- spikes.subset_by_channel(channels)
- # bin spikes and subset on intervals
- spikes_nonlocal_binned, _ = sp.calc_binned_spikes(spikes.spikes, \
- intervals=np.append(lfp_nonlocal.timestamps, lfp_nonlocal.timestamps[-1]+1/lfp.rate))
- spikes_nonlocal_fr = np.mean(spikes_nonlocal_binned, axis=1)
- spikes_local_binned, _ = sp.calc_binned_spikes(spikes.spikes, \
- intervals=np.append(lfp_local.timestamps, lfp_local.timestamps[-1]+1/lfp.rate))
- spikes_local_fr = np.mean(spikes_local_binned, axis=1)
- nl_low_theta_coh_units, nl_high_theta_coh_units, l_low_theta_coh_units, l_high_theta_coh_units = \
- [np.full(len(spikes.spikes), np.NaN) for _ in range(4)]
- # calculate rate-adjusted coherence per cell
- for u in range(len(spikes.spikes)):
- _, nl_low_theta_coh_units[u] = lf.multitaper_filtered_spike_coherence(spikes_nonlocal_binned[u][:, np.newaxis], lfp_nonlocal.lfp, \
- spikes_nonlocal_fr[u], spikes_local_fr[u], \
- low=lf.LOW_THETA[0], high=lf.LOW_THETA[1], window=1)
- _, nl_high_theta_coh_units[u] = lf.multitaper_filtered_spike_coherence(spikes_nonlocal_binned[u][:, np.newaxis], lfp_nonlocal.lfp, \
- spikes_nonlocal_fr[u], spikes_local_fr[u], \
- low=lf.HIGH_THETA[0], high=lf.HIGH_THETA[1], window=1)
- _, l_low_theta_coh_units[u] = lf.multitaper_filtered_spike_coherence(spikes_local_binned[u][:, np.newaxis], lfp_local.lfp, \
- spikes_local_fr[u], spikes_nonlocal_fr[u], \
- low=lf.LOW_THETA[0], high=lf.LOW_THETA[1], window=1)
- _, l_high_theta_coh_units[u] = lf.multitaper_filtered_spike_coherence(spikes_local_binned[u][:, np.newaxis], lfp_local.lfp, \
- spikes_local_fr[u], spikes_nonlocal_fr[u], \
- low=lf.HIGH_THETA[0], high=lf.HIGH_THETA[1], window=1)
- # average across the session
- nl_low_theta_coh[animal_idx][sess_idx] = np.nanmean(nl_low_theta_coh_units)
- nl_high_theta_coh[animal_idx][sess_idx] = np.nanmean(nl_high_theta_coh_units)
- l_low_theta_coh[animal_idx][sess_idx] = np.nanmean(l_low_theta_coh_units)
- l_high_theta_coh[animal_idx][sess_idx] = np.nanmean(l_high_theta_coh_units)
- delta_low_theta_coh[animal_idx][sess_idx] = np.nanmean(nl_low_theta_coh_units-l_low_theta_coh_units)
- delta_high_theta_coh[animal_idx][sess_idx] = np.nanmean(nl_high_theta_coh_units-l_high_theta_coh_units)
- print(f"{row['File']} {time.time()-start_time}")
- # %%
- print(f"Type II theta coherence changes by {np.mean(np.nanmean(delta_low_theta_coh, axis=1)):.02f} +/- {stats.sem(np.nanmean(delta_low_theta_coh, axis=1)):.04f}")
- print(f"Coherence: {np.mean(np.nanmean(l_low_theta_coh, axis=1)):.02f} +/- {stats.sem(np.nanmean(l_low_theta_coh, axis=1)):.04f}\n" + \
- f"{np.mean(np.nanmean(nl_low_theta_coh, axis=1)):.02f} +/- {stats.sem(np.nanmean(nl_low_theta_coh, axis=1)):.04f}")
- # %%
- # analyze & plot
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': nl_low_theta_coh.flatten(),
- 'Feature_nl': l_low_theta_coh.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'low_theta_spike_field_coh_l_vs_nl', 'Coherence', [0,1])
- data_by_session = pd.DataFrame({'Animal': np.repeat(np.arange(n_animals),n_sessions),
- 'Session': np.tile(np.arange(n_sessions),n_animals),
- 'Feature_l': nl_high_theta_coh.flatten(),
- 'Feature_nl': l_high_theta_coh.flatten()})
- plot_compare_paired_metrics('Feature_l', 'Feature_nl', data_by_session, \
- figure_path, 'high_theta_spike_field_coh_l_vs_nl', 'Coherence', [0,1])
- # %% [markdown]
- # # Figure 4 &
Figures_published_edition.ipynb at commit dfbbde1, under GPL-3.0 · at the source
Overview
- Department of Neurobiology, Stanford University School of Medicine, Stanford, CA USA
- Present Address: Department of Neurobiology, University of Maryland School of Medicine, Baltimore, MD USA
- Present Address: Zuckerman Mind Brain Behavior Institute, Columbia University, New York, NY USA
Abstract
Neurons can collectively represent the current sensory experience during exploration or remote experiences during immobility. Remote representations can reflect learned associations and support learning. Neurons in medial entorhinal cortex (MEC) represent the animal’s current location during movement, but little is known about MEC representations during immobility. We recorded hundreds of neurons simultaneously in MEC and CA1 as mice learned to associate pairs of rewarded locations. During immobility, the MEC neural population frequently represented positions far from the animal’s location (‘nonlocal coding’). Cells with spatial firing fields at remote locations drove nonlocal coding, even as cells representing the current position remained active. While MEC nonlocal coding has been reported during sharp-wave ripples in CA1, we observed nonlocal coding more often outside of ripples and saw less CA1–MEC coordination during nonlocal coding. Further, nonlocal coding preferentially represented remote task-relevant locations at appropriate times. Together, this work suggests that MEC nonlocal coding could strengthen associations between locations independently from CA1.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 19 matches between paragraphs and lines of code.
emilyasterjones/X_maze
b5692c46163cf889a074870ca44af2317f76132e, 24 October 2025Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
4 files
- Capture/
Camera/ , Python, 157 linescapture_video_AlliedVisi on.py - Capture/
Camera/ , Python, 239 linescapture_video_FLIR.py - LICENSE, License, 21 lines
- README.md, Text, 33 lines
petersaj/AP_histology
67d71af75657dbd14bd97604514337f4822b2a98, 23 September 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
33 files
- AP_histology.m, MATLAB, 702 lines
- analysis_functions/
+ap_histology/ , MATLAB, 81 lineshistology_volume.m - gui_functions/
+ap_histology/ , MATLAB, 193 linesalign_auto_histology_atl as.m - gui_functions/
+ap_histology/ , MATLAB, 369 linesalign_manual_histology_a tlas.m - gui_functions/
+ap_histology/ , MATLAB, 229 linesalign_manual_histology_a tlas_v2.m - gui_functions/
+ap_histology/ , MATLAB, 98 linesannotation2ccf.m - gui_functions/
+ap_histology/ , MATLAB, 227 linesannotator.m - gui_functions/
+ap_histology/ , MATLAB, 539 lineschoose_histology_atlas.m - gui_functions/
+ap_histology/ , MATLAB, 3 linesexport_annotated_histolo gy_vector.m - gui_functions/
+ap_histology/ , MATLAB, 52 linesflip_slices.m - gui_functions/
+ap_histology/ , MATLAB, 107 linesgrab_atlas_slice.m - gui_functions/
+ap_histology/ , MATLAB, 113 linesreorder_slices.m - gui_functions/
+ap_histology/ , MATLAB, 64 linesrigid_transform.m - gui_functions/
+ap_histology/ , MATLAB, 59 linesrotate_center_slices.m - gui_functions/
+ap_histology/ , MATLAB, 72 linesset_channel_properties.m - unused_functions/
+ap_histology_unused/ , MATLAB, 195 linesAP_align_probe_histology .m - unused_functions/
+ap_histology_unused/ , MATLAB, 64 linesAP_grab_fullsize_histolo gy_slices.m - unused_functions/
+ap_histology_unused/ , MATLAB, 53 linesAP_histology2ccf.m - unused_functions/
+ap_histology_unused/ , MATLAB, 166 linesAP_view_aligned_histolog y_volume.m - unused_functions/
+ap_histology_unused/ , MATLAB, 404 linesannotate_neuropixels.m - unused_functions/
+ap_histology_unused/ , MATLAB, 91 linesannotate_probes.m - unused_functions/
+ap_histology_unused/ , MATLAB, 90 linesannotate_volume.m - unused_functions/
+ap_histology_unused/ , MATLAB, 124 linesannotation2ccf.m - unused_functions/
+ap_histology_unused/ , MATLAB, 92 linesdemo_histology_pipeline. m - utility_functions/
+ap_histology/ , MATLAB, 37 linesexport_ibl_probe.m - utility_functions/
+ap_histology/ , MATLAB, 81 linesfit_probe_line.m - utility_functions/
+ap_histology/ , MATLAB, 51 linesloadStructureTree.m - utility_functions/
+ap_histology/ , MATLAB, 21 linesload_ccf.m - utility_functions/
+ap_histology/ , MATLAB, 330 linesnatsort.m - utility_functions/
+ap_histology/ , MATLAB, 169 linesnatsortfiles.m - utility_functions/
+ap_histology/ , MATLAB, 23 linesread_image_metadata.m - LICENSE, License, 674 lines
- README.md, Text, 7 lines
emilyasterjones/ecephys_spike_sorting
b6ef3f0de4f16bf1bba2852edab4988d6345c521, 4 June 2024Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
139 files
- .cookiecutter/
update.sh , Shell, 15 lines - .cookiecutter/
update_from_repo.py , Python, 12 lines - .phy/
phy_config.py , Python, 15 lines - .phy/
plugins/ , Python, 51 linesclusterViewStylingPlugin .py - .phy/
plugins/ , Python, 18 linescustom_columns.py - SpikeGLX_Datafile_Tools/
MATLAB/ , MATLAB, 45 linesDemoReadSGLXData.m - SpikeGLX_Datafile_Tools/
MATLAB/ , MATLAB, 436 linesSGLX_readMeta.m - SpikeGLX_Datafile_Tools/
MATLAB/ , MATLAB, 260 linesks25_phy_toBinary.m - SpikeGLX_Datafile_Tools/
Python/ , Python, 1 lineDemoReadSGLXData/ __init__.py - SpikeGLX_Datafile_Tools/
Python/ , Python, 399 linesDemoReadSGLXData/ readSGLX.py - SpikeGLX_Datafile_Tools/
Python/ , Python, 114 linesbuild_fyi_all.py - SpikeGLX_Datafile_Tools/
Python/ , Jupyter, 58 linesread_SGLX_analog.ipynb - SpikeGLX_Datafile_Tools/
Python/ , Jupyter, 60 linesread_SGLX_digital.ipynb - docs/
aibs_sphinx/ , Shell, 8 linesbuildPortalAssets.sh - docs/
aibs_sphinx/ , JavaScript, 1 linestatic/ external_assets/ bundled.js - docs/
aibs_sphinx/ , JavaScript, 292 linesstatic/ external_assets/ javascript/ AC_RunActiveContent.js - docs/
aibs_sphinx/ , JavaScript, 14 linesstatic/ external_assets/ javascript/ appConfig.js - docs/
aibs_sphinx/ , JavaScript, 28 linesstatic/ external_assets/ javascript/ browserVersions.js - docs/
aibs_sphinx/ , JavaScript, 5 linesstatic/ external_assets/ javascript/ relatedData.js - docs/
conf.py , Python, 295 lines - docs/
gallery/ , Python, 21 lineshelloworld.py - ecephys_spike_sorting/
__init__.py , Python, 1 line - ecephys_spike_sorting/
buildAndCheckImro.m , MATLAB, 114 lines - ecephys_spike_sorting/
common/ , Python, 79 linesOEFileInfo.py - ecephys_spike_sorting/
common/ , Python, 698 linesSGLXMetaToCoords.py - ecephys_spike_sorting/
common/ , Python, 1 line__init__.py - ecephys_spike_sorting/
common/ , Python, 84 linesepoch.py - ecephys_spike_sorting/
common/ , Python, 35 linesschemas.py - ecephys_spike_sorting/
common/ , Python, 671 linesutils.py - ecephys_spike_sorting/
common/ , Python, 407 linesvisualization.py - ecephys_spike_sorting/
createChanMapFileFromImr , MATLAB, 44 lineso.m - ecephys_spike_sorting/
modules/ , Python, 1 line__init__.py - ecephys_spike_sorting/
modules/ , Python, 1 lineautomerging/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 54 linesautomerging/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 27 linesautomerging/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 99 linesautomerging/ automerging.py - ecephys_spike_sorting/
modules/ , Python, 141 linesautomerging/ merges.py - ecephys_spike_sorting/
modules/ , Python, 160 linesautomerging/ metrics.py - ecephys_spike_sorting/
modules/ , Python, 266 linesautomerging/ spike_ISI.py - ecephys_spike_sorting/
modules/ , Python, 1 linecatGT_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 171 linescatGT_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 38 linescatGT_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linedepth_estimation/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 75 linesdepth_estimation/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 48 linesdepth_estimation/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 256 linesdepth_estimation/ depth_estimation.py - ecephys_spike_sorting/
modules/ , Python, 1 lineextract_from_npx/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 71 linesextract_from_npx/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 28 linesextract_from_npx/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 65 linesextract_from_npx/ create_settings_json.py - ecephys_spike_sorting/
modules/ , Python, 1 linekilosort_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 298 lineskilosort_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 97 lineskilosort_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , MATLAB, 51 lineskilosort_helper/ kilosort2_master_file.m - ecephys_spike_sorting/
modules/ , MATLAB, 110 lineskilosort_helper/ main_KS2_KS25.m - ecephys_spike_sorting/
modules/ , MATLAB, 139 lineskilosort_helper/ main_KS2_KS25_KS3.m - ecephys_spike_sorting/
modules/ , MATLAB, 140 lineskilosort_helper/ main_kilosort_multiversi on.m - ecephys_spike_sorting/
modules/ , Python, 148 lineskilosort_helper/ matlab_file_generator.py - ecephys_spike_sorting/
modules/ , Python, 1 linekilosort_postprocessing/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 118 lineskilosort_postprocessing/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 33 lineskilosort_postprocessing/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 437 lineskilosort_postprocessing/ postprocessing.py - ecephys_spike_sorting/
modules/ , Python, 1 linemean_waveforms/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 244 linesmean_waveforms/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 39 linesmean_waveforms/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 214 linesmean_waveforms/ extract_waveforms.py - ecephys_spike_sorting/
modules/ , Python, 195 linesmean_waveforms/ metrics_from_file.py - ecephys_spike_sorting/
modules/ , Python, 595 linesmean_waveforms/ waveform_metrics.py - ecephys_spike_sorting/
modules/ , C/C++, 215 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ AppConfig.h - ecephys_spike_sorting/
modules/ , C/C++, 48 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ JuceHeader.h - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_basics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_devices.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_formats.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_processors.cp p - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_core.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_cryptography.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_data_structures.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_events.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_graphics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_gui_basics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_gui_extra.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_opengl.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_video.cpp - ecephys_spike_sorting/
modules/ , C++, 186 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ Source/ Main.cpp - ecephys_spike_sorting/
modules/ , Python, 1 linemedian_subtraction/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 55 linesmedian_subtraction/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 27 linesmedian_subtraction/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linenoise_templates/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 95 linesnoise_templates/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 51 linesnoise_templates/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 369 linesnoise_templates/ id_noise_templates.py - ecephys_spike_sorting/
modules/ , Python, 289 linesnoise_templates/ template_classifier_app. py - ecephys_spike_sorting/
modules/ , Python, 136 linesnoise_templates/ train_classifier.py - ecephys_spike_sorting/
modules/ , Python, 1 lineprePhy_filters/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 98 linesprePhy_filters/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 32 linesprePhy_filters/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linepsth_events/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 165 linespsth_events/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 25 linespsth_events/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linepykilosort_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 197 linespykilosort_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 52 linespykilosort_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linequality_metrics/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 108 linesquality_metrics/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 39 linesquality_metrics/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1,179 linesquality_metrics/ metrics.py - ecephys_spike_sorting/
modules/ , Python, 1 linetPrime_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 412 linestPrime_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 36 linestPrime_helper/ _schemas.py - ecephys_spike_sorting/
scripts/ , Python, 1 line__init__.py - ecephys_spike_sorting/
scripts/ , Python, 84 linesclassifier_pipeline.py - ecephys_spike_sorting/
scripts/ , Python, 427 linescreate_input_json.py - ecephys_spike_sorting/
scripts/ , Python, 283 lineshelpers/ SpikeGLX_utils.py - ecephys_spike_sorting/
scripts/ , Python, 1 linehelpers/ __init__.py - ecephys_spike_sorting/
scripts/ , Python, 398 lineshelpers/ check_data_processing.py - ecephys_spike_sorting/
scripts/ , Python, 104 lineshelpers/ log_from_json.py - ecephys_spike_sorting/
scripts/ , Python, 38 lineshelpers/ metric_file_fix.py - ecephys_spike_sorting/
scripts/ , Python, 54 lineshelpers/ plot_raw_data.py - ecephys_spike_sorting/
scripts/ , Python, 1 linehelpers/ processing.py - ecephys_spike_sorting/
scripts/ , Python, 39 lineshelpers/ run_one_probe.py - ecephys_spike_sorting/
scripts/ , Python, 201 linessglx_filelist_pipeline.p y - ecephys_spike_sorting/
scripts/ , Python, 404 linessglx_multi_run_3A_DL.py - ecephys_spike_sorting/
scripts/ , Python, 416 linessglx_multi_run_pipeline. py - ecephys_spike_sorting/
scripts/ , Python, 410 linessglx_multi_run_pipeline_ 2point0.py - ecephys_spike_sorting/
scripts/ , Python, 401 linessglx_multi_run_pipeline_ 2point0_gtlist.py - ecephys_spike_sorting/
scripts/ , Python, 384 linessglx_multi_run_pipeline_ WenSorscher2023.py - ecephys_spike_sorting/
supercat.sh , Shell, 6 lines - setup.py, Python, 41 lines
- tests/
__init__.py , Python, 10 lines - tests/
integration/ , Python, 10 lines__init__.py - tests/
unit/ , Python, 48 linescommon/ test_utils.py - tests/
unit/ , Python, 24 linesmodules/ automerging/ test_automerging.py - tests/
unit/ , Python, 44 linesmodules/ depth_estimation/ test_depth_estimation.py - tests/
unit/ , Python, 14 linesmodules/ extract_from_npx/ test_extract_from_npx.py - tests/
unit/ , Python, 32 linesmodules/ mean_waveforms/ test_mean_waveforms.py - tests/
unit/ , Python, 23 linesmodules/ noise_templates/ test_noise_templates.py - tests/
unit/ , Python, 36 linesmodules/ quality_metrics/ test_quality_metrics.py - LICENSE.txt, License, 33 lines
- README.md, Text, 412 lines
jenniferColonell/ecephys_spike_sorting
d61fba8e4387780ea4277c78eb891aacf7a4ee6b, 22 April 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
123 files
- .cookiecutter/
update.sh , Shell, 15 lines - .cookiecutter/
update_from_repo.py , Python, 12 lines - docs/
aibs_sphinx/ , Shell, 8 linesbuildPortalAssets.sh - docs/
aibs_sphinx/ , JavaScript, 1 linestatic/ external_assets/ bundled.js - docs/
aibs_sphinx/ , JavaScript, 292 linesstatic/ external_assets/ javascript/ AC_RunActiveContent.js - docs/
aibs_sphinx/ , JavaScript, 14 linesstatic/ external_assets/ javascript/ appConfig.js - docs/
aibs_sphinx/ , JavaScript, 28 linesstatic/ external_assets/ javascript/ browserVersions.js - docs/
aibs_sphinx/ , JavaScript, 5 linesstatic/ external_assets/ javascript/ relatedData.js - docs/
conf.py , Python, 295 lines - docs/
gallery/ , Python, 21 lineshelloworld.py - ecephys_spike_sorting/
__init__.py , Python, 1 line - ecephys_spike_sorting/
common/ , Python, 79 linesOEFileInfo.py - ecephys_spike_sorting/
common/ , Python, 729 linesSGLXMetaToCoords.py - ecephys_spike_sorting/
common/ , Python, 1 line__init__.py - ecephys_spike_sorting/
common/ , Python, 84 linesepoch.py - ecephys_spike_sorting/
common/ , Python, 36 linesschemas.py - ecephys_spike_sorting/
common/ , Python, 708 linesutils.py - ecephys_spike_sorting/
common/ , Python, 407 linesvisualization.py - ecephys_spike_sorting/
modules/ , Python, 1 line__init__.py - ecephys_spike_sorting/
modules/ , Python, 1 lineautomerging/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 54 linesautomerging/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 27 linesautomerging/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 99 linesautomerging/ automerging.py - ecephys_spike_sorting/
modules/ , Python, 141 linesautomerging/ merges.py - ecephys_spike_sorting/
modules/ , Python, 160 linesautomerging/ metrics.py - ecephys_spike_sorting/
modules/ , Python, 266 linesautomerging/ spike_ISI.py - ecephys_spike_sorting/
modules/ , Python, 1 linecatGT_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 181 linescatGT_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 38 linescatGT_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linedepth_estimation/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 75 linesdepth_estimation/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 48 linesdepth_estimation/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 256 linesdepth_estimation/ depth_estimation.py - ecephys_spike_sorting/
modules/ , Python, 1 lineextract_from_npx/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 71 linesextract_from_npx/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 28 linesextract_from_npx/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 65 linesextract_from_npx/ create_settings_json.py - ecephys_spike_sorting/
modules/ , Python, 1 linekilosort_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 311 lineskilosort_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 97 lineskilosort_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , MATLAB, 51 lineskilosort_helper/ kilosort2_master_file.m - ecephys_spike_sorting/
modules/ , MATLAB, 110 lineskilosort_helper/ main_KS2_KS25.m - ecephys_spike_sorting/
modules/ , MATLAB, 139 lineskilosort_helper/ main_KS2_KS25_KS3.m - ecephys_spike_sorting/
modules/ , MATLAB, 141 lineskilosort_helper/ main_kilosort_multiversi on.m - ecephys_spike_sorting/
modules/ , Python, 148 lineskilosort_helper/ matlab_file_generator.py - ecephys_spike_sorting/
modules/ , Python, 1 linekilosort_postprocessing/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 113 lineskilosort_postprocessing/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 32 lineskilosort_postprocessing/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 440 lineskilosort_postprocessing/ postprocessing.py - ecephys_spike_sorting/
modules/ , Python, 1 lineks4_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 297 linesks4_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 55 linesks4_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linemean_waveforms/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 358 linesmean_waveforms/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 41 linesmean_waveforms/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 210 linesmean_waveforms/ extract_waveforms.py - ecephys_spike_sorting/
modules/ , Python, 183 linesmean_waveforms/ metrics_from_file.py - ecephys_spike_sorting/
modules/ , Python, 583 linesmean_waveforms/ waveform_metrics.py - ecephys_spike_sorting/
modules/ , C/C++, 215 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ AppConfig.h - ecephys_spike_sorting/
modules/ , C/C++, 48 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ JuceHeader.h - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_basics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_devices.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_formats.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_audio_processors.cp p - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_core.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_cryptography.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_data_structures.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_events.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_graphics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_gui_basics.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_gui_extra.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_opengl.cpp - ecephys_spike_sorting/
modules/ , C++, 9 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ JuceLibraryCode/ juce_video.cpp - ecephys_spike_sorting/
modules/ , C++, 186 linesmedian_subtraction/ SpikeBandMedianSubtracti on/ Source/ Main.cpp - ecephys_spike_sorting/
modules/ , Python, 1 linemedian_subtraction/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 55 linesmedian_subtraction/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 27 linesmedian_subtraction/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linenoise_templates/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 67 linesnoise_templates/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 55 linesnoise_templates/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 428 linesnoise_templates/ id_noise_templates.py - ecephys_spike_sorting/
modules/ , Python, 289 linesnoise_templates/ template_classifier_app. py - ecephys_spike_sorting/
modules/ , Python, 136 linesnoise_templates/ train_classifier.py - ecephys_spike_sorting/
modules/ , Python, 1 linepsth_events/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 165 linespsth_events/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 25 linespsth_events/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linepykilosort_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 197 linespykilosort_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 52 linespykilosort_helper/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 1 linequality_metrics/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 108 linesquality_metrics/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 40 linesquality_metrics/ _schemas.py - ecephys_spike_sorting/
modules/ , Python, 286 linesquality_metrics/ ibl_metrics.py - ecephys_spike_sorting/
modules/ , Python, 1,179 linesquality_metrics/ metrics.py - ecephys_spike_sorting/
modules/ , Python, 1 linetPrime_helper/ __init__.py - ecephys_spike_sorting/
modules/ , Python, 431 linestPrime_helper/ __main__.py - ecephys_spike_sorting/
modules/ , Python, 37 linestPrime_helper/ _schemas.py - ecephys_spike_sorting/
scripts/ , Python, 1 line__init__.py - ecephys_spike_sorting/
scripts/ , Python, 467 linescreate_input_json.py - ecephys_spike_sorting/
scripts/ , Python, 501 lineshelpers/ SpikeGLX_utils.py - ecephys_spike_sorting/
scripts/ , Python, 1 linehelpers/ __init__.py - ecephys_spike_sorting/
scripts/ , Python, 398 lineshelpers/ check_data_processing.py - ecephys_spike_sorting/
scripts/ , Python, 104 lineshelpers/ log_from_json.py - ecephys_spike_sorting/
scripts/ , Python, 38 lineshelpers/ metric_file_fix.py - ecephys_spike_sorting/
scripts/ , Python, 54 lineshelpers/ plot_raw_data.py - ecephys_spike_sorting/
scripts/ , Python, 1 linehelpers/ processing.py - ecephys_spike_sorting/
scripts/ , Python, 40 lineshelpers/ run_one_probe.py - ecephys_spike_sorting/
scripts/ , Python, 266 linessglx_filelist_pipeline.p y - ecephys_spike_sorting/
scripts/ , Python, 485 linessglx_multi_run_pipeline. py - ecephys_spike_sorting/
scripts/ , Python, 526 linessglx_runlist_split_shank s_pipeline.py - ecephys_spike_sorting/
scripts/ , Python, 494 linessglx_super_run_pipeline. py - setup.py, Python, 40 lines
- tests/
__init__.py , Python, 10 lines - tests/
integration/ , Python, 10 lines__init__.py - tests/
unit/ , Python, 48 linescommon/ test_utils.py - tests/
unit/ , Python, 24 linesmodules/ automerging/ test_automerging.py - tests/
unit/ , Python, 44 linesmodules/ depth_estimation/ test_depth_estimation.py - tests/
unit/ , Python, 14 linesmodules/ extract_from_npx/ test_extract_from_npx.py - tests/
unit/ , Python, 32 linesmodules/ mean_waveforms/ test_mean_waveforms.py - tests/
unit/ , Python, 23 linesmodules/ noise_templates/ test_noise_templates.py - tests/
unit/ , Python, 36 linesmodules/ quality_metrics/ test_quality_metrics.py - LICENSE.txt, License, 33 lines
- README.md, Text, 454 lines
emilyasterjones/bombcell
b7127c41f35ec6e57973b3aa9b61ec79159e86f2, 11 March 2024Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
151 files
- bc_qualityMetrics_pipeli
ne.m , MATLAB, 98 lines - classifyStriatum/
bc_classifyStriatalCells , MATLAB, 18 lines.m - classifyStriatum/
bc_selectAndClassifyStri , MATLAB, 69 linesatum.m - classifyStriatum/
classifyStriatum.m , MATLAB, 20 lines - classifyStriatum/
pipeline.m , MATLAB, 127 lines - classifyStriatum/
plotStriatumCells.m , MATLAB, 35 lines - classifyStriatum/
qualityMetricVenn.R , R, 28 lines - decompressData/
Ephys_Reader_FromMatlab. , Python, 26 linespy - decompressData/
MTSDecomp_From_Matlab.py , Python, 21 lines - decompressData/
bc_extractCbinData.m , MATLAB, 206 lines - decompressData/
test.m , MATLAB, 32 lines - eaj_qualityMetrics_pipel
ine.m , MATLAB, 62 lines - eaj_qualityMetrics_pipel
ine_2point0.m , MATLAB, 58 lines - eaj_qualityMetrics_pipel
ine_WenSorscher2023.m , MATLAB, 58 lines - ephysProperties/
bc_computeACG.m , MATLAB, 15 lines - ephysProperties/
bc_computeAllEphysProper , MATLAB, 84 linesties.m - ephysProperties/
bc_computeFR.m , MATLAB, 14 lines - ephysProperties/
bc_computePSS.m , MATLAB, 10 lines - ephysProperties/
bc_computePropLongISI.m , MATLAB, 32 lines - ephysProperties/
bc_computeTemplateWavefo , MATLAB, 46 linesrmDuration.m - ephysProperties/
bc_ephysPropValues.m , MATLAB, 37 lines - ephysProperties/
bc_ephysPropertiesPipeli , MATLAB, 28 linesne_JF.m - ephysProperties/
bc_getWaveformMaxChannel , MATLAB, 28 linesEP.m - ephysProperties/
bc_loadSavedProperties.m , MATLAB, 13 lines - ephysProperties/
bc_saveEphysProperties.m , MATLAB, 46 lines - ephysProperties/
helpers/ , MATLAB, 164 linesCCGBz.m - ephysProperties/
helpers/ , C, 207 linesCCGHeart.c - ephysProperties/
helpers/ , C, 292 lineshistdiff.c - ephysProperties/
helpers/ , MATLAB, 24 lineshistdiff.m - ephysProperties/
helpers/ , C, 303 lineshistdiffMulti.c - ephysProperties/
helpers/ , MATLAB, 56 linesisdmatrix.m - ephysProperties/
helpers/ , MATLAB, 57 linesisdscalar.m - ephysProperties/
helpers/ , MATLAB, 72 linesisdvector.m - ephysProperties/
helpers/ , MATLAB, 59 linesisimatrix.m - ephysProperties/
helpers/ , MATLAB, 61 linesisiscalar.m - ephysProperties/
helpers/ , MATLAB, 75 linesisivector.m - ephysProperties/
helpers/ , MATLAB, 40 linesislmatrix.m - ephysProperties/
helpers/ , MATLAB, 40 linesislscalar.m - ephysProperties/
helpers/ , MATLAB, 59 linesislvector.m - ephysProperties/
helpers/ , MATLAB, 52 linesisradians.m - ephysProperties/
old/ , MATLAB, 109 linesgetEphysProperties.m - histology/
bc_StackSlideOverlay.m , MATLAB, 508 lines - histology/
bc_StackSlider2.m , MATLAB, 727 lines - histology/
bc_brainreg.m , MATLAB, 32 lines - histology/
bc_display_histology_ccf , MATLAB, 346 lines.m - histology/
bc_get_probe_histology.m , MATLAB, 410 lines - histology/
bc_grab_histology_ccf.m , MATLAB, 358 lines - histology/
bc_manual_align_histolog , MATLAB, 326 linesy_ccf.m - histology/
bc_processRockSawGUI.m , MATLAB, 325 lines - histology/
histology_playground.m , MATLAB, 33 lines - histology/
utilities/ , MATLAB, 727 linesStackSlider2.m - histology/
utilities/ , MATLAB, 24 linesscreensize.m - loading/
ReadMeta2.m , MATLAB, 34 lines - loading/
bc_AP_load_experimentJF. , MATLAB, 1,835 linesm - loading/
bc_extractRawWaveforms.m , MATLAB, 122 lines - loading/
bc_legacyReadtable.m , MATLAB, 67 lines - loading/
bc_loadEphysData.m , MATLAB, 71 lines - loading/
bc_loadMetricsForGUI.m , MATLAB, 106 lines - loading/
bc_loadSavedMetrics.m , MATLAB, 39 lines - loading/
bc_qMetric_to_parquet.m , MATLAB, 30 lines - loading/
bc_readMetaForCBins.m , MATLAB, 34 lines - loading/
bc_readOEMetaFile.m , MATLAB, 24 lines - loading/
bc_readSpikeGLXMetaFile. , MATLAB, 55 linesm - loading/
bc_readtable.m , MATLAB, 514 lines - loading/
bc_writetable.m , MATLAB, 450 lines - loading/
loadEphysDataJF.m , MATLAB, 18 lines - personal_work_in_progres
s/ , MATLAB, 34 linesbc_checkArtifacts_pipeli ne.m - personal_work_in_progres
s/ , MATLAB, 32 linesbc_checkSpikeDetectionTh reshold_pipeline.m - personal_work_in_progres
s/ , MATLAB, 42 linesbc_fshift.m - personal_work_in_progres
s/ , MATLAB, 59 linesbc_qualityMetricsPipelin e_JF.m - personal_work_in_progres
s/ , MATLAB, 65 linesbc_qualityMetrics_pipeli ne_DecompressedData.m - personal_work_in_progres
s/ , MATLAB, 63 linesbc_qualityMetrics_pipeli ne_compressedPlayground. m - personal_work_in_progres
s/ , MATLAB, 62 linesbc_rawDataView.m - personal_work_in_progres
s/ , MATLAB, 87 linesbc_subsetRawData.m - personal_work_in_progres
s/ , MATLAB, 7 linesfixFracRPVs.m - personal_work_in_progres
s/ , MATLAB, 103 linespreprocessing/ bc_tShift.m - personal_work_in_progres
s/ , MATLAB, 117 linestest_merging.m - personal_work_in_progres
s/ , Python, 15 linesuncompressData/ bc_uncompressBin.py - personal_work_in_progres
s/ , MATLAB, 16 linesuncompressData/ bc_uncompressBinData.m - phyPlugins/
colorSelectorPlugin.py , Python, 35 lines - phyPlugins/
customizeSelectorStatsPl , Python, 12 linesugin.py - phyPlugins/
phy_config.py , Python, 15 lines - phyPlugins/
qMetricsPlugin.py , Python, 113 lines - qualityMetrics/
bc_defineTimechunksToKee , MATLAB, 71 linesp.m - qualityMetrics/
bc_fractionRPviolations. , MATLAB, 138 linesm - qualityMetrics/
bc_getDistanceMetrics.m , MATLAB, 173 lines - qualityMetrics/
bc_getQualityUnitType.m , MATLAB, 122 lines - qualityMetrics/
bc_getRawAmplitude.m , MATLAB, 42 lines - qualityMetrics/
bc_manageDataCompression , MATLAB, 31 lines.m - qualityMetrics/
bc_maxDriftEstimate.m , MATLAB, 57 lines - qualityMetrics/
bc_numberSpikes.m , MATLAB, 15 lines - qualityMetrics/
bc_percSpikesMissing.m , MATLAB, 172 lines - qualityMetrics/
bc_plotGlobalQualityMetr , MATLAB, 245 linesic.m - qualityMetrics/
bc_presenceRatio.m , MATLAB, 58 lines - qualityMetrics/
bc_qualityParamValues.m , MATLAB, 123 lines, 1 match - qualityMetrics/
bc_qualityParamValuesFor , MATLAB, 166 linesUnitMatch.m - qualityMetrics/
bc_runAllQualityMetrics. , MATLAB, 241 linesm - qualityMetrics/
bc_saveQMetrics.m , MATLAB, 70 lines - qualityMetrics/
bc_waveformShape.m , MATLAB, 258 lines - qualityMetrics/
eaj_getQualityUnitType.m , MATLAB, 18 lines - qualityMetrics/
eaj_qualityParamValues.m , MATLAB, 115 lines, 1 match - qualityMetrics/
helpers/ , MATLAB, 14 linesJF_gaussian_cut.m - qualityMetrics/
helpers/ , MATLAB, 13 linesTextLocation.m - qualityMetrics/
helpers/ , MATLAB, 176 linesbc_extractRawWaveformsFa st.m - qualityMetrics/
helpers/ , MATLAB, 16 linesbc_getWaveformMaxChannel .m - qualityMetrics/
helpers/ , MATLAB, 9 linesbc_readOEMetaFile.m - qualityMetrics/
helpers/ , MATLAB, 29 linesbc_readSpikeGLXMetaFile. m - qualityMetrics/
helpers/ , MATLAB, 70 linesprevious/ Copy_of_extractSPKs.m - qualityMetrics/
helpers/ , MATLAB, 136 linesprevious/ bc_extractRawWaveformsFa st_copy_works.m - qualityMetrics/
helpers/ , MATLAB, 167 linesprevious/ bc_extractRawWaveformsFa st_old.m - qualityMetrics/
helpers/ , MATLAB, 290 linesprevious/ bc_extractRawWaveformsFa st_old2.m - qualityMetrics/
helpers/ , MATLAB, 100 linesprevious/ extractSPKs.m - qualityMetrics/
helpers/ , MATLAB, 1,029 linesvennEulerDiagram.m - qualityMetrics/
old/ , MATLAB, 62 linesampli_fit_prc_missJF.m - qualityMetrics/
old/ , MATLAB, 350 linesclassifyUnitQualityCellT ypeJF.m - qualityMetrics/
old/ , MATLAB, 39 linesdetectBurstsJF.m - qualityMetrics/
old/ , MATLAB, 84 linesexampleQualityMetCellTyp e_single.m - qualityMetrics/
old/ , MATLAB, 41 linesfractionRPviolationsJF.m - qualityMetrics/
old/ , Python, 21 linesgaussFitJF.py - qualityMetrics/
old/ , MATLAB, 121 linesgetDistanceMetricsJF.m - qualityMetrics/
old/ , MATLAB, 104 linesgetQualityMetrics.m - qualityMetrics/
old/ , MATLAB, 62 linesgetRawWaveformAmplitude. m - qualityMetrics/
old/ , MATLAB, 75 linesgetRawWaveformAmplitude2 .m - qualityMetrics/
toTry/ , MATLAB, 83 linesgaussian_mssing.m - qualityMetrics/
toTry/ , MATLAB, 36 linesmode_guesser.m - recordingUtilities/
generateChannelMaps/ , MATLAB, 224 lineschanMapGenerateTemplate. m - recordingUtilities/
generateIMROfiles/ , MATLAB, 226 linesnptype21_imro.m - recordingUtilities/
generateIMROfiles/ , MATLAB, 180 linesnptype24_imro.m - visualizationTools/
bc_colors.m , MATLAB, 71 lines - visualizationTools/
bc_getRawMemMap.m , MATLAB, 18 lines - visualizationTools/
bc_getRawMemMap_WithPyth , MATLAB, 72 lineson.m - visualizationTools/
bc_plotEulerDiagram.m , MATLAB, 65 lines - visualizationTools/
bc_plotRawData.m , MATLAB, 29 lines - visualizationTools/
bc_rawDataGUI.m , MATLAB, 201 lines - visualizationTools/
bc_unitQualityGUI.m , MATLAB, 657 lines - visualizationTools/
bc_upSetPlot.m , MATLAB, 32 lines - visualizationTools/
helpers/ , MATLAB, 540 linesLineReducer.m - visualizationTools/
helpers/ , MATLAB, 51 linesbc_combvec.m - visualizationTools/
helpers/ , MATLAB, 147 linesdistinguishable_colors.m - visualizationTools/
helpers/ , MATLAB, 68 lineskeep.m - visualizationTools/
helpers/ , MATLAB, 276 linesrgb.m - visualizationTools/
makepretty.m , MATLAB, 92 lines - visualizationTools/
old/ , MATLAB, 282 linesdynamicClusterPlot.m - visualizationTools/
old/ , MATLAB, 77 linesdynamicRawPlot.m - visualizationTools/
old/ , MATLAB, 69 linesdynamicSubRawPlot.m - visualizationTools/
old/ , MATLAB, 33 linesexampleDynamicClusterPlo t.m - visualizationTools/
old/ , MATLAB, 30 linesexampleDynamicRawPlot.m - visualizationTools/
old/ , MATLAB, 370 linesunitQualityGUI_slow.m - visualizationTools/
plotAmplis_simple.m , MATLAB, 31 lines - LICENSE, License, 674 lines
- README.md, Text, 65 lines
LorenFrankLab/track_linearization
424087881215e3e30bfbf00926571d9e5bef1239, 16 October 2025Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
18 files
- examples/
interactive_track_builde , Python, 248 linesr_demo.py - notebooks/
advanced_features_tutori , Jupyter, 755 linesal.ipynb - notebooks/
test_linearization.ipynb , Jupyter, 681 lines - notebooks/
track_linearization_tuto , Jupyter, 587 linesrial.ipynb - src/
track_linearization/ , Python, 82 lines__init__.py - src/
track_linearization/ , Python, 1,313 lines, 1 matchcore.py - src/
track_linearization/ , Python, 246 linestests/ test_batch_utils.py - src/
track_linearization/ , Python, 1,058 linestests/ test_core.py - src/
track_linearization/ , Python, 290 linestests/ test_hmm.py - src/
track_linearization/ , Python, 4 linestests/ test_import.py - src/
track_linearization/ , Python, 272 linestests/ test_track_builders.py - src/
track_linearization/ , Python, 444 linestests/ test_utils.py - src/
track_linearization/ , Python, 344 linestests/ test_validation.py - src/
track_linearization/ , Python, 1,089 linestrack_builders.py - src/
track_linearization/ , Python, 629 linesutils.py - src/
track_linearization/ , Python, 410 linesvalidation.py - LICENSE, License, 21 lines
- README.md, Text, 367 lines
Eden-Kramer-Lab/ripple_detection
68e1784b183f161a568d3154325cf770730bfb83, 26 September 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
44 files
- examples/
detection_examples.ipynb , Jupyter, 408 lines - examples/
literature_recipes.py , Python, 165 lines - examples/
measured_walkthrough.py , Python, 233 lines - examples/
ripple_detection_tutoria , Jupyter, 963 linesl.ipynb - examples/
simulation_study.ipynb , Jupyter, 249 lines - examples/
simulation_study.py , Python, 320 lines - examples/
test_individual_algorith , Jupyter, 138 linesm_components.ipynb - src/
ripple_detection/ , Python, 169 lines__init__.py - src/
ripple_detection/ , Python, 276 lines_call_hints.py - src/
ripple_detection/ , Python, 455 lines_descriptions.py - src/
ripple_detection/ , Python, 3,295 linescore.py - src/
ripple_detection/ , Python, 1 linedata/ __init__.py - src/
ripple_detection/ , Python, 48 linesdetectors/ __init__.py - src/
ripple_detection/ , Python, 234 linesdetectors/ _blocks.py - src/
ripple_detection/ , Python, 854 linesdetectors/ _carey.py - src/
ripple_detection/ , Python, 468 linesdetectors/ _events.py - src/
ripple_detection/ , Python, 260 lines, 1 matchdetectors/ _hse.py - src/
ripple_detection/ , Python, 1,440 lines, 1 matchdetectors/ _lfp.py - src/
ripple_detection/ , Python, 555 linesdetectors/ _long.py - src/
ripple_detection/ , Python, 344 linesdetectors/ _silence.py - src/
ripple_detection/ , Python, 292 linesdetectors/ _state.py - src/
ripple_detection/ , Python, 520 linesdetectors/ _trace.py - src/
ripple_detection/ , Python, 380 linesdetectors/ _units.py - src/
ripple_detection/ , Python, 503 linesdetectors/ _validation.py - src/
ripple_detection/ , Python, 382 linesdetectors/ _zugaro.py - src/
ripple_detection/ , Python, 137 linesliterature.py - src/
ripple_detection/ , Python, 5,264 lines, 1 matchliterature_methods.py - src/
ripple_detection/ , Python, 513 linesregistry.py - src/
ripple_detection/ , Python, 1,320 linessimulate.py - tests/
_synthetic.py , Python, 70 lines - tests/
conftest.py , Python, 316 lines - tests/
test_core.py , Python, 2,842 lines - tests/
test_detectors.py , Python, 4,667 lines - tests/
test_integration.py , Python, 727 lines - tests/
test_literature.py , Python, 311 lines - tests/
test_literature_methods. , Python, 2,816 linespy - tests/
test_literature_recipes. , Python, 249 linespy - tests/
test_properties.py , Python, 500 lines - tests/
test_public_api.py , Python, 532 lines - tests/
test_registry.py , Python, 439 lines - tests/
test_simulate.py , Python, 1,146 lines - tests/
test_snapshots.py , Python, 416 lines - LICENSE, License, 21 lines
- README.md, Text, 1,120 lines
emilyasterjones/AeryJones_2025
dfbbde116929d420523421d7bfe5d441eb91568a, 11 June 2025Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
26 files
- Figures_published_editio
n.ipynb , Jupyter, 3,709 lines, 4 matches - Histology.ipynb, Jupyter, 211 lines
- Yggdrasil/
Capture/ , Python, 239 linesCamera/ capture_video_FLIR.py - Yggdrasil/
Electrodes/ , Python, 255 lineselectrodes.py - Yggdrasil/
LFP/ , Python, 401 lineshuman_precession.py - Yggdrasil/
LFP/ , Python, 476 lines, 2 matcheslfp.py - Yggdrasil/
NWB/ , Python, 238 linesnwb.py - Yggdrasil/
Position/ , Python, 44 linesDLC/ dlc_analyze_videos.py - Yggdrasil/
Position/ , Python, 50 linesDLC/ train_dlc_recipe.py - Yggdrasil/
Position/ , Python, 558 lines, 1 matcharena.py - Yggdrasil/
Position/ , Python, 781 linesposition.py - Yggdrasil/
Position/ , Python, 1,095 linesspatial_functions.py - Yggdrasil/
Sequences/ , Python, 400 linesdenovellis_elife.py - Yggdrasil/
Sequences/ , Python, 960 linesplot.py - Yggdrasil/
Sequences/ , Python, 1,643 lines, 2 matchessequences.py - Yggdrasil/
Spikes/ , Python, 434 lines, 2 matchesspikes.py - Yggdrasil/
Task/ , Python, 371 linestask.py - Yggdrasil/
statistics.py , Python, 95 lines - Yggdrasil/
utilities.py , Python, 69 lines - convert_to_NWB.ipynb, Jupyter, 155 lines
- extract_sequences_publis
hed_edition.ipynb , Jupyter, 709 lines, 2 matches - figurl.ipynb, Jupyter, 1,116 lines
- preprocess_all_sessions_
published_edition.ipynb , Jupyter, 727 lines - setup.py, Python, 31 lines
- LICENSE, License, 674 lines
- README.md, Text, 22 lines
Code availability
All original code can be found at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 8 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 522 scripts, each with its path and the digest of its content;
- 19 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- dandi:001701, at DANDI; found in “Data availability”
Data availability
The 0.1–300-Hz filtered LFP, isolated unit spike times, electrode site locations, trial data, mouse position and head direction, subject metadata and session metadata are available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Publisher: n/a → Nature Portfolio
Version 1, 28 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 2 keywords, 10 MeSH terms, 3 funders, 52 references, 1 RRID.
Cite
This paper
Aery Jones, E. A., Low, I. I. C., Cho, F. S., & Giocomo, L. M. (2026). Entorhinal cortex represents task-relevant remote locations independently of CA1. Nature neuroscience, 29(5), 1181-1190. https://
BibTeX
@article{aeryjones2026en
author = {Aery Jones, Emily A and Low, Isabel I C and Cho, Frances S and Giocomo, Lisa M},
title = {{Entorhinal cortex represents task-relevant remote locations independently of CA1}},
journal = {Nature neuroscience},
year = {2026},
month = apr,
volume = {29},
number = {5},
pages = {1181--1190},
publisher = {Nature Portfolio},
issn = {1097-6256},
doi = {10.1038/
url = {https://
pmid = {41922514},
pmcid = {PMC13107481}
}
RIS
TY - JOUR
AU - Aery Jones, Emily A
AU - Low, Isabel I C
AU - Cho, Frances S
AU - Giocomo, Lisa M
TI - Entorhinal cortex represents task-relevant remote locations independently of CA1
T2 - Nature neuroscience
J2 - Nat Neurosci
PY - 2026
DA - 2026/
VL - 29
IS - 5
SP - 1181
EP - 1190
SN - 1097-6256
PB - Nature Portfolio
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Entorhinal cortex represents task-relevant remote locations independently of CA1",
"container-title": "Nature neuroscience",
"author": [
{
"family": "Aery Jones",
"given": "Emily A"
},
{
"family": "Low",
"given": "Isabel I C"
},
{
"family": "Cho",
"given": "Frances S"
},
{
"family": "Giocomo",
"given": "Lisa M"
}
],
"container-title-short":
"volume": "29",
"issue": "5",
"page": "1181-1190",
"DOI": "10.1038/
"PMID": "41922514",
"PMCID": "PMC13107481",
"ISSN": "1097-6256",
"publisher": "Nature Portfolio",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
1
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1016/j.patter.2026.101590 [code]
- Density-based longitudinal neuron tracking in high-density electrophysiological recordings.Journal: Patterns (New York, N.Y.)In common: Phy, Kilosort, SpikeInterface, 14 other tools, 3 references
- [2] doi:10.7554/elife.110588 [code]
- Opening the black box toward a modular approach to spike sorting.Journal: eLifeIn common: Kilosort, SpikeInterface, Neurodata Without Borders (PyNWB, MatNWB), 12 other tools, mouse, 4 references
- [3] doi:10.1038/s41593-026-02362-5 [code]
- Replay of procedural memory is independent of the hippocampus.Journal: Nature neuroscienceIn common: Pingouin, h5py, Pillow, 9 other tools, mouse, 9 references
- [4] doi:10.1038/s41467-026-75347-4 [code]
- Sleep reveals dynamics integrating and segregating movement and stimulus representations in V1.Journal: Nature communicationsIn common: Phy, Neurodata Without Borders (PyNWB, MatNWB), CircStat, 13 other tools, systems, mouse, 1 reference
- [5] doi:10.1016/j.celrep.2026.117646 [code]
- Medial entorhinal-hippocampal desynchronization parallels the emergence of memory impairment in a mouse model of Alzheimer's disease pathology.Journal: Cell reportsIn common: Neurodata Without Borders (PyNWB, MatNWB), CircStat, Optimization Toolbox, 9 other tools, systems, mouse, 5 references
- [6] doi: [code]
- Naturalistic behavior and self-generated neural activity predictive of self-correctionJournal: bioRxiv : the preprint server for biologyIn common: SpikeInterface, Neurodata Without Borders (PyNWB, MatNWB), xarray, 11 other tools, 2 references
- [7] doi:10.1038/s41467-026-76581-6 [code]
- Thalamocortical bursts encode reward contingencies and drive associative learning.Journal: Nature communicationsIn common: Kilosort, xarray, CircStat, 11 other tools, systems, mouse, 2 references
- [8] doi:10.7554/elife.109717 [code]
- Retrosplenial cortex enables context-dependent goal-directed sensorimotor transformation.Journal: eLifeIn common: Kilosort, Neurodata Without Borders (PyNWB, MatNWB), Numba, 12 other tools, systems, mouse, 1 reference
- [9] doi:10.1016/j.isci.2026.116825 [code]
- Social hierarchy shapes behavioral and transcriptional responses to chronic stress and ketamine in male mice.Journal: iScienceIn common: Pingouin, Numba, NetworkX, 12 other tools, systems, mouse, 2 references
- [10] doi:10.1002/hipo.70131 [code]
- Decoding Medial Entorhinal Cortical Dynamics Produces Planning-Like Alternations in Hippocampal theta Sequences.Journal: HippocampusIn common: xarray, Numba, OpenCV, 6 other tools, systems, 6 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 8 repositories of the authors' code, each at its verified commit and with its license, 522 scripts, and 19 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:77cee9b24e533be5…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
- emilyasterjones/X_maze: README.md on GitHub
- petersaj/AP_histology: README.md on GitHub
- emilyasterjones/ecephys_spike_sorting: README.md on GitHub
- jenniferColonell/ecephys_spike_sorting: README.md on GitHub
- emilyasterjones/bombcell: README.md on GitHub
- LorenFrankLab/track_linearization: README.md on GitHub
- Eden-Kramer-Lab/ripple_detection: README.md on GitHub
- emilyasterjones/AeryJones_2025: README.md on GitHub
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
