OSCR

Impaired behavioral inhibition in Fmr1 KO mice is linked to disrupted visual cortex theta oscillations.

Code ↔ Paper

20 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 20 matches
  1. [1] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Local field potential (LFP) analysis ↔ LFP/Neuropixels_LFP/2_reward_LFP-novel.ipynb, lines 162–194 · score 0.94 · 1.05–1.15 s, 0.55–0.7 s, 0.71–0.85 s, 0.86–1 s, 0.86 s, 0.71 s
  2. [2] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Local field potential (LFP) analysis ↔ LFP/V1_HPC/mz_LFP_functions.py, lines 105–230 · score 0.89 · Morlet wavelet, wavelet convolution, phase locking, frequency precision, 3–10, dB
  3. [3] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Classification analyses ↔ ML Code/accvsunits.py, lines 20–119 · score 0.80 · cross validated, balanced accuracy, logistic regression, fold, classifier, bins
  4. [4] § RESULTS › Reduced local field potential dynamics in V1 across conditions ↔ LFP/64Chs_LFP/64Ch_lfp.ipynb, lines 612–655 · score 0.79 · 30–40 Hz, 50–70 Hz, 12–30 Hz, 30–70 Hz, 8–12 Hz, beta
  5. [5] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Classification analyses ↔ ML Code/accvsunits.py, lines 20–119 · score 0.77 · cross validated, balanced accuracy, LBFGS, L2, fold, classification
  6. [6] § RESULTS › Reduced local field potential dynamics in V1 across conditions ↔ LFP/Neuropixels_LFP/2_reward_LFP-novel.ipynb, lines 162–194 · score 0.76 · 0.55–0.7 s, 0.71–0.85 s, 0.86–1 s, 0.86 s, 0.71 s, 0.55 s
  7. [7] § RESULTS › Reduced local field potential dynamics in V1 across conditions ↔ LFP/V1_HPC/plv_phd_afterSaving.ipynb, lines 330–394 · score 0.76 · 30–40 Hz, 50–70 Hz, 12–30 Hz, 30–70 Hz, 8–12 Hz, beta
  8. [8] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Associating theta oscillations with behavior outcomes ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 1577–1636 · score 0.71 · linear regression, standard deviation, theta power, linregress, fit, lick
  9. [9] § RESULTS › Inter-region coupling is decreased in FX while intra-region coherence matches WT ↔ LFP/V1_HPC/plv_phd_afterSaving.ipynb, lines 396–429 · score 0.71 · 0.7–1.5 s, 0.5–0.7 s, 30–70 Hz, V1 HPC, PLV, PHD
  10. [10] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Single unit analysis ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 1294–1336 · score 0.70 · phase domain, LFP phase, Hilbert, SPC, coherence, filter
  11. [11] § RESULTS › Reduced local field potential dynamics in V1 across conditions ↔ LFP/V1_HPC/2_HPC_TF.ipynb, lines 326–358 · score 0.69 · 30–40 Hz, 50–70 Hz, 12–30 Hz, 30–70 Hz, 8–12 Hz, frequency band
  12. [12] § RESULTS › Reduced local field potential dynamics in V1 across conditions ↔ LFP/Neuropixels_LFP/3_TF_analysis-novel.ipynb, lines 241–262 · score 0.67 · 30–40 Hz, 50–70 Hz, 12–30 Hz, 30–70 Hz, 8–12 Hz, 4–8 Hz
  13. [13] § RESULTS › Correlating behavior outcomes with theta oscillation activity ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 1577–1636 · score 0.64 · Linear regressions, Incorrect trials, theta power, fit, correlation, licking
  14. [14] § STAR★METHODS › QUANTIFICATION AND STATISTICAL ANALYSIS ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 1638–1654 · score 0.61 · Spearman correlation coefficient, permutation, licking, behavior, theta, HPC
  15. [15] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Classification analyses ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 781–810 · score 0.60 · logistic regression model, accuracy score, trained, stimulus
  16. [16] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Single unit analysis ↔ LFP/V1_HPC/1_HPC_LFP.ipynb, lines 247–291 · score 0.60 · 30–70 Hz, 12–30, 8–12, 2–4, fft, AUC
  17. [17] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Single unit analysis ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 355–393 · score 0.60 · 30–70 Hz, 12–30, 8–12, 2–4, fft, AUC
  18. [18] § RESULTS › Correlating behavior outcomes with theta oscillation activity ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 1178–1265 · score 0.57 · unit raster, lick raster, LFP traces, CR, Correlating, theta
  19. [19] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Classification analyses ↔ Behavior_Theta_Correlation/Behavior_Theta_Correlation.ipynb, lines 716–779 · score 0.57 · logistic regression model, Go trials, probability, trained
  20. [20] § STAR★METHODS › METHOD DETAILS › Pharmacological interventions › Data acquisition and preprocessing ↔ LFP/64Chs_LFP/64Ch_lfp.ipynb, lines 192–263 · score 0.56 · bandpass filtered, notch, noise, preprocessing, Scipy, electrodes

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 · 1,672 lines · 79 KB · no license · 8 matches

  1. # %%
  2. import os
  3. import glob
  4. import numpy as np
  5. import random
  6. import pandas as pd
  7. import pickle
  8. import matplotlib as mpl
  9. import matplotlib.pyplot as plt
  10. import seaborn as sns
  11. from matplotlib.patches import Ellipse
  12. import matplotlib.transforms as transforms
  13. import scipy.signal as ssig
  14. from sklearn.metrics import auc
  15. import itertools
  16. import scipy.ndimage as scnd
  17. import scipy.stats as sstat
  18. from statsmodels.formula.api import mixedlm
  19. import mz_LFP_functions as mz_LFP
  20. import mz_ephys_unit_analysis as mz_ena
  21. # %%
  22. mpl.rcParams['pdf.fonttype'] = 42
  23. mpl.rcParams['font.sans-serif']=['Arial', 'Helvetica','Bitstream Vera Sans', 'DejaVu Sans', 'Lucida Grande',
  24. 'Verdana', 'Geneva', 'Lucid', 'Avant Garde', 'sans-serif']
  25. rc_pub={'font.size': 20, 'axes.labelsize': 20, 'legend.fontsize': 20,
  26. 'axes.titlesize': 25, 'xtick.labelsize': 20, 'ytick.labelsize': 20,
  27. 'axes.linewidth':1.5, 'lines.linewidth': 2.0,
  28. 'xtick.color': 'black', 'ytick.color': 'black', 'axes.edgecolor': 'black',
  29. 'axes.labelcolor':'black','text.color':'black'}
  30. # for publication quality plots
  31. def set_pub_plots(pal=sns.blend_palette(['cyan', 'magenta','gray','crimson','purple'], 5)):
  32. sns.set_style("white")
  33. sns.set_palette(pal)
  34. sns.set_context("poster", font_scale=1.5, rc=rc_pub)
  35. sns.set_style("ticks", {"xtick.major.size": 5, "ytick.major.size": 5})
  36. # to restore the defaults, call plt.rcdefaults()
  37. set_pub_plots()
  38. # %% [markdown]
  39. # # Base variables
  40. # This is primarily base values for ephys data
  41. # %%
  42. insert_depth = 3100 #change this as appropriate
  43. sp_bw_ch = 20/2
  44. surface_ch = np.round(insert_depth/sp_bw_ch)
  45. V1_hip_ch = np.round((insert_depth-1000)/sp_bw_ch)
  46. Hip_thal_ch = np.round((insert_depth-1000-1200)/sp_bw_ch)
  47. CA1_DG_ch = np.round((insert_depth-1000-600)/sp_bw_ch)
  48. samples_tr = 7350 #this is based on the shortest #samples in a trial
  49. sr = 2500
  50. n_chan = 384
  51. rec_length = 3.0 #how long is the arduino triggered
  52. v1_ch = 260
  53. hpc_ch = 110
  54. # %% [markdown]
  55. # # Load ephys data
  56. # output
  57. # - all_trial_lfp <- dataframe of the LFPs for each trial with a 2-d array (#ch x #samp)
  58. # - vr_units <- dataframe of all vr units psth
  59. # - units_fft <- dataframe of all vr units power spectrum analysis
  60. # %% [markdown]
  61. # ## LFP
  62. # %%
  63. all_trial_lfp = pd.read_pickle(r'G:\Neuropixels\02_wtfx_behavior\all_trials.pkl')
  64. display(all_trial_lfp.head())
  65. print(all_trial_lfp.group.unique(), all_trial_lfp.stim_id.unique())
  66. print(all_trial_lfp.groupby('group')['et'].nunique())
  67. # %% [markdown]
  68. # ## Units
  69. # %% [markdown]
  70. # ### PSTH dataframe
  71. # %%
  72. final_df = pd.read_parquet(r"U:\Papers\FX Behavior paper\data\final_V1HPC_OperantNovel_psth.parquet")
  73. vr_units = final_df[final_df.visRes == 'yes']
  74. vr_units.head()
  75. # %%
  76. print(vr_units.region.unique(), vr_units.group.unique(), vr_units.stim_id.unique())
  77. print(vr_units.groupby('group')['et'].nunique())
  78. # %% [markdown]
  79. # ### Create units FFT dataframe
  80. # %%
  81. def get_unit_fft(unit_df):
  82. unit_arr = unit_df[(unit_df.times>0.5)&(unit_df.times<1.8)].zscore.values
  83. freq = np.arange(unit_arr.shape[0]) / unit_arr.shape[0] * 100
  84. freq = freq[:freq.shape[0]//2]
  85. f = np.fft.fft(unit_arr)
  86. magnitude_spectrum = (np.abs(f)[:freq.shape[0]])
  87. return freq, magnitude_spectrum
  88. # %%
  89. units_fft = []
  90. for unit,df in vr_units.groupby(['stim_id','cuid']):
  91. fft_freq, fft_amp = get_unit_fft(df)
  92. bands = [[2,4],[4,8],[8,12],[12,30],[30,70]]
  93. auc_val,band_val = [],[]
  94. for ran in bands:
  95. lower = fft_freq.searchsorted(ran[0], 'left')
  96. upper = fft_freq.searchsorted(ran[1], 'right') -1
  97. val = auc(fft_freq[lower:upper],fft_amp[lower:upper])
  98. auc_val.append(val)
  99. band_val.append(str(ran))
  100. units_fft.append(pd.DataFrame({'band': band_val, 'auc': auc_val, 'cuid': unit[1],
  101. 'stim': unit[0], 'group': df.group.unique()[0],
  102. 'region': df.region.unique()[0], 'et': df.et.unique()[0]}))
  103. units_fft = pd.concat(units_fft)
  104. # %% [markdown]
  105. # # Load behavior data
  106. # output
  107. # - behavior <- dataframe of trials and behavior label for each mouse
  108. # %%
  109. behavior = pd.read_pickle(r"G:\Neuropixels\02_wtfx_behavior\lick_behavior_rec.pkl")
  110. #replace et CC067431_HP3 with CC067432_HP3 (*this was mislabeled originally)
  111. behavior.loc[behavior["et"] == "CC067431_HP3", "et"] = "CC067432_HP3"
  112. #the stim_id col currently on the df is off, update with true stim_id below
  113. behavior = behavior.drop('stim_id', axis=1)
  114. # %%
  115. # Psuedo random presentation of the stimuli - 25 per row * 6 rows = 150 trials
  116. # 0 -- drifting grating, rewarded stimulus, 100 trials
  117. # 1 -- pink noise, unrewarded stimulus, 50 trials
  118. stim_order = [0,1,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,
  119. 0,1,0,1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,0,0,0,0,1,
  120. 0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,0,0,0,0,1,
  121. 0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,
  122. 1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,0,1,1,0,0,
  123. 0,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0]
  124. # Psuedo random distribution of water to the rewarded stimuli
  125. # 0 -- water given -- 80 times
  126. # 1 -- no water given -- 20 times
  127. rew_order = [0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,
  128. 0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,
  129. 0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
  130. 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0]
  131. overall_order, i = {}, 0
  132. for idx,val in enumerate(stim_order):
  133. if val == 0:
  134. if rew_order[i] == 0:
  135. overall_order[idx]='Go+' #rew
  136. elif rew_order[i] == 1:
  137. overall_order[idx]='Go-' #rew2
  138. i+=1
  139. elif val == 1:
  140. overall_order[idx]='No-Go' #unrew
  141. # %%
  142. #update the stim_id column with the overall order dictionary made above
  143. display(behavior.head(2))
  144. behavior['stim_id'] = behavior['true_tr'].map(overall_order)
  145. display(behavior.head(2))
  146. # %%
  147. #add behavior outcome for each trial based on the stimulus and if licked 2+ times from [0, 1.2] sec
  148. beh_ls = []
  149. for d,dd in behavior.groupby(['et','trial']):
  150. lt = dd.lick_time.values
  151. did_lick = True if sum((lt>0)&(lt<1.2))>=2 else False #checks licks that are between [0, 1.2] time window
  152. stim = dd.stim_id.unique()[0]
  153. if stim == 'Go+':
  154. beh_ls.append(['H']*dd.shape[0] if did_lick else ['M']*dd.shape[0])
  155. elif stim == 'Go-':
  156. beh_ls.append(['H']*dd.shape[0] if did_lick else ['M']*dd.shape[0])
  157. else:
  158. beh_ls.append(['FA']*dd.shape[0] if did_lick else ['CR']*dd.shape[0])
  159. behavior['behav'] = list(itertools.chain(*beh_ls)) #itertools flattens the list of lists to add to the dataframe
  160. print(behavior.behav.unique())
  161. behavior.head()
  162. # %% [markdown]
  163. # # Plot the Results (units and behavior)
  164. # %% [markdown]
  165. # ## Combine ephys and behavior
  166. # %%
  167. mouse_beh = []
  168. for d,dd in behavior.groupby(['et','stim_id','behav']):
  169. counts = dd.true_tr.nunique()
  170. tmp_df=pd.DataFrame({'et':[d[0]],
  171. 'stim_id':[d[1]],
  172. 'behav':[d[2]],
  173. 'counts':counts
  174. })
  175. mouse_beh.append(tmp_df)
  176. mouse_beh = pd.concat(mouse_beh, ignore_index=True)
  177. mouse_beh.head(3)
  178. # %%
  179. et_beh_dict = {}
  180. for d,dd in mouse_beh.groupby('et'):
  181. try:
  182. nmH = dd[dd.behav=='H']['counts'].values[0]
  183. except:
  184. nmH = 0
  185. try:
  186. nmM = dd[dd.behav=='M']['counts'].values[0]
  187. except:
  188. nmM = 0
  189. try:
  190. nmCR = dd[dd.behav=='CR']['counts'].values[0]
  191. except:
  192. nmCR = 0
  193. try:
  194. nmFA = dd[dd.behav=='FA']['counts'].values[0]
  195. except:
  196. nmFA = 0
  197. et_beh_dict[d] = [nmH, nmM, nmCR, nmFA] #build dict like this "{et: [nmH, nmM, nmCR, nmFA]}" to map to below df
  198. # %%
  199. # map dict above with the df above above to give 4 new columns (nmH, nmM, nmCR, nmFA)
  200. units_fft['nmH'] = units_fft.et.map(lambda x: et_beh_dict[x][0])
  201. units_fft['nmM'] = units_fft.et.map(lambda x: et_beh_dict[x][1])
  202. units_fft['nmCR'] = units_fft.et.map(lambda x: et_beh_dict[x][2])
  203. units_fft['nmFA'] = units_fft.et.map(lambda x: et_beh_dict[x][3])
  204. # %%
  205. # take the mean AUC across the units for each mouse
  206. theta_fft = units_fft[(units_fft.band=='[4, 8]')]
  207. theta_fft = theta_fft[(theta_fft.stim==0) | (theta_fft.stim==2)]
  208. mean_theta = []
  209. for d,dd in theta_fft.groupby(['group','et','stim','region','band']):
  210. mean_theta.append({'mean_auc':dd.auc.mean(), 'median_auc':dd.auc.median(),
  211. 'group':d[0], 'et':d[1], 'stim':d[2], 'region':d[3], 'band':d[4],
  212. 'nmH':dd.nmH.unique()[0], 'nmM':dd.nmM.unique()[0], 'nmCR':dd.nmCR.unique()[0], 'nmFA':dd.nmFA.unique()[0]})
  213. mean_theta = pd.DataFrame(mean_theta)
  214. mean_theta.head(3)
  215. # %% [markdown]
  216. # ## Plot it
  217. # %%
  218. y_choice = 'mean_auc' # mean_auc & median_auc
  219. for x_choice in ["nmH", "nmM", "nmCR", "nmFA"]:
  220. sns.relplot(data=mean_theta, x=x_choice, y=y_choice, hue='group', col='stim', row='region',
  221. palette={'WT':'cyan', 'FX':'magenta'}, height=4, aspect=1.2)
  222. plt.show()
  223. for d,dd in mean_theta.groupby('stim'):
  224. print(f"~~~~~~~~~~ {d} ~~~~~~~~~~")
  225. sns.relplot(data=dd, x='nmH', y='mean_auc',
  226. col='behav', row='region',
  227. hue='group', palette={'WT':'cyan', 'FX':'magenta'},
  228. height=3, facet_kws={'sharey': True, 'sharex': False})
  229. plt.suptitle(d)
  230. plt.show()
  231. # %% [markdown]
  232. # # Plot the results (LFP and behavior)
  233. # %%
  234. display(all_trial_lfp.head(2))
  235. display(behavior.head(2))
  236. # %% [markdown]
  237. # ## LFP traces and licks (all mice all trials)
  238. # %%
  239. v1_ch = 260
  240. hpc_ch = 110
  241. show_plots = False
  242. lfp_behav, i = [], 0
  243. # plot the single trial veps with the licks overlaid
  244. for d,dd in all_trial_lfp.groupby(['et','trial']):
  245. #gets the v1 lfp trace for the et/trial pairing
  246. tr_stim = dd.stim_id.unique()[0]
  247. plt_stim = 'Go+' if tr_stim=='0' else ('Go-' if tr_stim=='1' else 'No-Go')
  248. tr_lfp = dd.lfp_data.values[0]
  249. v1_lfp = tr_lfp[v1_ch,:]
  250. hpc_lfp = tr_lfp[hpc_ch,:]
  251. #trims the behavior df to the et/trial pairing
  252. tmp0 = behavior[(behavior.et==d[0])&(behavior.true_tr==d[1])&(behavior.lick_time>-0.5)&(behavior.lick_time<2.5)]
  253. tmp = tmp0['lick_time'].values+0.5 #lick times now zeroed to start of recording
  254. num_licks = len([x for x in tmp if (x>1.0)&(x<1.7)]) #counting the number of licks within the delay period
  255. tr_beh = tmp0.behav.unique()[0] if tmp0.size else ('CR' if plt_stim=='No-Go' else 'M') #OR else 'nolick'
  256. #save to new df --- columns = trial, et, group, stim_id, v1_lfp, hpc_lfp, num_licks, behav
  257. lfp_behav.append([d[1], d[0], dd.group.unique()[0], plt_stim, v1_lfp.astype('float16'), hpc_lfp.astype('float16'), num_licks, tr_beh])
  258. #plot the lfp traces and the licks overlaid
  259. if show_plots==False:
  260. if i%500 == 0:
  261. print(f"Done with {i} out of {all_trial_lfp.et.nunique()*all_trial_lfp.trial.nunique()}") #loading bar if not plotting LFPs and lick rasters
  262. i+=1
  263. else:
  264. x_times = np.linspace(0,3,v1_lfp.shape[0])
  265. plt_color = 'cyan' if dd.group.unique()[0]=='WT' else 'magenta'
  266. fig,ax = plt.subplots(1,2, sharex=True, figsize=(15,2.5))
  267. ax[0].axvspan(0.5,0.7, color='grey', alpha=0.2)
  268. ax[1].axvspan(0.5,0.7, color='grey', alpha=0.2)
  269. if plt_stim=='Go+':
  270. ax[0].axvline(1.7, color='royalblue')
  271. ax[1].axvline(1.7, color='royalblue')
  272. elif plt_stim=='Go-':
  273. ax[0].axvline(1.7, color='grey')
  274. ax[1].axvline(1.7, color='grey')
  275. else:
  276. ax[0].axvline(1.7, color='grey', ls='--')
  277. ax[1].axvline(1.7, color='grey', ls='--')
  278. ax[0].plot(x_times, scnd.gaussian_filter1d(v1_lfp, sigma=20), color=plt_color) #plot gaussian filtered V1 vep
  279. ax[0].scatter(x=tmp, y=[-500]*len(tmp), marker='|', c='black', s=70) #plot licks
  280. ax[1].plot(x_times, scnd.gaussian_filter1d(hpc_lfp, sigma=20), color=plt_color) #plot gaussian filtered V1 vep
  281. ax[1].scatter(x=tmp, y=[-800]*len(tmp), marker='|', c='black', s=70) #plot licks
  282. ax[0].set_xlabel('Time (s)')
  283. ax[1].set_xlabel('Time (s)')
  284. ax[0].set_ylabel('V1')
  285. ax[0].set_ylim([-600,600])
  286. ax[1].set_ylim([-900,900])
  287. ax[0].set_title(f"{d[0]} ~~ Trial {d[1]} ~~ {plt_stim} ~~ {tr_beh}")
  288. ax[1].set_ylabel('HPC')
  289. sns.despine()
  290. plt.show()
  291. lfp_behav = pd.DataFrame(lfp_behav, columns=['trial','et','group','stim_id','v1_lfp','hpc_lfp','num_licks','behav'])
  292. # %% [markdown]
  293. # ## LFP oscillation FFT and behavior
  294. # %%
  295. def get_lfp_fft(lfp_arr, sr=2500, limit_time=False):
  296. if limit_time:
  297. time_cut_arr = lfp_arr[int(sr*limit_time[0]):int(sr*limit_time[1])] #limits the LFP trace to [0.5, 1.7] and quantify power on that time
  298. else:
  299. time_cut_arr = lfp_arr
  300. freq = np.arange(time_cut_arr.shape[0]) / time_cut_arr.shape[0] * sr #sr of the lfp traces
  301. freq = freq[:freq.shape[0]//2]
  302. f = np.fft.fft(time_cut_arr)
  303. magnitude_spectrum = (np.abs(f)[:freq.shape[0]])
  304. return freq, magnitude_spectrum
  305. # %%
  306. lfp_fft = []
  307. for lfp,df in lfp_behav.groupby(['et','trial']):
  308. # for lfp,df in lfp_behav[lfp_behav.trial<100].groupby(['et','trial']): #limit the # of trials to account for loss of motivation in later ones? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  309. fft_freq, fft_amp = get_lfp_fft(df.v1_lfp.values[0], limit_time=[0.5,1.8])
  310. bands = [[2,4],[4,8],[8,12],[12,30],[30,70]]
  311. auc_val,band_val,mean_ls,peak_val = [],[],[],[]
  312. for ran in bands:
  313. lower = fft_freq.searchsorted(ran[0], 'left')
  314. upper = fft_freq.searchsorted(ran[1], 'right') -1
  315. val = auc(fft_freq[lower:upper],fft_amp[lower:upper])
  316. mean_val = np.mean(fft_amp[lower:upper])
  317. peak = np.max(fft_amp[lower:upper])
  318. auc_val.append(val/100000) #scale factor for the auc values
  319. mean_ls.append(mean_val/10000)
  320. peak_val.append(peak/10000)
  321. band_val.append(str(ran))
  322. lfp_fft.append(pd.DataFrame({'trial':lfp[1], 'band':band_val, 'mean_val':mean_ls, 'peak_val':peak_val, 'auc':auc_val, 'et':lfp[0], 'region':'V1',
  323. 'group':df.group.unique()[0], 'stim_id':df.stim_id.unique()[0], 'num_licks':df.num_licks.unique()[0], 'behav':df.behav.unique()[0]}))
  324. #repeat above for the HPC channel
  325. fft_freq, fft_amp = get_lfp_fft(df.hpc_lfp.values[0], limit_time=[0.5,1.8])
  326. auc_val,band_val,mean_ls,peak_val = [],[],[],[]
  327. for ran in bands:
  328. lower = fft_freq.searchsorted(ran[0], 'left')
  329. upper = fft_freq.searchsorted(ran[1], 'right') -1
  330. val = auc(fft_freq[lower:upper],fft_amp[lower:upper])
  331. mean_val = np.mean(fft_amp[lower:upper])
  332. peak = np.max(fft_amp[lower:upper])
  333. auc_val.append(val/100000)
  334. mean_ls.append(mean_val/10000)
  335. peak_val.append(peak/10000)
  336. band_val.append(str(ran))
  337. lfp_fft.append(pd.DataFrame({'trial':lfp[1], 'band':band_val, 'mean_val':mean_ls, 'peak_val':peak_val, 'auc':auc_val, 'et':lfp[0], 'region':'HPC',
  338. 'group':df.group.unique()[0], 'stim_id':df.stim_id.unique()[0], 'num_licks':df.num_licks.unique()[0], 'behav':df.behav.unique()[0]}))
  339. lfp_fft = pd.concat(lfp_fft)
  340. # replace instances of H2 & M2 with H & M
  341. lfp_fft['behav'] = lfp_fft['behav'].replace(['H2','M2'], ['H','M'])
  342. lfp_fft.head()
  343. # %% [markdown]
  344. # ## Plotting results of all trials
  345. # N = #trials
  346. # %%
  347. do_plot=False
  348. feature_choice = 'peak_val'
  349. for d,dd in lfp_fft.groupby(['stim_id','region']):
  350. if do_plot:
  351. fig,ax = plt.subplots(1,2, sharex=True, figsize=(15,3.5))
  352. plt_order = ['CR','FA'] if d[0]=='No-Go' else ['H','M']
  353. print("2-sided KS test comparing the distributions of WT & FX")
  354. for i,b in enumerate(plt_order):
  355. plt_df = dd[(dd.band=="[4, 8]")&(dd.behav==b)]
  356. x,y = plt_df[plt_df.group=='WT'][feature_choice].values, plt_df[plt_df.group=='FX'][feature_choice].values
  357. res = sstat.ks_2samp(x,y)
  358. plt_stats = "***" if res.pvalue < 0.001 else ("**" if res.pvalue<0.01 else ("*" if res.pvalue <0.05 else "ns"))
  359. if do_plot:
  360. sns.histplot(data=plt_df, x=feature_choice, binwidth=1,
  361. hue='group', hue_order=['WT','FX'],
  362. stat='density', common_norm=False,
  363. kde=True, legend=False, ax=ax[i])
  364. ax[i].set_title(f"{d} ~~ {b}")
  365. if feature_choice == 'peak_val':
  366. ax[i].text(x=25, y=0.06, s=plt_stats)
  367. else:
  368. ax[i].text(x=6, y=0.2, s=plt_stats)
  369. print(f"{d} {b} -- N: WT={len(x)}, F={len(y)} -- p={res.pvalue} --", plt_stats)
  370. if do_plot:
  371. sns.despine()
  372. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUChistogram_{d}.pdf", transparent=True)
  373. plt.show()
  374. # %%
  375. for d,dd in lfp_fft.groupby('stim_id'):
  376. aver_df = dd[dd.band=="[4, 8]"]
  377. plt_order = ['CR','FA'] if d=='No-Go' else ['H','M']
  378. sns.catplot(data=aver_df, x='behav', y='mean_val', kind='bar', col='region', order=plt_order,
  379. hue='group', hue_order=['WT','FX'], palette={'WT':'cyan','FX':'magenta'},
  380. height=3.5, aspect=1)
  381. # plt.ylim([0,6.5])
  382. plt.suptitle(d)
  383. sns.despine()
  384. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUCbarplot_{d}.pdf", transparent=True)
  385. plt.show()
  386. # %%
  387. feature_choice = 'peak_val'
  388. #Mann Whitney U to compare pairwise within each band for each region
  389. print('~~~~~~~~~~~~ Comparing WT/FX for each region/stim/behav ~~~~~~~~~~~~')
  390. for d,dd in lfp_fft[lfp_fft.band=="[4, 8]"].groupby(['region','stim_id','behav']):
  391. x,y = dd[dd.group=='WT'][feature_choice].values, dd[dd.group=='FX'][feature_choice].values
  392. U,pval = sstat.mannwhitneyu(x,y)
  393. print(f"{d} -- N (#trials, all mice): WT={len(x)}, FX={len(y)} -- pvals: {pval} -- ",
  394. '***' if pval<0.001 else ('**' if pval<0.01 else ('*' if pval<0.05 else 'ns')))
  395. #Mann Whitney U to compare pairwise within each group for each region
  396. print('\n~~~~~~~~~~~~ Comparing behav for each region/stim/group ~~~~~~~~~~~~')
  397. for d,dd in lfp_fft[lfp_fft.band=="[4, 8]"].groupby(['region','stim_id','group']):
  398. beh = dd.behav.unique()
  399. x,y = dd[dd.behav==beh[0]][feature_choice].values, dd[dd.behav==beh[1]][feature_choice].values
  400. U,pval = sstat.mannwhitneyu(x,y)
  401. print(f"{d} -- N (#trials, all mice): WT={len(x)}, FX={len(y)} -- pvals: {pval} -- ",
  402. '***' if pval<0.001 else ('**' if pval<0.01 else ('*' if pval<0.05 else 'ns')))
  403. # %% [markdown]
  404. # # Remake df, grouped by mouse
  405. # This is for each mouse, meaning my N = #mice NOT #trials like above
  406. # %%
  407. trial_lims = [0,150]
  408. lfp_avg_fft = []
  409. for d,dd in lfp_fft[(lfp_fft.trial>=trial_lims[0])&(lfp_fft.trial<=trial_lims[1])].groupby(['et','region','band','group','stim_id','behav']):
  410. lfp_avg_fft.append(pd.DataFrame({'band':d[2], 'auc':dd.auc.mean(), 'peak_val':dd.peak_val.mean(), 'mean_val':dd.mean_val.mean(),
  411. 'et':d[0], 'region':d[1], 'group':d[3], 'stim_id':d[4], 'behav':d[5]}, index=[0]))
  412. lfp_avg_fft = pd.concat(lfp_avg_fft, ignore_index=True)
  413. lfp_avg_fft.head()
  414. # %% [markdown]
  415. # # other ideas...
  416. # %%
  417. # remove mice that are inactive (less than n HIT trials)
  418. active_ets = []
  419. for d,dd in lfp_fft[lfp_fft.band=='[4, 8]'].groupby('et'):
  420. num_Hits = dd.groupby('behav').trial.nunique().to_dict()['H'] if 'H' in dd.groupby('behav').trial.nunique().to_dict() else 0
  421. if num_Hits>=5:
  422. active_ets.append(d)
  423. active_ets.remove("CC067489_HP2") #removing an outlier found from the plots below
  424. print(active_ets)
  425. # %% [markdown]
  426. # # Previous plot - histogram
  427. # %%
  428. feature_choice = 'auc' #'auc', 'mean_val', 'peak_val'
  429. for d,dd in lfp_avg_fft[lfp_avg_fft.et.isin(active_ets)].groupby('stim_id'):
  430. plt_data = dd[dd.band=='[4, 8]']
  431. sns.displot(data=plt_data, x=feature_choice, hue='group', hue_order=['WT','FX'],
  432. kde=True, rug=False, stat='density', binwidth=0.35, col='behav', row='region', height=4, aspect=1.2)
  433. plt.ylim([0,0.26])
  434. plt.xlim([0,5])
  435. plt.suptitle(d)
  436. print("2-sided KS test comparing the distributions of WT & FX")
  437. for e,ee in plt_data.groupby(['region','behav']):
  438. x,y = ee[ee.group=='WT'][feature_choice].values, ee[ee.group=='FX'][feature_choice].values # N = #mice bc behavior outcome is separate (ie Go+ has Hit and Miss)
  439. res = sstat.ks_2samp(x,y)
  440. plt_stats = "***" if res.pvalue < 0.001 else ("**" if res.pvalue<0.01 else ("*" if res.pvalue <0.05 else "ns"))
  441. print(f"{d} {e} -- N: WT={len(x)}, F={len(y)} -- p={res.pvalue} --", plt_stats)
  442. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUChistogram_{d}.pdf", transparent=True)
  443. plt.show()
  444. # %%
  445. feature_choice = 'auc' #'auc', 'mean_val', 'peak_val'
  446. for d,dd in lfp_avg_fft[lfp_avg_fft.et.isin(active_ets)].groupby('stim_id'):
  447. plt_data = dd[dd.band=='[4, 8]']
  448. sns.displot(data=plt_data, x=feature_choice, hue='behav', palette={'H':'royalblue','M':'grey','CR':'royalblue','FA':'grey'},
  449. kde=True, rug=False, stat='density', binwidth=0.35, col='group', row='region', height=4, aspect=1.2)
  450. plt.ylim([0,0.26])
  451. plt.xlim([0,5])
  452. plt.suptitle(d)
  453. print("2-sided KS test comparing the distributions of behavior within group")
  454. for e,ee in plt_data.groupby(['region','group']):
  455. if (d=='Go+')|(d=='Go-'):
  456. x,y = ee[ee.behav=='H'][feature_choice].values, ee[ee.behav=='M'][feature_choice].values # N = #mice bc behavior outcome is separate (ie Go+ has Hit and Miss)
  457. else:
  458. x,y = ee[ee.behav=='CR'][feature_choice].values, ee[ee.behav=='FA'][feature_choice].values
  459. res = sstat.ks_2samp(x,y)
  460. plt_stats = "***" if res.pvalue < 0.001 else ("**" if res.pvalue<0.01 else ("*" if res.pvalue <0.05 else "ns"))
  461. print(f"{d} {e} -- N: WT={len(x)}, F={len(y)} -- p={res.pvalue} --", plt_stats)
  462. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUChistogram_{d}.pdf", transparent=True)
  463. plt.show()
  464. # %% [markdown]
  465. # # ! Previous plot - scatter (trial # and AUC, split by behavior)
  466. # %%
  467. feature_choice = 'auc' #'auc', 'mean_val', 'peak_val'
  468. for d,dd in lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et.isin(active_ets))].groupby(['region','stim_id']):
  469. behav_ls = dd.behav.unique()
  470. fig,ax=plt.subplots(1,2,figsize=(14,3), sharey=True)
  471. wt_beh_thresh = dd[dd.group=='WT'][feature_choice].mean() + dd[dd.group=='WT'][feature_choice].std() #mean + 1std to use as the threshold for WT
  472. fx_beh_thresh = dd[dd.group=='FX'][feature_choice].mean() + dd[dd.group=='FX'][feature_choice].std() #mean + 1std to use as the threshold for FX
  473. ax[0].hlines(y=[wt_beh_thresh, fx_beh_thresh], xmin=0, xmax=150, colors=['cyan','magenta'], ls='--')
  474. ax[1].hlines(y=[wt_beh_thresh, fx_beh_thresh], xmin=0, xmax=150, colors=['cyan','magenta'], ls='--')
  475. sns.scatterplot(data=dd[dd.behav==behav_ls[0]], x='trial', y=feature_choice, s=50, hue='group', palette={'WT':'cyan', 'FX':'magenta'}, ax=ax[0], legend=False)
  476. sns.scatterplot(data=dd[dd.behav==behav_ls[1]], x='trial', y=feature_choice, s=50, hue='group', palette={'WT':'cyan', 'FX':'magenta'}, ax=ax[1], legend=False)
  477. ax[0].set_title(f'{d} -- {behav_ls[0]}')
  478. ax[1].set_title(f'{d} -- {behav_ls[1]}')
  479. ax[0].set_xlim([-1,151])
  480. ax[1].set_xlim([-1,151])
  481. ax[0].set_ylim([0,6.5])
  482. ax[1].set_ylim([0,6.5])
  483. ax[0].set_xlabel('Trial')
  484. ax[0].set_ylabel('AUC (a.u.)')
  485. ax[1].set_xlabel('Trial')
  486. sns.despine()
  487. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUCscatterplot_{d[0]}_{d[1]}_v2.pdf", transparent=True)
  488. plt.show()
  489. # %%
  490. # make the same threshold for each stimulus group, not each stimulus/behavior group
  491. feature_choice = 'auc' #'auc', 'mean_val', 'peak_val'
  492. group_thresh = True
  493. for d,dd in lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et.isin(active_ets))].groupby(['region','stim_id']):
  494. if d[1] == 'No-Go':
  495. behav_ls = ['CR', 'FA']
  496. else:
  497. behav_ls = ['H', 'M']
  498. fig,ax=plt.subplots(2,2,figsize=(14,6), sharey=True)
  499. ax=ax.flatten()
  500. if group_thresh:
  501. wt_beh_thresh = dd[dd.group=='WT'][feature_choice].mean() + dd[dd.group=='WT'][feature_choice].std() #mean + 1std to use as the threshold for WT
  502. fx_beh_thresh = dd[dd.group=='FX'][feature_choice].mean() + dd[dd.group=='FX'][feature_choice].std() #mean + 1std to use as the threshold for FX
  503. # ax[0].hlines(y=[wt_beh_thresh,fx_beh_thresh], xmin=0, xmax=150, colors=['cyan','magenta'], ls='--')
  504. # ax[1].hlines(y=[wt_beh_thresh,fx_beh_thresh], xmin=0, xmax=150, colors=['cyan','magenta'], ls='--')
  505. ax[0].hlines(y=[wt_beh_thresh], xmin=0, xmax=150, colors=['cyan'], ls='--')
  506. ax[1].hlines(y=[wt_beh_thresh], xmin=0, xmax=150, colors=['cyan'], ls='--')
  507. ax[2].hlines(y=[fx_beh_thresh], xmin=0, xmax=150, colors=['magenta'], ls='--')
  508. ax[3].hlines(y=[fx_beh_thresh], xmin=0, xmax=150, colors=['magenta'], ls='--')
  509. else:
  510. beh_thresh = dd[feature_choice].mean() + (1.5*dd[feature_choice].std()) #mean + 1.5std to use as the threshold for FX
  511. ax[0].axhline(y=beh_thresh, color='grey', ls='--')
  512. ax[1].axhline(y=beh_thresh, color='grey', ls='--')
  513. # sns.scatterplot(data=dd[dd.behav==behav_ls[0]], x='trial', y=feature_choice, s=50, hue='group', palette={'WT':'cyan', 'FX':'magenta'}, ax=ax[0], legend=False)
  514. # sns.scatterplot(data=dd[dd.behav==behav_ls[1]], x='trial', y=feature_choice, s=50, hue='group', palette={'WT':'cyan', 'FX':'magenta'}, ax=ax[1], legend=False)
  515. sns.lineplot(data=dd[(dd.behav==behav_ls[0])&(dd.group=='WT')], x='trial', y=feature_choice, hue='et', palette='tab10', ax=ax[0], legend=False)
  516. sns.lineplot(data=dd[(dd.behav==behav_ls[1])&(dd.group=='WT')], x='trial', y=feature_choice, hue='et', palette='tab10', ax=ax[1], legend=False)
  517. sns.lineplot(data=dd[(dd.behav==behav_ls[0])&(dd.group=='FX')], x='trial', y=feature_choice, hue='et', palette='tab10', ax=ax[2], legend=False)
  518. sns.lineplot(data=dd[(dd.behav==behav_ls[1])&(dd.group=='FX')], x='trial', y=feature_choice, hue='et', palette='tab10', ax=ax[3], legend=False)
  519. ax[0].set_title(f'{d} -- {behav_ls[0]}')
  520. ax[1].set_title(f'{d} -- {behav_ls[1]}')
  521. # ax[0].set_xlim([-1,151])
  522. # ax[1].set_xlim([-1,151])
  523. # ax[0].set_ylim([0,6.5])
  524. # ax[1].set_ylim([0,6.5])
  525. # ax[0].set_xlabel('Trial')
  526. # ax[0].set_ylabel('AUC (a.u.)')
  527. # ax[1].set_xlabel('Trial')
  528. sns.despine()
  529. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\allTrial_AUCscatterplot_{d[0]}_{d[1]}.pdf", transparent=True)
  530. plt.show()
  531. # %% [markdown]
  532. # # ! Threshold and find probability of Hit or Miss above mean+1std
  533. # %%
  534. num_std = 1
  535. feature_choice = 'auc' #'auc', 'mean_val', 'peak_val'
  536. above_thresh_df = []
  537. for d,dd in lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et.isin(active_ets))].groupby(['region','stim_id']):
  538. wt_dd, fx_dd = dd[dd.group=='WT'], dd[dd.group=='FX']
  539. wt_beh_thresh = wt_dd[feature_choice].mean() + (num_std*wt_dd[feature_choice].std()) #mean + Xstd to use as the threshold for WT
  540. fx_beh_thresh = fx_dd[feature_choice].mean() + (num_std*fx_dd[feature_choice].std()) #mean + Xstd to use as the threshold for FX
  541. wt_above = wt_dd[wt_dd[feature_choice]>=wt_beh_thresh]
  542. for e,ee in wt_above.groupby('et'):
  543. tot_trls = ee.trial.nunique()
  544. corr_perc = (ee[ee.behav=='CR']['trial'].nunique())/tot_trls*100 if d[1]=='No-Go' else (ee[ee.behav=='H']['trial'].nunique())/tot_trls*100
  545. corr_auc = ee[ee.behav=='CR'][feature_choice].mean() if d[1]=='No-Go' else ee[ee.behav=='H'][feature_choice].mean()
  546. incorr_auc = ee[ee.behav=='FA'][feature_choice].mean() if d[1]=='No-Go' else ee[ee.behav=='M'][feature_choice].mean()
  547. above_thresh_df.append(pd.DataFrame({'region':d[0], 'stim_id':d[1], 'group':ee.group.unique(), 'et':e,
  548. 'perc':corr_perc, 'corr_auc':corr_auc, 'incorr_auc':incorr_auc, 'behav':'H/CR'}))
  549. above_thresh_df.append(pd.DataFrame({'region':d[0], 'stim_id':d[1], 'group':ee.group.unique(), 'et':e,
  550. 'perc':100-corr_perc, 'corr_auc':corr_auc, 'incorr_auc':incorr_auc, 'behav':'M/FA'}))
  551. fx_above = fx_dd[fx_dd[feature_choice]>=fx_beh_thresh]
  552. for e,ee in fx_above.groupby('et'):
  553. tot_trls = ee.trial.nunique()
  554. corr_perc = (ee[ee.behav=='CR']['trial'].nunique())/tot_trls*100 if d[1]=='No-Go' else (ee[ee.behav=='H']['trial'].nunique())/tot_trls*100
  555. corr_auc = ee[ee.behav=='CR'][feature_choice].mean() if d[1]=='No-Go' else ee[ee.behav=='H'][feature_choice].mean()
  556. incorr_auc = ee[ee.behav=='FA'][feature_choice].mean() if d[1]=='No-Go' else ee[ee.behav=='M'][feature_choice].mean()
  557. above_thresh_df.append(pd.DataFrame({'region':d[0], 'stim_id':d[1], 'group':ee.group.unique(), 'et':e,
  558. 'perc':corr_perc, 'corr_auc':corr_auc, 'incorr_auc':incorr_auc, 'behav':'H/CR'}))
  559. above_thresh_df.append(pd.DataFrame({'region':d[0], 'stim_id':d[1], 'group':ee.group.unique(), 'et':e,
  560. 'perc':100-corr_perc, 'corr_auc':corr_auc, 'incorr_auc':incorr_auc, 'behav':'M/FA'}))
  561. above_thresh_df = pd.concat(above_thresh_df, ignore_index=True)
  562. above_thresh_df.head()
  563. # %%
  564. num_std = 1.5 # standard deviation you want to have contained within the ellipse
  565. dot_size = 50 # aesthetic choice for the size of the scatter plot dots
  566. plot_linReg = True
  567. pt1_above_thresh_df = above_thresh_df[above_thresh_df.behav=="H/CR"]
  568. idx=0
  569. fig,ax = plt.subplots(1,2, figsize=(10,3), sharey=True, sharex=True)
  570. for d,dd in pt1_above_thresh_df.groupby("region"): # THIS IS INCORPORATING BOTH THE GO AND NO_GO TRIALS TOGETHER FOR THE CORRECT RESPONSES ONLY
  571. dd = dd.dropna()
  572. x = dd[(dd.group=='WT')]['perc'].values
  573. y = dd[(dd.group=='WT')]['corr_auc'].values
  574. x1 = dd[(dd.group=='FX')]['perc'].values
  575. y1 = dd[(dd.group=='FX')]['corr_auc'].values
  576. # plot linear regression of the points & print R**2 value of the fit
  577. if plot_linReg:
  578. res, res1 = sstat.linregress(x, y), sstat.linregress(x1, y1)
  579. print(f"------------- {d} -------------")
  580. print(f'Slope: WT {res.slope:.6f}, FX {res1.slope:.6f}')
  581. print(f'R squared: WT {res.rvalue**2:.6f}, FX {res1.rvalue**2:.6f}')
  582. print(f'pval: WT {res.pvalue:.6f}, FX {res1.pvalue:.6f}')
  583. ax[idx].plot(x, res.intercept+res.slope*x, color='cyan')
  584. ax[idx].plot(x1, res1.intercept+res1.slope*x1, color='magenta')
  585. # Plot scatter
  586. ax[idx].scatter(x, y, s=dot_size, edgecolors=None, color='cyan', label='WT')
  587. ax[idx].scatter(x1, y1, s=dot_size, edgecolors=None, color='magenta', label='FX')
  588. ax[idx].set_xlabel("Correct %")
  589. ax[idx].set_ylabel('Theta AUC')
  590. ax[idx].set_title(d)
  591. idx+=1
  592. sns.despine()
  593. plt.show()
  594. # %%
  595. # the results above show a significant correlation with correct behavior response and Theta AUC for WT V1!! this is in theresholded trials above mean+1std
  596. # %%
  597. g = sns.catplot(data=above_thresh_df, x='behav', y='perc', kind='bar', hue='group', row='region', row_order=['V1', 'HPC'], col='stim_id', errorbar='se', height=3.5, aspect=1.1)
  598. g.set(xlabel='', ylabel='% of Trials')
  599. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\barplot_thresholdTrialPercent.pdf", transparent=True)
  600. plt.show()
  601. print('----------- WT/FX -----------') # stats for comparing WT/FX
  602. for d,dd in above_thresh_df.groupby(["region","stim_id"]):
  603. for e,ee in dd.groupby('behav'):
  604. x,y = ee[ee.group=='WT'].perc.values, ee[ee.group=='FX'].perc.values
  605. num_x,num_y = ee[ee.group=='WT'].et.nunique(), ee[ee.group=='FX'].et.nunique()
  606. u,p = sstat.mannwhitneyu(x,y)
  607. print(d,e,num_x,num_y,p,"***" if p<0.001 else ("**" if p<0.01 else "*" if p<0.05 else "ns"))
  608. print('----------- C/IC -----------') # stats for comparing within group
  609. for d,dd in above_thresh_df.groupby(["region","stim_id"]):
  610. for e,ee in dd.groupby('group'):
  611. x,y = ee[ee.behav=='H/CR'].perc.values, ee[ee.behav=='M/FA'].perc.values
  612. num_x,num_y = ee[ee.behav=='H/CR'].et.nunique(), ee[ee.behav=='M/FA'].et.nunique()
  613. u,p = sstat.mannwhitneyu(x,y)
  614. print(d,e,num_x,num_y,p,"***" if p<0.001 else ("**" if p<0.01 else "*" if p<0.05 else "ns"))
  615. # %% [markdown]
  616. # # Logistic regression on the trial by trial data - MZ 03.07.25
  617. # %%
  618. from sklearn.model_selection import train_test_split
  619. from sklearn.preprocessing import StandardScaler
  620. from sklearn.linear_model import LogisticRegression
  621. from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, roc_curve, auc
  622. import statsmodels.api as sm
  623. theta_lfp_fft = lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et.isin(active_ets))]
  624. theta_lfp_fft.head(2)
  625. # %%
  626. is_plot = True
  627. run_stats = True
  628. for d,dd in theta_lfp_fft.groupby(['group', 'region']): #combine all Go and No-Go trials together
  629. # for d,dd in theta_lfp_fft[theta_lfp_fft.stim_id!='No-Go'].groupby(['group','region']): #Only look at Go trials
  630. # for d,dd in theta_lfp_fft[theta_lfp_fft.stim_id=='No-Go'].groupby(['group','region']): #Only look at No-Go trials
  631. X = dd.auc.to_numpy().reshape(-1,1)
  632. foo = dd.behav.values
  633. y_binary = np.select([foo=='H', foo=='M', foo=='CR', foo=='FA'], [1,0,1,0], foo).astype('int32') #replace behavior with 1 or 0 if correct or incorrect (BOTH GO AND NO-GO INCLUDED)
  634. # Split the data into training and testing sets
  635. X_train, X_test, y_train, y_test = train_test_split(X, y_binary, test_size=0.2, random_state=42)
  636. # Standardize features
  637. scaler = StandardScaler()
  638. X_train = scaler.fit_transform(X_train)
  639. X_test = scaler.transform(X_test)
  640. # Train the Logistic Regression model
  641. model = LogisticRegression()
  642. model.fit(X_train, y_train)
  643. # Evaluate the model
  644. y_pred = model.predict(X_test)
  645. accuracy = accuracy_score(y_test, y_pred)
  646. if run_stats:
  647. X = dd.auc.to_numpy().reshape(-1,1)
  648. foo = dd.behav.values
  649. y_binary = np.select([foo=='H', foo=='M', foo=='CR', foo=='FA'], [1,0,1,0], foo).astype('int32') #replace behavior outcome with 1 or 0
  650. # Split the data into training and testing sets
  651. X_train, X_test, y_train, y_test = train_test_split(X, y_binary, test_size=0.2, random_state=42)
  652. # building the model and fitting the data
  653. log_reg = sm.Logit(y_train, X_train).fit()
  654. pstar = '***' if log_reg.pvalues < 0.001 else ('**' if log_reg.pvalues < 0.01 else ('*' if log_reg.pvalues < 0.05 else 'ns'))
  655. print(log_reg.summary())
  656. print(f"pvals: {log_reg.pvalues} -- {pstar}\n")
  657. if is_plot:
  658. # Plot logistic regression fit Curve
  659. fig,ax = plt.subplots(1,3, figsize=(13,4))
  660. data = pd.DataFrame({'auc': dd.auc.to_numpy(), 'behav': y_binary})
  661. sns.regplot(x=data['auc'], y=data['behav'], data=data, logistic=True, ci=None, color="cyan" if d[0]=='WT' else 'magenta',
  662. scatter_kws={'s': 10}, line_kws={'color': 'gray'}, ax=ax[0])
  663. ax[0].set_title(d)
  664. ax[0].set_xlim([0,9])
  665. sns.despine(ax=ax[0])
  666. # Plot ROC Curve
  667. y_prob = model.predict_proba(X_test)[:, 1]
  668. fpr, tpr, thresholds = roc_curve(y_test, y_prob)
  669. roc_auc = auc(fpr, tpr)
  670. ax[1].plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC Curve (AUC = {roc_auc:.2f})')
  671. ax[1].plot([0, 1], [0, 1], color='grey', lw=2, linestyle='--', label='Random')
  672. ax[1].set_xlabel('False Positive Rate')
  673. ax[1].set_ylabel('True Positive Rate')
  674. ax[1].set_title(f'Accuracy: {accuracy * 100:.2f}%')
  675. sns.despine(ax=ax[1])
  676. # Confusion matrix
  677. cm = confusion_matrix(y_test, y_pred)
  678. print(cm)
  679. sns.heatmap(cm, annot=True, fmt='d', cmap='Blues' if d[0]=='WT' else 'Reds', ax=ax[2])
  680. ax[2].set_xlabel('Predicted')
  681. ax[2].set_ylabel('Actual')
  682. plt.tight_layout()
  683. plt.show()
  684. # %%
  685. # similar code to the above cell, just doesn't plot and saves accuracy values to a DataFrame
  686. accuracy_ls = []
  687. for stim in ['Go', 'No-Go']:
  688. if stim == 'Go':
  689. foo_df = theta_lfp_fft[theta_lfp_fft.stim_id!='No-Go']
  690. else:
  691. foo_df = theta_lfp_fft[theta_lfp_fft.stim_id=='No-Go']
  692. for d,dd in foo_df.groupby(['group', 'region', 'et']): #combine all Go and No-Go trials together
  693. try:
  694. X = dd.auc.to_numpy().reshape(-1,1)
  695. foo = dd.behav.values
  696. y_binary = np.select([foo=='H', foo=='M', foo=='CR', foo=='FA'], [1,0,1,0], foo).astype('int32') #replace behavior with 1 or 0 if correct or incorrect (BOTH GO AND NO-GO INCLUDED)
  697. # Split the data into training and testing sets
  698. X_train, X_test, y_train, y_test = train_test_split(X, y_binary, test_size=0.2, random_state=42)
  699. # Standardize features
  700. scaler = StandardScaler()
  701. X_train = scaler.fit_transform(X_train)
  702. X_test = scaler.transform(X_test)
  703. # Train the Logistic Regression model
  704. model = LogisticRegression()
  705. model.fit(X_train, y_train)
  706. # Evaluate the model
  707. y_pred = model.predict(X_test)
  708. accuracy = accuracy_score(y_test, y_pred)
  709. accuracy_ls.append(pd.DataFrame({'Accuracy': [accuracy], 'et': d[2], 'group': d[0], 'region':d[1], 'stim_id':[stim]}))
  710. except:
  711. continue
  712. accuracy_df = pd.concat(accuracy_ls, ignore_index=True)
  713. accuracy_df.head()
  714. # %%
  715. sns.catplot(data=accuracy_df, kind="bar", x="group", y="Accuracy", order=['WT', 'FX'],
  716. col='stim_id', col_order=['Go', 'No-Go'], row='region', row_order=['V1', 'HPC'],
  717. height=4, aspect=1.25)
  718. for d,dd in accuracy_df.groupby(['stim_id', 'region']):
  719. x = dd[dd.group=='WT'].Accuracy.values
  720. y = dd[dd.group=='FX'].Accuracy.values
  721. res = sstat.shapiro(x)
  722. print("wt --", res)
  723. res = sstat.shapiro(y)
  724. print("fx --", res)
  725. res = sstat.ttest_ind(x, y)
  726. pstar = '***' if res.pvalue < 0.001 else ('**' if res.pvalue < 0.01 else ('*' if res.pvalue < 0.05 else "ns"))
  727. print(f"{d} -- {res} -- {pstar}")
  728. for d,dd in accuracy_df.groupby(['group', 'region']):
  729. x = dd[dd.stim_id=='Go'].Accuracy.values
  730. y = dd[dd.stim_id=='No-Go'].Accuracy.values
  731. res = sstat.ttest_ind(x, y)
  732. pstar = '***' if res.pvalue < 0.001 else ('**' if res.pvalue < 0.01 else ('*' if res.pvalue < 0.05 else "ns"))
  733. print(f"{d} -- {res} -- {pstar}")
  734. plt.show()
  735. # %%
  736. # %%
  737. # %%
  738. # %%
  739. # %%
  740. # %% [markdown]
  741. # # ! 2d scatter plots for lick prob and behavior for the LFP data
  742. # %%
  743. osc_characteristic = 'auc' #'auc', 'mean_val', 'peak_val'
  744. go_evidence = []
  745. for d,dd in lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et.isin(active_ets))].groupby(['et','region']):
  746. go_c = dd[(dd.stim_id=='Go+')&(dd.behav=='H')|(dd.stim_id=='Go-')&(dd.behav=='H')][osc_characteristic].mean()
  747. go_i = dd[(dd.stim_id=='Go+')&(dd.behav=='M')|(dd.stim_id=='Go-')&(dd.behav=='M')][osc_characteristic].mean()
  748. go_all = dd[(dd.stim_id=='Go+')|(dd.stim_id=='Go-')][osc_characteristic].mean()
  749. ng_c = dd[(dd.stim_id=='No-Go')&(dd.behav=='CR')][osc_characteristic].mean()
  750. ng_i = dd[(dd.stim_id=='No-Go')&(dd.behav=='FA')][osc_characteristic].mean()
  751. ng_all = dd[dd.stim_id=='No-Go'][osc_characteristic].mean()
  752. go = (go_c-go_i)/(go_c+go_i)
  753. ng = (ng_c-ng_i)/(ng_c+ng_i)
  754. g_ng = (go-ng)/(go+ng)
  755. go_base = (go_c-go_all)/(dd[(dd.stim_id=='Go+')|(dd.stim_id=='Go-')][osc_characteristic].std())
  756. ng_base = (ng_c-ng_all)/(dd[dd.stim_id=='No-Go'][osc_characteristic].std())
  757. lick_dict = dd.groupby('behav').trial.nunique().to_dict()
  758. d_prime = sstat.norm.ppf(lick_dict['H']/100) - sstat.norm.ppf(lick_dict['FA']/50)
  759. go_evidence.append(pd.DataFrame({'goC':go_c, 'goIC':go_i,'ngC':ng_c, 'ngIC':ng_i, 'go_avg':go, 'ng_avg':ng, 'gng_avg':g_ng, 'go_base':go_base, 'ng_base':ng_base,
  760. 'go_licks':lick_dict['H']/100, 'ng_licks':lick_dict['CR']/50, 'gng_licks':(lick_dict['H']+lick_dict['CR'])/150, 'Dprime':d_prime,
  761. 'go2_licks':lick_dict['M']/100, 'ng2_licks':lick_dict['FA']/50,
  762. 'et':d[0], 'group':dd.group.unique()[0], 'region':d[1]}, index=[0]))
  763. go_evidence = pd.concat(go_evidence, ignore_index=True)
  764. go_evidence.head()
  765. # %%
  766. def confidence_ellipse(x, y, ax, n_std=3.0, facecolor='none', **kwargs):
  767. """
  768. Create a plot of the covariance confidence ellipse of *x* and *y*.
  769. Parameters
  770. ----------
  771. x, y : array-like, shape (n, )
  772. Input data.
  773. ax : matplotlib.axes.Axes
  774. The Axes object to draw the ellipse into.
  775. n_std : float
  776. The number of standard deviations to determine the ellipse's radiuses.
  777. **kwargs
  778. Forwarded to `~matplotlib.patches.Ellipse`
  779. Returns
  780. -------
  781. matplotlib.patches.Ellipse
  782. CODE FROM: https://matplotlib.org/stable/gallery/statistics/confidence_ellipse.html#sphx-glr-gallery-statistics-confidence-ellipse-py
  783. """
  784. if x.size != y.size:
  785. raise ValueError("x and y must be the same size")
  786. cov = np.cov(x, y)
  787. pearson = cov[0, 1]/np.sqrt(cov[0, 0] * cov[1, 1])
  788. # Using a special case to obtain the eigenvalues of this two-dimensional dataset.
  789. ell_radius_x = np.sqrt(1 + pearson)
  790. ell_radius_y = np.sqrt(1 - pearson)
  791. ellipse = Ellipse((0, 0), width=ell_radius_x * 2, height=ell_radius_y * 2, facecolor=facecolor, **kwargs)
  792. # Calculating the standard deviation of x from the squareroot of the variance and multiplying with the given number of standard deviations.
  793. scale_x = np.sqrt(cov[0, 0]) * n_std
  794. mean_x = np.mean(x)
  795. # calculating the standard deviation of y ...
  796. scale_y = np.sqrt(cov[1, 1]) * n_std
  797. mean_y = np.mean(y)
  798. transf = transforms.Affine2D().rotate_deg(45).scale(scale_x, scale_y).translate(mean_x, mean_y)
  799. ellipse.set_transform(transf + ax.transData)
  800. return ax.add_patch(ellipse)
  801. # %%
  802. num_std = 1.5 # standard deviation you want to have contained within the ellipse
  803. dot_size = 50 # aesthetic choice for the size of the scatter plot dots
  804. plot_linReg = True # adds a linear regression to the 2d scatter (with the ellipse)
  805. # for val in [['go_licks', 'go_base'], ['ng_licks', 'ng_base']]:
  806. # for val in [['go_licks', 'go_avg'], ['ng_licks', 'ng_avg'], ['gng_licks', 'gng_avg'], ['Dprime', 'gng_avg']]:
  807. # for val in [['go_licks', 'goC'], ['ng_licks', 'ngC']]:
  808. for val in [['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]:
  809. my_x, my_y = val[0], val[1]
  810. fig, ax = plt.subplots(1, 2, figsize=(10, 4), sharex=True, sharey=True)
  811. for idx, reg in enumerate(['V1','HPC']):
  812. x = go_evidence[(go_evidence.group=='WT')&(go_evidence.region==reg)][my_x].values
  813. y = go_evidence[(go_evidence.group=='WT')&(go_evidence.region==reg)][my_y].values
  814. x1 = go_evidence[(go_evidence.group=='FX')&(go_evidence.region==reg)][my_x].values
  815. y1 = go_evidence[(go_evidence.group=='FX')&(go_evidence.region==reg)][my_y].values
  816. # plot linear regression of the points & print R**2 value of the fit
  817. if plot_linReg:
  818. res, res1 = sstat.linregress(x, y), sstat.linregress(x1, y1)
  819. print(f"------------- {my_x} -------------")
  820. print(f'{reg} - Slope: WT {res.slope:.6f}, FX {res1.slope:.6f}')
  821. print(f'{reg} - R squared: WT {res.rvalue**2:.6f}, FX {res1.rvalue**2:.6f}')
  822. print(f'{reg} - pval: WT {res.pvalue:.6f}, FX {res1.pvalue:.6f}')
  823. ax[idx].plot(x, res.intercept+res.slope*x, color='cyan')
  824. ax[idx].plot(x1, res1.intercept+res1.slope*x1, color='magenta')
  825. # Plot scatter
  826. ax[idx].scatter(x, y, s=dot_size, edgecolors=None, color='cyan', label='WT')
  827. ax[idx].scatter(x1, y1, s=dot_size, edgecolors=None, color='magenta', label='FX')
  828. # Plot ellipse using above function
  829. confidence_ellipse(x, y, ax[idx], n_std=num_std, edgecolor=None, facecolor='cyan', alpha=0.3)
  830. confidence_ellipse(x1, y1, ax[idx], n_std=num_std, edgecolor=None, facecolor='magenta', alpha=0.3)
  831. if my_x == 'gng_licks':
  832. ax[idx].set_xlim([0,1.1])
  833. # ax[idx].set_ylim([0.45,0.57])
  834. ax[idx].set_xlabel("Correct %")
  835. ax[idx].set_ylabel("GNG Theta")
  836. elif my_x == 'Dprime':
  837. ax[idx].set_xlim([-1,2])
  838. # ax[idx].set_ylim([0.45,0.57])
  839. ax[idx].set_xlabel("d'")
  840. ax[idx].set_ylabel("GNG Theta")
  841. else:
  842. ax[idx].set_xlim([-0.1,1.1])
  843. ax[idx].set_xlabel("Correct rate")
  844. if (my_y=='go_avg')|(my_y=='ng_avg'):
  845. ax[idx].set_ylabel("Go Theta") if my_x=='go_licks' else ax[idx].set_ylabel("No-Go Theta")
  846. else:
  847. if (my_y=='goIC')|(my_y=='ngIC'):
  848. ax[idx].set_ylabel("Incorrect Go") if my_x=='go2_licks' else ax[idx].set_ylabel("Incorrect No-Go")
  849. ax[idx].set_ylim([0.5,4.5])
  850. ax[idx].set_xlabel("Incorrect rate")
  851. else:
  852. ax[idx].set_ylabel("Correct Go") if my_x=='go_licks' else ax[idx].set_ylabel("Correct No-Go")
  853. ax[idx].set_ylim([0.5,4.5])
  854. ax[idx].set_title(reg)
  855. plt.tight_layout()
  856. sns.despine()
  857. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\2dscatter_LFP_incorrectTrials_{my_x}_v1hpc.pdf", transparent=True)
  858. plt.show()
  859. # %%
  860. # Calculate a Spearman correlation coefficient with associated p-value on the 2d scatter plots
  861. def statistic(x): # permute only `x`
  862. return sstat.spearmanr(x, y).statistic
  863. # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.spearmanr.html <--- Spearman test info
  864. # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.permutation_test.html <--- Permutation info
  865. # for val in [['go_licks', 'go_avg'], ['ng_licks', 'ng_avg'], ['gng_licks', 'gng_avg'], ['Dprime', 'gng_avg']]:
  866. for val in [['go_licks', 'goC'], ['ng_licks', 'ngC'], ['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]:
  867. my_x, my_y = val[0], val[1]
  868. for idx, reg in enumerate(['V1','HPC']):
  869. for g in ['WT', 'FX']:
  870. x = go_evidence[(go_evidence.group==g)&(go_evidence.region==reg)][my_x].values
  871. y = go_evidence[(go_evidence.group==g)&(go_evidence.region==reg)][my_y].values
  872. res_exact = sstat.permutation_test((x,), statistic, permutation_type='pairings')
  873. print(val, reg, g)
  874. pval = "***" if res_exact.pvalue < 0.001 else ("**" if res_exact.pvalue<0.01 else ("*" if res_exact.pvalue <0.05 else "ns"))
  875. print(f"stat = {res_exact.statistic:.6f} -- pval = {res_exact.pvalue:.6f} -- {pval}")
  876. # %%
  877. # trying a 2-dimensional, 2-sample KS test for comparing the WT and FX groups (https://github.com/syrte/ndtest)
  878. import ndtest
  879. for val in [['go_licks', 'goC'], ['ng_licks', 'ngC'], ['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]: #correct/incorrect trial responses only
  880. my_x, my_y = val[0], val[1]
  881. for idx, reg in enumerate(['V1','HPC']):
  882. x = go_evidence[(go_evidence.group=='WT')&(go_evidence.region==reg)][my_x].values
  883. y = go_evidence[(go_evidence.group=='WT')&(go_evidence.region==reg)][my_y].values
  884. x1 = go_evidence[(go_evidence.group=='FX')&(go_evidence.region==reg)][my_x].values
  885. y1 = go_evidence[(go_evidence.group=='FX')&(go_evidence.region==reg)][my_y].values
  886. P, D = ndtest.ks2d2s(x, y, x1, y1, extra=True)
  887. pval = "***" if P<0.001 else ("**" if P<0.01 else ("*" if P<0.05 else "ns"))
  888. print(f"{my_y} -- {reg} -- d={D:.7f} -- p={P:.7f} -- {pval}")
  889. # %%
  890. # %%
  891. # %%
  892. # %%
  893. # %%
  894. # %%
  895. # # trying a multivariate ANOVA test (https://www.reneshbedre.com/blog/manova-python.html)
  896. # # https://www.statsmodels.org/stable/generated/statsmodels.multivariate.manova.MANOVA.html#statsmodels.multivariate.manova.MANOVA
  897. # from statsmodels.multivariate.manova import MANOVA
  898. # for reg in ['V1','HPC']:
  899. # region_df = go_evidence[go_evidence.region==reg]
  900. # fit = MANOVA.from_formula('go_licks + goC ~ group', data=region_df)
  901. # print(f'goC -- {reg}')
  902. # print(fit.mv_test())
  903. # for reg in ['V1','HPC']:
  904. # region_df = go_evidence[go_evidence.region==reg]
  905. # fit = MANOVA.from_formula('ng_licks + ngC ~ group', data=region_df)
  906. # print(f'goC -- {reg}')
  907. # print(fit.mv_test())
  908. # %%
  909. # # Trying Linear Mixed Model (https://www.statsmodels.org/stable/mixed_linear.html)
  910. # import statsmodels.formula.api as smf
  911. # for reg in ['V1','HPC']:
  912. # region_df = go_evidence[go_evidence.region==reg]
  913. # md = smf.mixedlm("goC ~ go_licks", region_df, groups=region_df["group"], re_formula="~go_licks")
  914. # mdf = md.fit(method=["lbfgs"])
  915. # print(mdf.summary())
  916. # for reg in ['V1','HPC']:
  917. # region_df = go_evidence[go_evidence.region==reg]
  918. # md = smf.mixedlm("ngC ~ ng_licks", region_df, groups=region_df["group"], re_formula="~ng_licks")
  919. # mdf = md.fit(method=["lbfgs"])
  920. # print(mdf.summary())
  921. # %%
  922. # %%
  923. # %% [markdown]
  924. # ## ! 2d scatter plots for lick prob and behavior for the units data
  925. # %%
  926. display(units_fft.head(2))
  927. display(vr_units.head(2))
  928. # %%
  929. osc_characteristic = 'auc'
  930. go_evid_units = []
  931. for d,dd in units_fft[(units_fft.band=="[4, 8]")&(units_fft.et.isin(active_ets))].groupby(['et','region']):
  932. go = dd[(dd.stim==0)|(dd.stim==1)][osc_characteristic].mean()
  933. ng = dd[(dd.stim==2)][osc_characteristic].mean()
  934. g_ng = go/(go+ng)
  935. go_evid_units.append(pd.DataFrame({'go_avg':go, 'ng_avg':ng, 'gng_avg':g_ng, 'et':d[0], 'group':dd.group.unique()[0], 'region':d[1]}, index=[0]))
  936. go_evid_units = pd.concat(go_evid_units, ignore_index=True)
  937. #map lick probability values from LFP df to units df
  938. map_dict = dict(zip(go_evidence['et'], go_evidence['gng_licks']))
  939. go_evid_units['gng_licks'] = go_evid_units['et'].map(map_dict)
  940. map_dict = dict(zip(go_evidence['et'], go_evidence['go_licks']))
  941. go_evid_units['go_licks'] = go_evid_units['et'].map(map_dict)
  942. map_dict = dict(zip(go_evidence['et'], go_evidence['ng_licks']))
  943. go_evid_units['ng_licks'] = go_evid_units['et'].map(map_dict)
  944. map_dict = dict(zip(go_evidence['et'], go_evidence['Dprime']))
  945. go_evid_units['Dprime'] = go_evid_units['et'].map(map_dict)
  946. go_evid_units.head()
  947. # %%
  948. num_std = 1.5 # standard deviation you want to have contained within the ellipse
  949. dot_size = 50 # aesthetic choice for the size of the scatter plot dots
  950. plot_linReg = False # adds a linear regression to the 2d scatter (with the ellipse)
  951. for val in [['go_licks', 'go_avg'], ['ng_licks', 'ng_avg'], ['gng_licks', 'gng_avg'], ['Dprime', 'gng_avg']]:
  952. my_x, my_y = val[0], val[1]
  953. fig, ax = plt.subplots(1, 2, figsize=(10, 4), sharex=True, sharey=True)
  954. for idx, reg in enumerate(['v1','hippo']):
  955. x = go_evid_units[(go_evid_units.group=='WT')&(go_evid_units.region==reg)][my_x].values
  956. y = go_evid_units[(go_evid_units.group=='WT')&(go_evid_units.region==reg)][my_y].values
  957. x1 = go_evid_units[(go_evid_units.group=='FX')&(go_evid_units.region==reg)][my_x].values
  958. y1 = go_evid_units[(go_evid_units.group=='FX')&(go_evid_units.region==reg)][my_y].values
  959. # plot linear regression of the points & print R**2 value of the fit
  960. if plot_linReg:
  961. res, res1 = sstat.linregress(x, y), sstat.linregress(x1, y1)
  962. print(f'{reg} - Slope: WT {res.slope:.6f}, FX {res1.slope:.6f}')
  963. print(f'{reg} - R squared: WT {res.rvalue**2:.6f}, FX {res1.rvalue**2:.6f}')
  964. ax[idx].plot(x, res.intercept+res.slope*x, color='cyan')
  965. ax[idx].plot(x1, res1.intercept+res1.slope*x1, color='magenta')
  966. # Plot scatter
  967. ax[idx].scatter(x, y, s=dot_size, edgecolors=None, color='cyan', label='WT')
  968. ax[idx].scatter(x1, y1, s=dot_size, edgecolors=None, color='magenta', label='FX')
  969. # Plot ellipse using above function
  970. confidence_ellipse(x, y, ax[idx], n_std=num_std, edgecolor='cyan', facecolor='cyan', alpha=0.2)
  971. confidence_ellipse(x1, y1, ax[idx], n_std=num_std, edgecolor='magenta', facecolor='magenta', alpha=0.2)
  972. if my_x == 'gng_licks':
  973. ax[idx].set_xlim([0,1.1])
  974. # ax[idx].set_ylim([0.45,0.57])
  975. ax[idx].set_xlabel("Lick probability")
  976. ax[idx].set_ylabel("GNG Theta")
  977. elif my_x == 'Dprime':
  978. ax[idx].set_xlim([-1,2])
  979. # ax[idx].set_ylim([0.45,0.57])
  980. ax[idx].set_xlabel("d'")
  981. ax[idx].set_ylabel("GNG Theta")
  982. else:
  983. ax[idx].set_xlim([-0.1,1.1])
  984. # ax[idx].set_ylim([0.4,0.6])
  985. ax[idx].set_xlabel("Lick probability")
  986. ax[idx].set_ylabel("Go Theta") if my_x=='go_licks' else ax[idx].set_ylabel("No-Go Theta")
  987. ax[idx].set_title(f"{reg} units")
  988. plt.tight_layout()
  989. sns.despine()
  990. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\2dscatter_units_{my_x}_v1hpc.pdf", transparent=True)
  991. plt.show()
  992. # %% [markdown]
  993. # # ! LFP trace, unit rasters, and lick behavior
  994. # %%
  995. unit_spikes = pd.read_pickle(r"U:\Papers\FX Behavior paper\data\operant_spikes_df.pkl")
  996. unit_spikes.head()
  997. # %%
  998. # #plot rasters for all units to decide which ones to use for the final combo plots in cell below
  999. # my_et = "CC082260_HP2" # WT mouse
  1000. # # my_et = "CC082255_HP0" # FX mouse
  1001. # stim_id = 0
  1002. # plt_color = 'cyan' if my_et == "CC082260_HP2" else 'magenta'
  1003. # et_behav = dict(zip(range(150),lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et==my_et)&(lfp_fft.region=='V1')].behav.values))
  1004. # et_spk = unit_spikes[unit_spikes.et==my_et]
  1005. # et_spk['behav'] = et_spk['trial'].map(et_behav)
  1006. # for unit in vr_units[vr_units.et==my_et].cuid.unique():
  1007. # print(unit)
  1008. # unit_spk = et_spk[et_spk.cuid==unit]
  1009. # fig, ax = plt.subplots(2,2, figsize=(15,5), sharex=True, sharey=True)
  1010. # ax = ax.flatten()
  1011. # ax_titles = ['Hit', "Miss", 'CR', "FA"]
  1012. # for idx,axis in enumerate(ax):
  1013. # axis.axvspan(0.5 ,0.7, color='grey', alpha=0.2)
  1014. # axis.set(ylabel='Trial #')
  1015. # axis.set_title(ax_titles[idx])
  1016. # #raster plots
  1017. # ax[0].plot(unit_spk[unit_spk.behav=='H'].trial_spikes, unit_spk[unit_spk.behav=='H'].trial, '.', ms=8, color=plt_color)
  1018. # ax[1].plot(unit_spk[unit_spk.behav=='M'].trial_spikes, unit_spk[unit_spk.behav=='M'].trial, '.', ms=8, color=plt_color)
  1019. # ax[2].plot(unit_spk[unit_spk.behav=='CR'].trial_spikes, unit_spk[unit_spk.behav=='CR'].trial, '.', ms=8, color=plt_color)
  1020. # ax[3].plot(unit_spk[unit_spk.behav=='FA'].trial_spikes, unit_spk[unit_spk.behav=='FA'].trial, '.', ms=8, color=plt_color)
  1021. # sns.despine()
  1022. # plt.show()
  1023. # %%
  1024. # this is dict with {et: [trial #s]}
  1025. d = {'CC082260_HP2':[147,56,124,107,122,30], 'CC082255_HP0':[84,129,51,9,119,78]}
  1026. wt_v1_units = ['CC082260_HP2_477', 'CC082260_HP2_544', 'CC082260_HP2_567', 'CC082260_HP2_521', 'CC082260_HP2_517',
  1027. 'CC082260_HP2_548', 'CC082260_HP2_562', 'CC082260_HP2_559']
  1028. wt_hpc_units = ['CC082260_HP2_187', 'CC082260_HP2_188', 'CC082260_HP2_201', 'CC082260_HP2_224', 'CC082260_HP2_236',
  1029. 'CC082260_HP2_239', 'CC082260_HP2_240', 'CC082260_HP2_254']
  1030. fx_v1_units = ['CC082255_HP0_564', 'CC082255_HP0_571', 'CC082255_HP0_589', 'CC082255_HP0_577', 'CC082255_HP0_517',
  1031. 'CC082255_HP0_601', 'CC082255_HP0_554']
  1032. fx_hpc_units = ['CC082255_HP0_193', 'CC082255_HP0_212', 'CC082255_HP0_214', 'CC082255_HP0_227', 'CC082255_HP0_259',
  1033. 'CC082255_HP0_263']
  1034. unit_gap = 120
  1035. rast_start = 1000
  1036. is_saving = False
  1037. for et,trs in d.items():
  1038. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1039. et_behav = dict(zip(range(150),lfp_fft[(lfp_fft.band=="[4, 8]")&(lfp_fft.et==et)&(lfp_fft.region=='V1')].behav.values))
  1040. et_spk = unit_spikes[unit_spikes.et==et]
  1041. et_spk['behav'] = et_spk['trial'].map(et_behav)
  1042. if et == "CC082260_HP2":
  1043. unit_spk = et_spk[(et_spk.cuid.isin(wt_v1_units))|(et_spk.cuid.isin(wt_hpc_units))] #wt units list for the raster plots
  1044. v1_units, hpc_units = wt_v1_units, wt_hpc_units
  1045. else:
  1046. unit_spk = et_spk[(et_spk.cuid.isin(fx_v1_units))|(et_spk.cuid.isin(fx_hpc_units))]
  1047. v1_units, hpc_units = fx_v1_units, fx_hpc_units
  1048. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1049. # for plt_tr in trs:
  1050. for plt_tr in [7, 20, 146, 101]: #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Make this a list of 0-149 to look for another VEP Mis for Go+ and Go-
  1051. dd = all_trial_lfp[(all_trial_lfp.et==et)&(all_trial_lfp.trial==plt_tr)]
  1052. #gets the v1 lfp trace for the et/trial pairing
  1053. tr_stim = dd.stim_id.unique()[0]
  1054. plt_stim = 'Go+' if tr_stim=='0' else ('Go-' if tr_stim=='1' else 'No-Go')
  1055. tr_lfp = dd.lfp_data.values[0]
  1056. v1_lfp = tr_lfp[v1_ch,:]
  1057. hpc_lfp = tr_lfp[hpc_ch,:]
  1058. #trims the behavior df to the et/trial pairing
  1059. tmp0 = behavior[(behavior.et==et)&(behavior.true_tr==plt_tr)&(behavior.lick_time>-0.5)&(behavior.lick_time<2.5)]
  1060. tmp = tmp0['lick_time'].values+0.5 #lick times now zeroed to start of recording
  1061. num_licks = len([x for x in tmp if (x>1.0)&(x<1.7)]) #counting the number of licks within the delay period
  1062. tr_beh = tmp0.behav.unique()[0] if tmp0.size else ('CR' if plt_stim=='No-Go' else 'M') #OR else 'nolick'
  1063. #plot the lfp traces and the licks overlaid
  1064. x_times = np.linspace(0,3,v1_lfp.shape[0])
  1065. plt_color = 'cyan' if dd.group.unique()[0]=='WT' else 'magenta'
  1066. fig,ax = plt.subplots(1,2, sharex=True, sharey=True, figsize=(15,5))
  1067. ax[0].axvspan(0.5,0.7, color='grey', alpha=0.2)
  1068. ax[1].axvspan(0.5,0.7, color='grey', alpha=0.2)
  1069. if plt_stim=='Go+':
  1070. ax[0].axvline(1.7, color='royalblue')
  1071. ax[1].axvline(1.7, color='royalblue')
  1072. elif plt_stim=='Go-':
  1073. ax[0].axvline(1.7, color='grey')
  1074. ax[1].axvline(1.7, color='grey')
  1075. ax[0].plot(x_times, scnd.gaussian_filter1d(v1_lfp, sigma=20), color=plt_color, linewidth=4) #plot gaussian filtered V1 vep
  1076. ax[0].scatter(x=tmp, y=[-750]*len(tmp), marker='|', c='black', s=200) #plot lick raster
  1077. ax[0].axhline(-750, color='grey', linewidth=1, alpha=0.5, zorder=0)
  1078. ax[1].plot(x_times, scnd.gaussian_filter1d(hpc_lfp, sigma=20), color=plt_color, linewidth=4) #plot gaussian filtered V1 vep
  1079. ax[1].scatter(x=tmp, y=[-750]*len(tmp), marker='|', c='black', s=200) #plot lick raster
  1080. ax[1].axhline(-750, color='grey', linewidth=1, alpha=0.5, zorder=0)
  1081. ax[0].set_xlabel('Time (s)')
  1082. ax[1].set_xlabel('Time (s)')
  1083. ax[0].set_ylabel('V1')
  1084. ax[0].set_ylim([-900,(rast_start+unit_gap*5+400)])
  1085. ax[0].set_yticks([-500,0,500,rast_start,(rast_start+unit_gap*5)])
  1086. ax[0].set_yticklabels([-500,0,500,0,5])
  1087. # ax[1].set_ylim([-900,900])
  1088. ax[0].set_title(f"{et} ~~ Trial {plt_tr} ~~ {plt_stim} ~~ {tr_beh}")
  1089. ax[1].set_ylabel('HPC')
  1090. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1091. #plot the unit rasters (~6 units per region - some don't fire on every trial)
  1092. unit_spk_tr = unit_spk[unit_spk.trial==plt_tr]
  1093. my_pal = sns.color_palette("tab10")
  1094. for idx in range(len(v1_units)):
  1095. ax[0].axhline(rast_start+unit_gap*idx, color='grey', linewidth=1, alpha=0.5, zorder=0)
  1096. for idx in range(len(hpc_units)):
  1097. ax[1].axhline(rast_start+unit_gap*idx, color='grey', linewidth=1, alpha=0.5, zorder=0)
  1098. for u,uu in unit_spk_tr.groupby('cuid'):
  1099. if uu.region.unique()[0]=='v1':
  1100. ax[0].scatter(x=uu.trial_spikes, y=[rast_start+unit_gap*v1_units.index(u)]*len(uu.trial_spikes), marker='|', s=120, color=my_pal[v1_units.index(u)])
  1101. elif uu.region.unique()[0]=='hippo':
  1102. ax[1].scatter(x=uu.trial_spikes, y=[rast_start+unit_gap*hpc_units.index(u)]*len(uu.trial_spikes), marker='|', s=120, color=my_pal[hpc_units.index(u)])
  1103. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1104. sns.despine()
  1105. if is_saving:
  1106. plt.savefig(rf"C:\Users\AChub_Lab\Desktop\oneEToneTrial_LFPUnitLick_{dd.group.unique()[0]}_tr{plt_tr}_{plt_stim}_{tr_beh}.pdf", transparent=True)
  1107. plt.show()
  1108. break
  1109. # %% [markdown]
  1110. # # ! Spike-Phase coherence
  1111. # %%
  1112. print("LFP dataFrame")
  1113. display(all_trial_lfp.head(2))
  1114. print("LFP dataFrame to map behavior responses")
  1115. display(lfp_fft.head(2))
  1116. print("Unit spike time dataFrame")
  1117. display(unit_spikes.head(2))
  1118. print("Unit psth for visually responsive units")
  1119. display(vr_units.head(2))
  1120. # %%
  1121. def butter_bandpass_filter(mydata, lowcut, highcut, fs, order=4):
  1122. nyq = 0.5 * fs
  1123. low = float(lowcut)/nyq
  1124. high = float(highcut)/nyq
  1125. b, a = ssig.butter(order, [low,high], btype='band')
  1126. y = ssig.filtfilt(b, a, mydata)
  1127. return y
  1128. # %%
  1129. #This cell cuts the unit spike time DataFrame to only include visually responsive units from the vr_psth DataFrame
  1130. vr_unit_ls = vr_units.cuid.unique()
  1131. vr_unit_spikes = unit_spikes[unit_spikes['cuid'].isin(vr_unit_ls)]
  1132. # %%
  1133. #### THIS SPC LOOKS AT LFP CHANNEL THATS SPECIFIC TO THE UNIT DEPTH
  1134. lfp_sr = 2500
  1135. unit_sr = 30000
  1136. time_win = [0.5, 1.5]
  1137. # v1_ch = 260
  1138. # hpc_ch = 110
  1139. spk_ph_coh_ls, et_num = [], 1
  1140. for d,dd in all_trial_lfp.groupby(["et","trial"]):
  1141. #progress bar for looping through ets
  1142. if (d[1]+1)%150==0:
  1143. print(f"Done with {et_num} out of {all_trial_lfp.et.nunique()} mice")
  1144. et_num+=1
  1145. #metadata for saving below
  1146. et_group = dd.group.unique()[0]
  1147. tr_stim = 'Go+' if dd.stim_id.unique()[0]=='0' else ('Go-' if dd.stim_id.unique()[0]=='1' else 'No-Go')
  1148. et_behav = lfp_fft[(lfp_fft.et==d[0])&(lfp_fft.trial==d[1])].behav.unique()[0] #this is the et:trial behavior response
  1149. # load spikes df, and limit to the specific et
  1150. et_spks = vr_unit_spikes[(vr_unit_spikes.et==d[0])&(vr_unit_spikes.trial==d[1])&(vr_unit_spikes.trial_spikes>=time_win[0])&(vr_unit_spikes.trial_spikes<=time_win[1])] #trim units df to time window
  1151. et_spks_v1hpc = et_spks[(et_spks.region=='v1')|(et_spks.region=='hippo')]
  1152. for u,uu in et_spks_v1hpc.groupby('cuid'):
  1153. unit_depth_ch = int(384-(uu.depth.unique()[0])/10)
  1154. my_region = 'V1' if uu.region.unique()[0] == 'v1' else 'HPC'
  1155. tr_lfp = dd.lfp_data.values[0][unit_depth_ch] #pick LFP channel that relates to the unit depth
  1156. filt_lfp = butter_bandpass_filter(tr_lfp, lowcut=4, highcut=8, fs=lfp_sr, order=4) #filter to theta range
  1157. reg_lfp_phase = np.angle(ssig.hilbert(filt_lfp)) #convert to phase domain [-pi, pi]
  1158. u_spk = uu.trial_spikes.values
  1159. unit_phase_ls = []
  1160. my_time = np.linspace(time_win[0],time_win[1],2500)
  1161. for i in range(len(my_time)-1):
  1162. for spk in u_spk:
  1163. if (spk<my_time[i+1])&(spk>=my_time[i]):
  1164. unit_phase_ls.append(reg_lfp_phase[i])
  1165. u_phs_circm = sstat.circmean(unit_phase_ls, high=np.pi, low=-np.pi)
  1166. spk_ph_coh_ls.append(pd.DataFrame({'trial':[d[1]], 'phase':[u_phs_circm], 'cuid':[u], 'et':[d[0]],
  1167. 'group':[et_group], 'region':[my_region], 'stim_id':[tr_stim], 'behav':[et_behav]}))
  1168. spk_ph_coh = pd.concat(spk_ph_coh_ls, ignore_index=True)
  1169. spk_ph_coh.head()
  1170. # %%
  1171. #takes the circular mean of each unit, split by stim_id and behavior
  1172. spk_ph_coh_mean = []
  1173. for d,dd in spk_ph_coh.groupby(['cuid','stim_id','behav']):
  1174. mean_phs_circm = sstat.circmean(dd.phase.values, high=np.pi, low=-np.pi)
  1175. spk_ph_coh_mean.append(pd.DataFrame({'mean_phase':[mean_phs_circm], 'cuid':[d[0]], 'et':dd.et.unique()[0],
  1176. 'group':dd.group.unique()[0], 'region':dd.region.unique()[0], 'stim_id':[d[1]], 'behav':[d[2]]}))
  1177. spk_ph_coh_mean = pd.concat(spk_ph_coh_mean, ignore_index=True)
  1178. spk_ph_coh_mean.head()
  1179. # %%
  1180. for d,dd in spk_ph_coh_mean.groupby('stim_id'):
  1181. g=sns.displot(data=dd, x='mean_phase', col='behav', col_order=['CR', 'FA'] if d=='No-Go' else ['H', 'M'], row='region', row_order=['V1', 'HPC'],
  1182. hue='group', hue_order=['WT','FX'], palette={'WT':'cyan', 'FX':'magenta'},
  1183. kde=True, rug=False, stat='density', binwidth=(np.pi/10), height=4, aspect=1.25, linewidth=0)
  1184. plt.suptitle(d)
  1185. g.set(xticks=[-np.pi, -np.pi/2, 0, np.pi/2, np.pi], yticks=[0, 0.03, 0.06], ylim=[0,0.065])
  1186. g.set_xticklabels([r'- $\pi$',r'- $\frac{\pi}{2}$', '0', r'$\frac{\pi}{2}$', r'$\pi$'])
  1187. print("2-sided KS test comparing the distributions of WT & FX")
  1188. for e,ee in dd.groupby(['region','behav']):
  1189. x,y = ee[ee.group=='WT']['mean_phase'].values, ee[ee.group=='FX']['mean_phase'].values # N = #units
  1190. res = sstat.ks_2samp(x,y)
  1191. plt_stats = "***" if res.pvalue < 0.001 else ("**" if res.pvalue<0.01 else ("*" if res.pvalue <0.05 else "ns"))
  1192. print(f"{d} {e} -- N: WT={len(x)}, FX={len(y)} -- p={res.pvalue} --", plt_stats)
  1193. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\Spike_phase_coherence\SPC_GenotypeSplit_histogram_{d}.pdf", transparent=True)
  1194. plt.show()
  1195. # %%
  1196. for d,dd in spk_ph_coh_mean.groupby('stim_id'):
  1197. g=sns.displot(data=dd, x='mean_phase', col='group', col_order=['WT','FX'], row='region', row_order=['V1', 'HPC'],
  1198. hue='behav', palette={'H':'blue', 'M':'grey', 'CR':'blue', 'FA':'grey'},
  1199. kde=True, rug=False, stat='density', binwidth=(np.pi/10), height=4, aspect=1.25, linewidth=0)
  1200. plt.suptitle(d)
  1201. g.set(xticks=[-np.pi, -np.pi/2, 0, np.pi/2, np.pi], yticks=[0, 0.03, 0.06], ylim=[0,0.065])
  1202. g.set_xticklabels([r'- $\frac{\pi}{2}$', r'- $\pi$', '0', r'$\frac{\pi}{2}$', r'$\pi$'])
  1203. print("2-sided KS test comparing the distributions of behav within genotype")
  1204. for e,ee in dd.groupby(['region','group']):
  1205. if d == 'No-Go':
  1206. x,y = ee[ee.behav=='CR']['mean_phase'].values, ee[ee.behav=='FA']['mean_phase'].values # N = #units
  1207. else:
  1208. x,y = ee[ee.behav=='H']['mean_phase'].values, ee[ee.behav=='M']['mean_phase'].values # N = #units
  1209. res = sstat.ks_2samp(x,y)
  1210. plt_stats = "***" if res.pvalue < 0.001 else ("**" if res.pvalue<0.01 else ("*" if res.pvalue <0.05 else "ns"))
  1211. print(f"{d} {e} -- N: H/CR={len(x)}, M/FA={len(y)} -- p={res.pvalue} --", plt_stats)
  1212. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\temp_figures\Spike_phase_coherence\SPC_BehaviorSplit_histogram_{d}.pdf", transparent=True)
  1213. plt.show()
  1214. # %% [markdown]
  1215. # # ! Aside, more unit analysis
  1216. # This is an aside for the above cells. I'm working on making a 2d plot for the unit responses split by behavior
  1217. # %% [markdown]
  1218. # ## PSTH dataframe creation
  1219. # %%
  1220. print("LFP dataFrame to map behavior responses")
  1221. display(lfp_fft.head(2))
  1222. print("Unit spike time dataFrame")
  1223. display(unit_spikes.head(2))
  1224. print("Unit psth (no behavior) used to id visually responsize units")
  1225. display(vr_units.head(2))
  1226. # %%
  1227. et_trl_behav_dict = {}
  1228. for t,tt in lfp_fft.groupby('et'):
  1229. inner = {}
  1230. for m,mm in tt.groupby('trial'):
  1231. inner.update({m:mm.behav.unique()[0]})
  1232. et_trl_behav_dict.update({t:inner})
  1233. # print(et_trl_behav_dict)
  1234. # %%
  1235. for t,tt in enumerate(unit_spikes.et.unique()):
  1236. unit_spikes.loc[(unit_spikes.et==tt), 'behav'] = unit_spikes[unit_spikes.et==tt].trial.map(et_trl_behav_dict[tt])
  1237. unit_spikes.head()
  1238. # %%
  1239. #This cell cuts the unit spike time DataFrame to only include visually responsive units from the vr_psth DataFrame
  1240. #also only includes units that are in V1 or HPC
  1241. vr_unit_ls = vr_units.cuid.unique()
  1242. region_ls = ['v1','hippo']
  1243. vr_unit_spikes = unit_spikes[(unit_spikes['cuid'].isin(vr_unit_ls))&(unit_spikes['region'].isin(region_ls))]
  1244. # %%
  1245. ls_psth = []
  1246. th_bin = 0.01
  1247. trial_length = 3.0
  1248. num_units, un_idx = vr_unit_spikes['cuid'].nunique(), 0
  1249. for l,ll in vr_unit_spikes.groupby(['cuid', 'stim_id', 'behav']): ##### I changed this from df_rez to data_df to check the units
  1250. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1251. trials_number_not_empty = len(ll.trial.unique())
  1252. h, ttr = mz_ena.PSTH(ll.trial_spikes, th_bin, trial_length, trials_number_not_empty)
  1253. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1254. zscore = sstat.mstats.zscore(h)
  1255. mean = np.mean(h[0:50])#The Baseline period. Be sure it matches time course of experiments##
  1256. std = 1 if mean<=0 else np.std(h[0:50])
  1257. ztc = (h - mean)/std
  1258. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1259. tr_stim = 'Go+' if l[1]==0 else ('Go-' if l[1]==1 else 'No-Go')
  1260. my_region = 'V1' if ll.region.unique()[0] == 'v1' else 'HPC'
  1261. tr_group = 'WT' if ll.group.unique()[0] == "A" else "FX"
  1262. df_psth_tmp = pd.DataFrame({'times':ttr, 'stim_id':tr_stim, 'Hz':h, 'depth':ll.depth.unique()[0],
  1263. 'zscore':zscore, 'ztc':ztc, 'et':ll.et.unique()[0], 'cc': ll.cc.unique()[0],
  1264. 'cuid':l[0], 'region':my_region, 'group':tr_group, 'behav':l[2]})
  1265. ls_psth.append(df_psth_tmp)
  1266. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1267. behav_psth = pd.concat(ls_psth)
  1268. behav_psth.head()
  1269. # %% [markdown]
  1270. # ## Power Spectrum Analysis, unit activity, split by behavior
  1271. # %%
  1272. def get_unit_fft(unit_df):
  1273. unit_arr = unit_df[(unit_df.times>0.5)&(unit_df.times<1.8)].zscore.values
  1274. freq = np.arange(unit_arr.shape[0]) / unit_arr.shape[0] * 100
  1275. freq = freq[:freq.shape[0]//2]
  1276. f = np.fft.fft(unit_arr)
  1277. magnitude_spectrum = (np.abs(f)[:freq.shape[0]])
  1278. return freq, magnitude_spectrum
  1279. # %%
  1280. behav_units_fft = []
  1281. for unit,df in behav_psth.groupby(['stim_id','behav','cuid']):
  1282. fft_freq, fft_amp = get_unit_fft(df)
  1283. bands = [[4,8]]
  1284. auc_val,band_val = [],[]
  1285. for ran in bands:
  1286. lower = fft_freq.searchsorted(ran[0], 'left')
  1287. upper = fft_freq.searchsorted(ran[1], 'right') -1
  1288. val = auc(fft_freq[lower:upper],fft_amp[lower:upper])
  1289. auc_val.append(val)
  1290. band_val.append(str(ran))
  1291. behav_units_fft.append(pd.DataFrame({'band': band_val, 'auc': auc_val, 'cuid': unit[-1],
  1292. 'stim_id': unit[0], 'group': df.group.unique()[0], 'behav':unit[1],
  1293. 'region': df.region.unique()[0], 'et': df.et.unique()[0]}))
  1294. behav_units_fft = pd.concat(behav_units_fft, ignore_index=True)
  1295. behav_units_fft.head()
  1296. # %%
  1297. # this is finding the threshold for each group/stim_id pairing to threshold units in cell below
  1298. num_std = 1.0
  1299. nested_dict={}
  1300. for d,dd in behav_units_fft.groupby('group'):
  1301. nested_dict[d] = {}
  1302. for stim in ["Go", "No-Go"]:
  1303. ee = dd[dd.stim_id!="No-Go"] if stim=="Go" else dd[dd.stim_id=="No-Go"]
  1304. thresh = ee.auc.values.mean()+num_std*ee.auc.values.std() # threshold of mean + 1 std.
  1305. nested_dict[d][stim] = thresh
  1306. nested_dict
  1307. # %%
  1308. unit_thresh_dict = {}
  1309. for stim in ["Go", "No-Go"]:
  1310. temp_df = behav_units_fft[behav_units_fft.stim_id!="No-Go"] if stim=="Go" else behav_units_fft[behav_units_fft.stim_id=="No-Go"]
  1311. unit_thresh_dict[stim] = {}
  1312. for d,dd in temp_df.groupby(['group','cuid']):
  1313. thresh = nested_dict[d[0]][stim]
  1314. unit_thresh_dict[stim][d[1]] = 'yes' if dd.auc.values.mean() >= thresh else 'no'
  1315. # print(unit_thresh_dict)
  1316. # %%
  1317. # Function to categorize values
  1318. def categorize(value):
  1319. if value == 'No-Go':
  1320. return 'No-Go'
  1321. else:
  1322. return 'Go'
  1323. behav_units_fft['stim_id2'] = behav_units_fft['stim_id'].apply(categorize)
  1324. behav_units_fft['thresh'] = behav_units_fft.apply(lambda x: unit_thresh_dict[x['stim_id2']][x['cuid']], axis=1) #map the nexted dictionary to the stim/cuid pairing
  1325. behav_units_fft.head()
  1326. # %%
  1327. for d,dd in behav_units_fft[behav_units_fft.thresh=='yes'].groupby('stim_id2'):
  1328. print("~~~~~~~~~~ comparing behavior conditions within each group ~~~~~~~~~~")
  1329. for e,ee in dd.groupby(['region', 'group']):
  1330. conds = ee.behav.unique()
  1331. x=ee[ee.behav==conds[0]].auc.values
  1332. y=ee[ee.behav==conds[1]].auc.values
  1333. res = sstat.mannwhitneyu(x, y)
  1334. pstar = '***' if res.pvalue < 0.001 else ('**' if res.pvalue < 0.01 else ('*' if res.pvalue < 0.05 else "ns"))
  1335. print(f"{e} -- {res} -- {pstar}")
  1336. print("~~~~~~~~~~ comparing groups within each behavior condition ~~~~~~~~~~")
  1337. for e,ee in dd.groupby(['region', 'behav']):
  1338. conds = ee.group.unique()
  1339. x=ee[ee.group==conds[0]].auc.values
  1340. y=ee[ee.group==conds[1]].auc.values
  1341. res = sstat.mannwhitneyu(x, y)
  1342. pstar = '***' if res.pvalue < 0.001 else ('**' if res.pvalue < 0.01 else ('*' if res.pvalue < 0.05 else "ns"))
  1343. print(f"{e} -- {res} -- {pstar}")
  1344. g = sns.catplot(dd, kind="bar",
  1345. x="behav", y="auc", hue='group', hue_order=['WT','FX'],
  1346. col='region', col_order=['V1', 'HPC'],
  1347. height=4, aspect=1.2)
  1348. g.set_ylabels(f"{d} AUC")
  1349. plt.show()
  1350. # %%
  1351. # %%
  1352. # %% [markdown]
  1353. # ## Plot it
  1354. # %%
  1355. osc_characteristic = 'auc'
  1356. unit_evidence = []
  1357. for d,dd in behav_units_fft[(behav_units_fft.et.isin(active_ets))].groupby(['et','region']):
  1358. go_c = dd[(dd.stim_id=='Go+')&(dd.behav=='H')|(dd.stim_id=='Go-')&(dd.behav=='H')][osc_characteristic].mean()
  1359. go_i = dd[(dd.stim_id=='Go+')&(dd.behav=='M')|(dd.stim_id=='Go-')&(dd.behav=='M')][osc_characteristic].mean()
  1360. go_all = dd[(dd.stim_id=='Go+')|(dd.stim_id=='Go-')][osc_characteristic].mean()
  1361. ng_c = dd[(dd.stim_id=='No-Go')&(dd.behav=='CR')][osc_characteristic].mean()
  1362. ng_i = dd[(dd.stim_id=='No-Go')&(dd.behav=='FA')][osc_characteristic].mean()
  1363. ng_all = dd[dd.stim_id=='No-Go'][osc_characteristic].mean()
  1364. go = (go_c-go_i)/(go_c+go_i)
  1365. ng = (ng_c-ng_i)/(ng_c+ng_i)
  1366. g_ng = (go-ng)/(go+ng)
  1367. go_base = (go_c-go_all)/(dd[(dd.stim_id=='Go+')|(dd.stim_id=='Go-')][osc_characteristic].std())
  1368. ng_base = (ng_c-ng_all)/(dd[dd.stim_id=='No-Go'][osc_characteristic].std())
  1369. foo = lfp_fft[(lfp_fft.et==d[0])&(lfp_fft.region==d[-1])]
  1370. lick_dict = foo.groupby('behav').trial.nunique().to_dict()
  1371. d_prime = sstat.norm.ppf(lick_dict['H']/100) - sstat.norm.ppf(lick_dict['FA']/50)
  1372. unit_evidence.append(pd.DataFrame({'goC':go_c, 'goIC':go_i,'ngC':ng_c, 'ngIC':ng_i,'go_avg':go, 'ng_avg':ng, 'gng_avg':g_ng, 'go_base':go_base, 'ng_base':ng_base,
  1373. 'go_licks':lick_dict['H']/100, 'ng_licks':lick_dict['CR']/50, 'gng_licks':(lick_dict['H']+lick_dict['CR'])/150, 'Dprime':d_prime,
  1374. 'go2_licks':lick_dict['M']/100, 'ng2_licks':lick_dict['FA']/50,
  1375. 'et':d[0], 'group':dd.group.unique()[0], 'region':d[-1]}, index=[0]))
  1376. unit_evidence = pd.concat(unit_evidence, ignore_index=True)
  1377. unit_evidence.head()
  1378. # %%
  1379. dot_size = 50 # 50, aesthetic choice for the size of the scatter plot dots
  1380. plot_linReg = False # adds a linear regression to the 2d scatter
  1381. plot_ell = True #adds the covariance confidence ellipse to the data
  1382. num_std = 1.5 # standard deviation you want to have contained within the ellipse
  1383. # for val in [['go_licks', 'go_base'], ['ng_licks', 'ng_base']]:
  1384. # for val in [['go_licks', 'go_avg'], ['ng_licks', 'ng_avg']]:#, ['gng_licks', 'gng_avg'], ['Dprime', 'gng_avg']]:
  1385. for val in [['go_licks', 'goC'], ['ng_licks', 'ngC']]:
  1386. # for val in [['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]:
  1387. my_x, my_y = val[0], val[1]
  1388. fig, ax = plt.subplots(1, 2, figsize=(10, 4), sharex=True, sharey=True)
  1389. for idx, reg in enumerate(['V1','HPC']):
  1390. x = unit_evidence[(unit_evidence.group=='WT')&(unit_evidence.region==reg)][my_x].values
  1391. y = unit_evidence[(unit_evidence.group=='WT')&(unit_evidence.region==reg)][my_y].values
  1392. x1 = unit_evidence[(unit_evidence.group=='FX')&(unit_evidence.region==reg)][my_x].values
  1393. y1 = unit_evidence[(unit_evidence.group=='FX')&(unit_evidence.region==reg)][my_y].values
  1394. # plot linear regression of the points & print R**2 value of the fit
  1395. if plot_linReg:
  1396. res, res1 = sstat.linregress(x, y), sstat.linregress(x1, y1)
  1397. print(f"------------- {my_x} -------------")
  1398. print(f'{reg} - Slope: WT {res.slope:.6f}, FX {res1.slope:.6f}')
  1399. print(f'{reg} - R squared: WT {res.rvalue**2:.6f}, FX {res1.rvalue**2:.6f}')
  1400. #"The p-value for a hypothesis test whose null hypothesis is that the slope is zero, using Wald Test with t-distribution of the test statistic."
  1401. print(f'{reg} - pval: WT {res.pvalue:.6f}, FX {res1.pvalue:.6f}')
  1402. ax[idx].plot(x, res.intercept+res.slope*x, color='cyan')
  1403. ax[idx].plot(x1, res1.intercept+res1.slope*x1, color='magenta')
  1404. # Plot scatter
  1405. ax[idx].scatter(x, y, s=dot_size, edgecolors=None, color='cyan', label='WT')
  1406. ax[idx].scatter(x1, y1, s=dot_size, edgecolors=None, color='magenta', label='FX')
  1407. # Plot ellipse using above function
  1408. if plot_ell:
  1409. confidence_ellipse(x, y, ax[idx], n_std=num_std, edgecolor=None, facecolor='cyan', alpha=0.3)
  1410. confidence_ellipse(x1, y1, ax[idx], n_std=num_std, edgecolor=None, facecolor='magenta', alpha=0.3)
  1411. if my_x == 'gng_licks':
  1412. ax[idx].set_xlim([0,1.1])
  1413. # ax[idx].set_ylim([0.45,0.57])
  1414. ax[idx].set_xlabel("Correct %")
  1415. ax[0].set_ylabel("GNG Theta")
  1416. elif my_x == 'Dprime':
  1417. ax[idx].set_xlim([-1,2])
  1418. # ax[idx].set_ylim([0.45,0.57])
  1419. ax[idx].set_xlabel("d'")
  1420. ax[0].set_ylabel("GNG Theta")
  1421. else:
  1422. ax[idx].set_xlim([-0.1,1.1])
  1423. ax[idx].set_xlabel("Correct rate")
  1424. if (my_y=='go_avg')|(my_y=='ng_avg'):
  1425. ax[0].set_ylabel("Go Theta") if my_x=='go_licks' else ax[0].set_ylabel("No-Go Theta")
  1426. else:
  1427. ax[0].set_ylabel("Theta power")
  1428. if (my_y=='goIC')|(my_y=='ngIC'):
  1429. ax[idx].set_ylim([16,39])
  1430. ax[idx].set_xlabel("Incorrect rate")
  1431. ax[idx].set_title(f"{reg} units")
  1432. plt.tight_layout()
  1433. sns.despine()
  1434. # plt.savefig(rf"C:\Users\AChub_Lab\Desktop\2dscatter_units_IncorrectTrials_{my_x}_v1hpc.pdf", transparent=True)
  1435. plt.show()
  1436. # %%
  1437. # Calculate a Spearman correlation coefficient with associated p-value on the 2d scatter plots
  1438. def statistic(x): # permute only `x`
  1439. return sstat.spearmanr(x, y).statistic
  1440. # for val in [['go_licks', 'go_avg'], ['ng_licks', 'ng_avg'], ['gng_licks', 'gng_avg'], ['Dprime', 'gng_avg']]:
  1441. for val in [['go_licks', 'goC'], ['ng_licks', 'ngC'], ['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]: #correct/incorrect trial responses only
  1442. my_x, my_y = val[0], val[1]
  1443. for idx, reg in enumerate(['V1','HPC']):
  1444. for g in ['WT', 'FX']:
  1445. x = unit_evidence[(unit_evidence.group==g)&(unit_evidence.region==reg)][my_x].values
  1446. y = unit_evidence[(unit_evidence.group==g)&(unit_evidence.region==reg)][my_y].values
  1447. res_exact = sstat.permutation_test((x,), statistic, permutation_type='pairings')
  1448. print(val, reg, g)
  1449. pval = "***" if res_exact.pvalue < 0.001 else ("**" if res_exact.pvalue<0.01 else ("*" if res_exact.pvalue <0.05 else "ns"))
  1450. print(f"stat = {res_exact.statistic:.6f} -- pval = {res_exact.pvalue:.6f} -- {pval}")
  1451. # %%
  1452. # trying a 2-dimensional, 2-sample KS test for comparing the WT and FX groups (https://github.com/syrte/ndtest)
  1453. import ndtest
  1454. for val in [['go_licks', 'goC'], ['ng_licks', 'ngC'], ['go2_licks', 'goIC'], ['ng2_licks', 'ngIC']]: #correct/incorrect trial responses only
  1455. my_x, my_y = val[0], val[1]
  1456. for idx, reg in enumerate(['V1','HPC']):
  1457. x = unit_evidence[(unit_evidence.group=='WT')&(unit_evidence.region==reg)][my_x].values
  1458. y = unit_evidence[(unit_evidence.group=='WT')&(unit_evidence.region==reg)][my_y].values
  1459. x1 = unit_evidence[(unit_evidence.group=='FX')&(unit_evidence.region==reg)][my_x].values
  1460. y1 = unit_evidence[(unit_evidence.group=='FX')&(unit_evidence.region==reg)][my_y].values
  1461. P, D = ndtest.ks2d2s(x, y, x1, y1, extra=True)
  1462. pval = "***" if P<0.001 else ("**" if P<0.01 else ("*" if P<0.05 else "ns"))
  1463. print(f"{my_y} -- {reg} -- d={D:.7f} -- p={P:.7f} -- {pval}")
  1464. # %%

Behavior_Theta_Correlation.ipynb at commit 05fe09d, no license · at the source

Overview

Authors: Michael P Zimmerman1,2, Mowen Yin1,2, Kevin R Cragg1,2, Sanghamitra Nareddula1, Varun M Kumar3, Violeta Saldarriaga1, Adriana Rotger2, Rachel Lehman1, Paige Edens1, Caroline Powell1, Jenna Barry1, Sein Kim1, Joseph G Makin3, Alexander A Chubykin1,2,4
  1. Department of Biological Sciences, Purdue Institute for Integrative Neuroscience, Purdue Autism Research Center, Purdue University, West Lafayette, IN 47907, USA
  2. Department of Biomedical Engineering, Purdue University, West Lafayette, IN 47907, USA
  3. Department of Electrical and Computer Engineering, Purdue University, West Lafayette, IN 47907, USA
  4. Lead contact
Institutions: Purdue University West Lafayette (United States)
Journal: Cell reports, volume 45, issue 7, article 117590
Dates: published online 20 June 2026; in print 28 July 2026
Type: Research article · Language: English
License: CC BY-NC
Identifiers: DOI 10.1016/j.celrep.2026.117590 · PMID 42322609 · PMCID PMC13472280 · OpenAlex W7165403289
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: EEG (modality), mouse (organism), other condition (population), autism (population), systems (subfield)
Methods: Spectral & time-frequency, Preprocessing, Statistics, Machine learning, Connectivity, Evoked potentials, Single-unit activity, calcium imaging
Keywords: Memory, Learning, Hippocampus, Vision, Primary visual cortex, prefrontal cortex, Autism, Fragile X Syndrome, Neural Circuits, Cp: Neuroscience
MeSH: Behavior, Animal*, Fragile X Messenger Ribonucleoprotein 1*, Fragile X Syndrome*, Theta Rhythm*, Visual Cortex*, Animals, Hippocampus, Male, Mice, Mice, Inbred C57BL, Mice, Knockout, Prefrontal Cortex (* major topic)
Topic: Memory and Neural Mechanisms (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: NIMH (R01 MH116500); National Institutes of Health; NIMH NIH HHS (R01 MH116500)
Citations: not cited yet (Europe PMC); 105 references in the paper
Research resources: Alexa Anti-Chicken 488 RRID:AB_142924, Wild type C57BL/6 mice RRID:IMSR_JAX:000664, B6.129P2-Fmr1tm1Cgr/J (Fmr1 KO mice) RRID:IMSR_JAX:003024, RRID:IMSR_JAX:008069, RRID:IMSR_JAX:012569

Abstract

Fragile X syndrome (FX) is associated with sensory processing and learning deficits. Visual familiarity evokes persistent theta oscillations during passive stimulus presentation in the primary visual cortex (V1) and the hippocampus (HPC), which are impaired in V1 of FX. How does this activity change during active behavior? To address this, we performed Neuropixels recordings in V1, HPC, and the prefrontal cortex (PFC) during Go/No-Go visual discrimination behavior. Theta oscillations are reduced in FX in both V1 and HPC and are abolished during No-Go trials, correlating with excessive, incorrect licking behavior. In wild-type (WT) mice, V1 theta power strongly correlates with correct behavioral outcomes. PFC shows significantly reduced cue-related responses in FX. Together, these findings show loss of behavioral inhibition in FX correlated with attenuated theta activity in V1 and HPC and deficient top-down control from PFC. This work sheds light on circuit-level impairments underlying behavioral deficits in FX for potential therapeutic interventions.

Reproduced under the paper's license (CC BY-NC), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 20 matches between paragraphs and lines of code.

chubykin/V1-HPC-PFC-Behavior-Oscillations

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 05fe09d84329d3582aee3ca74492e9b623a33d74, 19 May 2026
Languages: Jupyter (44), Python (24)
Size: 69 files, 68 scripts
Software Heritage: not archived
Found in: “Data and code availability”
Holds: README, 44 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (29 files), SciPy (27 files), pandas (21 files), Matplotlib (20 files), seaborn (15 files), statsmodels (12 files), Pingouin (4 files), scikit-learn (4 files), Neo (2 files), Open Ephys analysis tools (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
29 files

cortex-lab/allenCCF

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: e5a57fe7e1c9fb333fec51c29a8471131c233a76, 15 July 2025
Languages: MATLAB (61)
Size: 75 files, 61 scripts
Software Heritage: not archived
Found in: the resources table
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
62 files

The paper's code and data availability statement is in the Data section.

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:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 90 scripts, each with its path and the digest of its content;
  • 20 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

Data and code availability

All original datasets have been deposited at Zenodo at https://doi.org/10.5281/zenodo.20273683 and are publicly available as of the date of publication.

All original code has been deposited at GitHub and is publicly available at https://github.com/chubykin/V1-HPC-PFC-Behavior-Oscillationshttps://github.com/chubykin/V1-HPC-PFC-Behavior-Oscillations as of the date of publication.

Any additional information required to reanalyze the data reported in this paper is available from the lead contact upon request.

Reproduced under the paper's license (CC BY-NC), 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 → Cell Press
  • Authors: added Alexander A Chubykin (0000-0001-8224-9296); removed Alexander A Chubykin

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 14 authors, 10 keywords, 12 MeSH terms, 3 funders, 103 references, 5 RRIDs.

Cite

This paper

Zimmerman, M. P., Yin, M., Cragg, K. R., Nareddula, S., Kumar, V. M., Saldarriaga, V., Rotger, A., Lehman, R., Edens, P., Powell, C., Barry, J., Kim, S., Makin, J. G., & Chubykin, A. A. (2026). Impaired behavioral inhibition in Fmr1 KO mice is linked to disrupted visual cortex theta oscillations. Cell reports, 45(7), 117590. https://doi.org/10.1016/j.celrep.2026.117590

BibTeX

@article{zimmerman2026impaired,
author = {Zimmerman, Michael P and Yin, Mowen and Cragg, Kevin R and Nareddula, Sanghamitra and Kumar, Varun M and Saldarriaga, Violeta and Rotger, Adriana and Lehman, Rachel and Edens, Paige and Powell, Caroline and Barry, Jenna and Kim, Sein and Makin, Joseph G and Chubykin, Alexander A},
title = {{Impaired behavioral inhibition in Fmr1 KO mice is linked to disrupted visual cortex theta oscillations}},
journal = {Cell reports},
year = {2026},
month = jun,
volume = {45},
number = {7},
pages = {117590},
publisher = {Cell Press},
issn = {2211-1247},
doi = {10.1016/j.celrep.2026.117590},
url = {https://doi.org/10.1016/j.celrep.2026.117590},
pmid = {42322609},
pmcid = {PMC13472280}
}

RIS

TY - JOUR
AU - Zimmerman, Michael P
AU - Yin, Mowen
AU - Cragg, Kevin R
AU - Nareddula, Sanghamitra
AU - Kumar, Varun M
AU - Saldarriaga, Violeta
AU - Rotger, Adriana
AU - Lehman, Rachel
AU - Edens, Paige
AU - Powell, Caroline
AU - Barry, Jenna
AU - Kim, Sein
AU - Makin, Joseph G
AU - Chubykin, Alexander A
TI - Impaired behavioral inhibition in Fmr1 KO mice is linked to disrupted visual cortex theta oscillations
T2 - Cell reports
J2 - Cell Rep
PY - 2026
DA - 2026/06/20
VL - 45
IS - 7
SP - 117590
SN - 2211-1247
PB - Cell Press
DO - 10.1016/j.celrep.2026.117590
UR - https://doi.org/10.1016/j.celrep.2026.117590
LA - en
ER -

CSL-JSON

{
"id": "10.1016/j.celrep.2026.117590",
"type": "article-journal",
"title": "Impaired behavioral inhibition in Fmr1 KO mice is linked to disrupted visual cortex theta oscillations",
"container-title": "Cell reports",
"author": [
{
"family": "Zimmerman",
"given": "Michael P"
},
{
"family": "Yin",
"given": "Mowen"
},
{
"family": "Cragg",
"given": "Kevin R"
},
{
"family": "Nareddula",
"given": "Sanghamitra"
},
{
"family": "Kumar",
"given": "Varun M"
},
{
"family": "Saldarriaga",
"given": "Violeta"
},
{
"family": "Rotger",
"given": "Adriana"
},
{
"family": "Lehman",
"given": "Rachel"
},
{
"family": "Edens",
"given": "Paige"
},
{
"family": "Powell",
"given": "Caroline"
},
{
"family": "Barry",
"given": "Jenna"
},
{
"family": "Kim",
"given": "Sein"
},
{
"family": "Makin",
"given": "Joseph G"
},
{
"family": "Chubykin",
"given": "Alexander A"
}
],
"container-title-short": "Cell Rep",
"volume": "45",
"issue": "7",
"page": "117590",
"DOI": "10.1016/j.celrep.2026.117590",
"PMID": "42322609",
"PMCID": "PMC13472280",
"ISSN": "2211-1247",
"publisher": "Cell Press",
"URL": "https://doi.org/10.1016/j.celrep.2026.117590",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
20
]
]
}
}

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.1038/s41586-026-10501-y [code]
Long-term editing of brain circuits using an engineered electrical synapse.
Journal: Nature
In common: Neo, Pingouin, statsmodels, 7 other tools, mouse, 1 reference
[2] doi:10.1016/j.celrep.2026.117420 [code]
Neural population dynamics of direct electrical stimulation of neocortex.
Journal: Cell reports
In common: Open Ephys analysis tools, statsmodels, seaborn, 5 other tools, systems, mouse, 2 references
[3] 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: Neo, statsmodels, Statistics and Machine Learning Toolbox, 6 other tools, 2 references
[4] doi:10.1038/s41593-026-02314-z [code]
Low-dimensional population dynamics in the brainstem gate REM sleep.
Journal: Nature neuroscience
In common: Pingouin, statsmodels, seaborn, 5 other tools, systems, EEG, mouse, 2 references
[5] doi:10.7554/elife.108408 [code]
Frequency and laminar profile of feature-specific visual activity revealed by interleaved EEG-fMRI.
Journal: eLife
In common: Pingouin, Image Processing Toolbox, statsmodels, 6 other tools, systems, EEG, 1 reference
[6] doi:10.1038/s41593-026-02255-7 [code]
Neural circuits encode prior knowledge of temporal statistics.
Journal: Nature neuroscience
In common: Open Ephys analysis tools, Image Processing Toolbox, Statistics and Machine Learning Toolbox, 5 other tools, systems, mouse, 1 reference
[7] doi:10.1002/aur.70312 [code]
Aberrant Neural Entrainment to Word-Level Speech Patterns in Fragile X Syndrome: Evidence for a Statistical Learning Deficit.
Journal: Autism research : official journal of the International Society for Autism Research
In common: Statistics and Machine Learning Toolbox, autism, EEG, other condition, 5 references
[8] doi:10.1038/s41593-026-02232-0 [code]
Entorhinal cortex represents task-relevant remote locations independently of CA1.
Journal: Nature neuroscience
In common: Pingouin, Image Processing Toolbox, statsmodels, 7 other tools, systems, mouse
[9] doi:10.1002/advs.202519479 [code]
Diminished Signal-to-Noise Ratio Disrupts Somatosensory Population Encoding and Drives Tactile Hyposensitivity in the Fmr1&lt;sup&gt;-/y&lt;/sup&gt; Autism Model.
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)
In common: Pingouin, statsmodels, seaborn, 5 other tools, autism, other condition, mouse, 1 reference
[10] doi:10.1126/sciadv.aef0343 [code]
Learning induces activation-mechanism-dependent neural plasticity in an intracortical microstimulation task.
Journal: Science advances
In common: Neo, Image Processing Toolbox, statsmodels, 7 other tools

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.

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.