OSCR

Compositionality of social gaze in the prefrontal-amygdala circuits.

Code ↔ Paper

18 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 18 matches · 2 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
  1. [1] § Methods › Neural data analysis › Canonical correlation analysis (CCA) ↔ analysisCode/Cross_area_CCA.m, the whole file · a weak match · score 0.98 · canonical correlation, L2 regularization, fold cross validation, Pearson correlation, independently shuffled, population activity
  2. [2] § Methods › Neural data analysis › Encoding model of representational dissimilarity matrix (RDM) ↔ analysisCode/rsa_core_analysis.py, lines 1–88 · score 0.93 · Euclidean distances, dissimilarity matrices, representational geometry, neural RDM, Neural activity, brain region
  3. [3] § Methods › Neural data analysis › Encoding model of representational dissimilarity matrix (RDM) ↔ analysisCode/rsa_core_analysis.py, lines 1–88 · score 0.85 · multiple linear regression, dependent variable, regression model, neural RDM, diagonal, vectorized
  4. [4] § Methods › Neural data analysis › Population decoding analyses › Content decoding ↔ analysisCode/Cross_primitive_decoding.py, lines 1–64 · score 0.82 · fold cross validation, neural population activity, classifier trained, shuffling controls, decoding, neurons
  5. [5] § Methods › Neural data analysis › Population decoding analyses › Content decoding ↔ analysisCode/Cross_area_CCA.m, the whole file · a weak match · score 0.78 · fold cross validation, shuffling controls, population activity, repetitions, gaze events, trained
  6. [6] § Methods › Neural data analysis › Population decoding analyses › Cross-conditions decoding ↔ analysisCode/Cross_primitive_decoding.py, lines 1–64 · score 0.76 · cross primitives decoding, fold cross validation, neural representation, social gaze primitives, abstract, classifiers
  7. [7] § Results › Linear mixed selectivity neurons facilitate the generalization of social gaze primitives ↔ codes_for_figures1-5.py, lines 530–587 · score 0.75 · nonlinear mixed selectivity, pure content selective, pure state selective, error bars, neuron, BLA
  8. [8] § Methods › Behavioral data analysis › General linear mixed-effects modeling of M2’s social gaze ↔ analysisCode/GLMM.R, lines 44–116 · score 0.75 · lme4, M1 duration, M1 content, M1 state, binomial, logit
  9. [9] § Results › Linear mixed selectivity neurons facilitate the generalization of social gaze primitives ↔ codes_for_figures1-5.py, lines 530–587 · score 0.73 · nonlinear mixed selectivity, pure content selectivity, pure state selectivity, neuron, ACCg, BLA
  10. [10] § Methods › Behavioral data analysis › Control analyses for dominance hierarchy › Dominance as an additional predictor in the GLMM ↔ analysisCode/GLMM.R, lines 44–116 · score 0.61 · lme4, glmer, binomial, logit, GLMM, day
  11. [11] § Results › Combinations of social gaze primitives determine interactive social gaze behavior ↔ codes_for_supplementary_figuresS2-S16.py, lines 402–439 · score 0.58 · log odds, error bars, confidence intervals, Vertical, GLMM, positions
  12. [12] § Results › Combinations of social gaze primitives determine interactive social gaze behavior ↔ codes_for_figures1-5.py, lines 94–146 · score 0.57 · log odds, Predicted probabilities, M1 content, GLMM, square, bars
  13. [13] § Results › Combinations of social gaze primitives determine interactive social gaze behavior ↔ codes_for_figures1-5.py, lines 188–237 · score 0.57 · Predicted probabilities, M1 duration, M1 state, social gaze, Interaction, M2
  14. [14] § Methods › Neural data analysis › Population decoding analyses › Cross-primitives decoding ↔ analysisCode/Cross_primitive_decoding.py, lines 112–137 · score 0.56 · cross primitives decoding, fold, accuracy, classifier, trained, shuffled
  15. [15] § Results › Linear mixed selectivity neurons facilitate the generalization of social gaze primitives ↔ codes_for_supplementary_figuresS2-S16.py, lines 544–583 · score 0.55 · variance inflation, S9, VIF, collinearity, threshold, predictors
  16. [16] § Results › Combinations of social gaze primitives determine interactive social gaze behavior ↔ codes_for_supplementary_figuresS2-S16.py, lines 119–159 · score 0.54 · transformed correlation, S2, Fisher, pupil, median, bouts
  17. [17] § Methods › Neural data analysis › Population PSTHs recoded by state or content preference ↔ codes_for_supplementary_figuresS2-S16.py, lines 742–776 · score 0.52 · Population PSTHs, gaze onset, Firing rates, 200 ms
  18. [18] § Methods › Behavioral data analysis › Control analyses for dominance hierarchy › Dominance as an additional predictor in the GLMM ↔ codes_for_supplementary_figuresS2-S16.py, lines 402–439 · score 0.51 · log odds, confidence intervals, Dominance, GLMM

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

Python · 1,220 lines · 42 KB · no license · 5 matches

  1. #%% import libs
  2. import copy
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. import pandas as pd
  6. import seaborn as sns
  7. import scipy.stats as stats
  8. import pickle as pkl
  9. import matplotlib.colors as mcolors
  10. import matplotlib.collections as mcoll
  11. import matplotlib.cm as cm
  12. from scipy.stats import chi2
  13. #%% --------- figure S2 ---------
  14. #%% import figure S2 data
  15. dataS2 = pkl.load(open('figure_S2_data.pkl', 'rb'))
  16. sociFracMartMiniBlocResh = dataS2['sociFracMartMiniBlocResh']
  17. pupiMartMiniBlocResh = dataS2['pupiMartMiniBlocResh']
  18. pearColl_trans = dataS2['pearColl_trans']
  19. sociFracMartMiniBloc = dataS2['sociFracMartMiniBloc']
  20. pupiMartMiniBloc = dataS2['pupiMartMiniBloc']
  21. #%% plot figure S2A
  22. inpuData = copy.deepcopy(sociFracMartMiniBlocResh)
  23. with plt.style.context('style_paper.mplstyle'):
  24. # sns.set(style = "ticks")
  25. f, ax1 = plt.subplots(ncols=1, nrows=1, sharey=True,figsize=[3.54/1.5,3.54/2])
  26. g1 = sns.heatmap(
  27. inpuData,
  28. yticklabels = [i for i in range(1,inpuData.shape[0]+1)],
  29. cmap = 'viridis',
  30. # square = True,
  31. # linewidths=0.2,
  32. ax = ax1)
  33. ax1.set_yticks([1,11,21,31,41],[1,11,21,31,41])
  34. ax1.set_xticks([1.5,4.5,7.5,10.5,13.5,16.5,19.5,22.5],[1,2,3,4,5,6,7,8])
  35. plt.xlabel('Run')
  36. plt.ylabel('Session')
  37. plt.tight_layout()
  38. fileName = 'figS2A_social_bouts_fraction.pdf'
  39. # plt.savefig(fileName,dpi = 600)
  40. plt.show()
  41. #%% plot figure S2B
  42. inpuData = copy.deepcopy(pupiMartMiniBlocResh)
  43. with plt.style.context('style_paper.mplstyle'):
  44. # sns.set(style = "ticks")
  45. f, ax1 = plt.subplots(ncols=1, nrows=1, sharey=True,figsize=[3.54/1.5,3.54/2])
  46. g1 = sns.heatmap(
  47. inpuData,
  48. # xticklabels = [i for i in range(1,9)],
  49. yticklabels = [i for i in range(1,inpuData.shape[0]+1)],
  50. # yticklabels = [i for i in range(1,inpuData.shape[0]+1)],
  51. # cbar=False,
  52. # cmap = 'viridis',
  53. # square = True,
  54. # linewidths=0.2,
  55. ax = ax1)
  56. ax1.set_yticks([1,11,21,31,41],[1,11,21,31,41])
  57. ax1.set_xticks([1.5,4.5,7.5,10.5,13.5,16.5,19.5,22.5],[1,2,3,4,5,6,7,8])
  58. # ax1.set_yticks([,11,21,31,41],[1,11,21,31,41])
  59. # ax1.set_yticks([1,6,11],[1,6,11])
  60. plt.xlabel('Block')
  61. plt.ylabel('Session')
  62. # ax1.set_xticks([])
  63. # ax1.set_yticklabels(['1','0.5','0','-0.5'],rotation = 0)
  64. # plt.title('')
  65. plt.tight_layout()
  66. # fileName = 'blocLabelMatr_all_group.pdf'
  67. fileName = 'figS2B_blocLabelMatr_all_pupil.pdf'
  68. # plt.savefig(fileName,dpi = 600)
  69. plt.show()
  70. print(stats.ttest_1samp(pearColl_trans, 0))
  71. #%% plot figure S2C
  72. all_stateIndex = []
  73. all_pupilIndex = []
  74. with plt.style.context('style_paper.mplstyle'):
  75. plt.figure(figsize=(3.54/1.5, 3.54/2))
  76. for i in range(42):
  77. stateIndex = sociFracMartMiniBloc[i, :, :].flatten()
  78. pupilIndex = pupiMartMiniBloc[i, :, :].flatten()
  79. # Convert to DataFrame for seaborn plotting
  80. df_i = pd.DataFrame({'StateIndex': stateIndex, 'PupilIndex': pupilIndex})
  81. # Plot the linear regression line for each day (index i)
  82. sns.regplot(x='StateIndex', y='PupilIndex', data=df_i, scatter=False, ci=False,
  83. scatter_kws={'s': 5,
  84. 'alpha':.5,
  85. "edgecolor": "none",
  86. "color": "black"},
  87. line_kws={'color': '#1f77b4',
  88. 'lw':1,
  89. 'alpha': 0.75}, ax=plt.gca())
  90. # plt.title('Linear Regression Lines for Each Day (42 Lines)')
  91. plt.xlabel('Social bouts fraction')
  92. plt.ylabel('Pupil size\n(normalized)')
  93. plt.tight_layout()
  94. fileName = 'figS2C_linear_regression_social_state_pupil.pdf'
  95. # plt.savefig(fileName,dpi = 600)
  96. plt.show()
  97. #%% plot figure S2D
  98. with plt.style.context('style_paper.mplstyle'):
  99. plt.figure(figsize=(3.54/1.5, 3.54/2))
  100. # Histogram of Fisher Z transformed correlations
  101. # plt.figure(figsize=(3.54/2, 3.54/3))
  102. plt.hist(pearColl_trans, bins=10, edgecolor='black', alpha=0.7, color = '#1f77b4')
  103. # Calculate the mean of the Fisher Z-transformed correlations
  104. mean_z = np.mean(pearColl_trans)
  105. # Plot the red line for the mean
  106. plt.axvline(mean_z, color='red', linestyle='dashed', linewidth=1)
  107. # Add annotation for the mean
  108. plt.annotate(f'Mean = {mean_z:.4f}', xy=(mean_z, 5), xytext=(mean_z + 0.01, 9),
  109. fontsize=8, color='red')
  110. # plt.title('Histogram of Fisher Z-transformed Pearson Correlations')
  111. # plt.xlabel('Fisher Z-transformed Correlation')
  112. # plt.ylabel('Frequency')
  113. # plt.show()
  114. # plt.title('Histogram of Fisher Z-transformed Pearson Correlations')
  115. plt.xlabel('Correlation\n(Fisher Z-transformed)')
  116. plt.ylabel('Frequency')
  117. # plt.xlabel('Social bouts fraction')
  118. # plt.ylabel('Pupil size\n(normalized)')
  119. plt.tight_layout()
  120. fileName = 'figS2D_Fisher Z-transformed_corr_social_state_pupil.pdf'
  121. # plt.savefig(fileName,dpi = 600)
  122. plt.show()
  123. #%% --------- figure S3 ---------
  124. #%% import figure S3 data
  125. dataS3 = pkl.load(open('figure_S3_data.pkl', 'rb'))
  126. duraDisColl = dataS3['duraDisColl']
  127. faceDisColl = dataS3['faceDisColl']
  128. #%% plot duration distribution
  129. # Set up figure with shared axes
  130. with plt.style.context('style_paper.mplstyle'):
  131. fig, axes = plt.subplots(7, 6, figsize=(8, 6),)
  132. axes = axes.flatten()
  133. for i in range(42):
  134. session_data = np.array(duraDisColl[i])
  135. median = np.median(session_data)
  136. # Bin edges and centers
  137. bins = np.histogram_bin_edges(session_data, bins=25)
  138. bin_centers = 0.5 * (bins[1:] + bins[:-1])
  139. bin_width = bins[1] - bins[0]
  140. half_width = bin_width * 0.5
  141. # Count values by group
  142. short_counts = np.zeros(len(bins) - 1)
  143. long_counts = np.zeros(len(bins) - 1)
  144. bin_indices = np.digitize(session_data, bins) - 1
  145. for val, idx in zip(session_data, bin_indices):
  146. if 0 <= idx < len(short_counts):
  147. if val < median:
  148. short_counts[idx] += 1
  149. else:
  150. long_counts[idx] += 1
  151. # Plot side-by-side bars
  152. axes[i].bar(bin_centers - half_width * 0.5, short_counts,
  153. width=half_width, color='white', edgecolor='gray', label='Short (< median)')
  154. axes[i].bar(bin_centers + half_width * 0.5, long_counts,
  155. width=half_width, color='black', edgecolor='black', label='Long (≥ median)')
  156. axes[i].set_title(f'#{i+1}', fontsize=8)
  157. # Add legend and axis labels only to first subplot
  158. if i == 0:
  159. axes[i].legend(fontsize=6, loc='upper right')
  160. # Set common labels
  161. fig.text(0.5, 0, 'Gaze duration (s)', ha='center', fontsize=10)
  162. fig.text(0.0, 0.5, 'Gaze bouts number', va='center', rotation='vertical', fontsize=10)
  163. plt.tight_layout(rect=[0.06, 0.04, 1, 1])
  164. plt.tight_layout()
  165. fileName = 'figS3A_gazeDuraDistribu.pdf'
  166. # plt.savefig(fileName,dpi = 600)
  167. plt.show()
  168. # plt.show()
  169. #%% plot distribution of gaze content
  170. faceDisColl_face = [faceDisColl[i][0] for i in range(42)]
  171. faceDisColl_object = [faceDisColl[i][1] for i in range(42)]
  172. with plt.style.context('style_paper.mplstyle'):
  173. fig, axes = plt.subplots(1, 2, figsize=(4, 3),)
  174. axes = axes.flatten()
  175. plt.subplot(121)
  176. plt.hist(faceDisColl_face,color = '#E97F26')
  177. plt.ylabel('Sessions')
  178. plt.xlabel('Face gaze numbers')
  179. plt.subplot(122)
  180. plt.hist(faceDisColl_object,color = '#6BBA44')
  181. plt.xlabel('Object gaze numbers')
  182. # plt.
  183. fileName = 'figS3B_gazeContentDistribu.pdf'
  184. # plt.savefig(fileName,dpi = 600)
  185. plt.show()
  186. #%% --------- figure S4 ---------
  187. #%% import figure S4 data
  188. dataS4 = pkl.load(open('figure_S4_data.pkl', 'rb'))
  189. lrt_vs_full = dataS4['lrt_vs_full']
  190. delta_aic_vs_full = dataS4['delta_aic_vs_full']
  191. #%% plot figure S4A
  192. # LRT results vs full model
  193. # lrt_vs_full = pd.DataFrame({
  194. # "Removed_Primitive": ["State", "Content", "Duration"],
  195. # "Delta_2LL": [16.080, 58.362, 16.283],
  196. # "df": [4, 4, 4],
  197. # "p_value": [2.913e-03, 6.406e-12, 2.662e-03]
  198. # })
  199. # # ΔAIC vs full model
  200. # delta_aic_vs_full = pd.DataFrame({
  201. # "Removed_Primitive": ["State", "Content", "Duration"],
  202. # "DeltaAIC": [8.080167, 50.362017, 8.282597]
  203. # })
  204. with plt.style.context('style_paper.mplstyle'):
  205. fig, ax = plt.subplots(figsize=(4, 5))
  206. bars = ax.bar(
  207. lrt_vs_full["Removed_Primitive"],
  208. lrt_vs_full["Delta_2LL"],
  209. color="lightgray"
  210. )
  211. # Text annotations
  212. for i, row in lrt_vs_full.iterrows():
  213. ax.text(
  214. i,
  215. row["Delta_2LL"] + 1,
  216. f"df={row['df']}\nP={row['p_value']:.3g}",
  217. ha="center",
  218. va="bottom",
  219. fontsize=10
  220. )
  221. # Chi-square critical line (df = 4, alpha = 0.05)
  222. crit_df4 = chi2.ppf(0.95, df=4)
  223. ax.axhline(
  224. crit_df4,
  225. linestyle="--",
  226. alpha=0.6,
  227. color='gray'
  228. )
  229. ax.set_ylabel(r"$\Delta$ -2 log L (relative to full model)", fontsize=20)
  230. ax.set_xlabel("Primitive removed", fontsize=20)
  231. ax.tick_params(labelsize=18)
  232. plt.tight_layout()
  233. # plt.savefig("figS4A_Delta_2LL_primitives_remove.pdf", dpi=600)
  234. plt.show()
  235. # plt.close()
  236. #%% plot ΔAIC vs full model
  237. with plt.style.context('style_paper.mplstyle'):
  238. fig, ax = plt.subplots(figsize=(4, 5))
  239. # ax.axhline(2, linestyle="--", alpha=0.6, color='k')
  240. # ax.axhline(6, linestyle=":", alpha=0.6, color='k')
  241. ax.bar(
  242. delta_aic_vs_full["Removed_Primitive"],
  243. delta_aic_vs_full["DeltaAIC"],
  244. color="steelblue",alpha=0.8
  245. )
  246. # AIC rule-of-thumb thresholds
  247. ax.set_ylabel(r"$\Delta$ AIC (relative to full model)", fontsize=20)
  248. ax.set_xlabel("Primitive removed", fontsize=20)
  249. ax.tick_params(labelsize=18)
  250. plt.tight_layout()
  251. # plt.savefig("figS4B_Delta_AIC_primitives_remove.pdf", dpi=600)
  252. plt.show()
  253. # plt.close()
  254. #%% --------- figure S5 ---------
  255. #%% import figure S5 data
  256. dataS5 = pkl.load(open('figure_S5_data.pkl', 'rb'))
  257. coefs_pub = dataS5['coefs_pub']
  258. plot_state_df = dataS5['plot_state_df']
  259. #%% plot figure S5A
  260. # Sort predictors for better visualization
  261. coefs_pub_sorted = coefs_pub.sort_values("Estimate (log-odds)")
  262. with plt.style.context('style_paper.mplstyle'):
  263. fig, ax = plt.subplots(figsize=(5, 2))
  264. ax.errorbar(
  265. coefs_pub_sorted["Estimate (log-odds)"],
  266. coefs_pub_sorted["Predictor"],
  267. xerr=[
  268. coefs_pub_sorted["Estimate (log-odds)"] - coefs_pub_sorted["95% CI (Lower)"],
  269. coefs_pub_sorted["95% CI (Upper)"] - coefs_pub_sorted["Estimate (log-odds)"]
  270. ],
  271. fmt='.',
  272. color='#1f77b4', # consistent scientific blue
  273. ecolor='gray',
  274. capsize=0
  275. )
  276. ax.axvline(0, color='black', linestyle='--', linewidth=0.8)
  277. ax.set_xlabel("Estimate (log odds)", fontsize=9)
  278. ax.set_ylabel("Predictor",)
  279. ax.tick_params(axis='both')
  280. plt.tight_layout()
  281. fileName = 'figS5A_GLMM_Fixed_Effects_Social_State.pdf'
  282. # plt.savefig(fileName,dpi = 600)
  283. plt.show()
  284. #%% figS5B Predicted Probability for M1_state (Low vs. High)
  285. # Create bar plot
  286. with plt.style.context('style_paper.mplstyle'):
  287. fig, ax = plt.subplots(figsize=(1.75, 2))
  288. ax.bar(plot_state_df['M1_state'], plot_state_df['prob'],
  289. yerr=[plot_state_df['prob'] - plot_state_df['asymp.LCL'],
  290. plot_state_df['asymp.UCL'] - plot_state_df['prob']],
  291. capsize=0, color=['lightgray', 'orchid'], edgecolor='black')
  292. ax.set_title("Main effect: M1 state", fontsize=10)
  293. ax.set_ylabel("Predicted probability\n of M2 high social state")
  294. ax.set_xlabel("M1 state")
  295. ax.set_ylim(0, 0.8)
  296. # plt.grid(axis='y', linestyle='--', alpha=0.7)
  297. plt.tight_layout()
  298. fileName = 'figS5B_Predicted_Probability_of_M2_Social_State_by_M1_State.pdf'
  299. # plt.savefig(fileName,dpi = 600)
  300. plt.show()
  301. #%% --------- figure S6 ---------
  302. #%% import figure S6 data
  303. figure_S6_data = pkl.load(open('figure_S6_data.pkl', 'rb'))
  304. coefs_fixed = figure_S6_data['coefs_fixed']
  305. coefs_random = figure_S6_data['coefs_random']
  306. #%%
  307. # coefs_fixed = pd.DataFrame({
  308. # "term": [
  309. # "Intercept",
  310. # "M1_state1",
  311. # "M1_content1",
  312. # "M1_duration1",
  313. # "dominant1",
  314. # "M1_state1 × M1_content1",
  315. # "M1_state1 × M1_duration1",
  316. # "M1_content1 × M1_duration1",
  317. # "M1_state1 × dominant1",
  318. # "M1_content1 × dominant1",
  319. # "M1_duration1 × dominant1",
  320. # "M1_state1 × M1_content1 × M1_duration1",
  321. # "M1_state1 × M1_content1 × dominant1",
  322. # "M1_state1 × M1_duration1 × dominant1",
  323. # "M1_content1 × M1_duration1 × dominant1",
  324. # "M1_state1 × M1_content1 × M1_duration1 × dominant1"
  325. # ],
  326. # "estimate": [
  327. # -1.96, 0.388, 0.659, -0.0376, -0.158,
  328. # -0.369, 0.196, -0.108, -0.0488, -0.226,
  329. # 0.234, -0.170, 0.180, -0.388, -0.162, 0.175
  330. # ],
  331. # "conf.low": [
  332. # -2.56, -0.00504, 0.408, -0.380, -0.985,
  333. # -0.791, -0.388, -0.489, -0.535, -0.565,
  334. # -0.187, -0.793, -0.361, -1.11, -0.659, -0.621
  335. # ],
  336. # "conf.high": [
  337. # -1.35, 0.782, 0.910, 0.305, 0.670,
  338. # 0.0521, 0.779, 0.273, 0.438, 0.113,
  339. # 0.656, 0.454, 0.720, 0.331, 0.336, 0.972
  340. # ]
  341. # })
  342. #%%
  343. coefs_fixed = coefs_fixed.sort_values("estimate")
  344. y_pos = range(len(coefs_fixed))
  345. #%%
  346. with plt.style.context('style_paper.mplstyle'):
  347. plt.figure(figsize=(6, 4))
  348. # error bars
  349. plt.hlines(
  350. y=y_pos,
  351. xmin=coefs_fixed["conf.low"],
  352. xmax=coefs_fixed["conf.high"],
  353. color="gray",
  354. linewidth=1
  355. )
  356. # points
  357. plt.scatter(
  358. coefs_fixed["estimate"],
  359. y_pos,
  360. color="blue",
  361. s=120
  362. )
  363. # vertical zero line
  364. plt.axvline(0, linestyle="--", color="black", linewidth=0.8)
  365. # axes
  366. plt.yticks(y_pos, coefs_fixed["term"])
  367. plt.xlabel("Estimate (Log Odds)")
  368. plt.title("GLMM Fixed Effects with 95% Confidence Intervals")
  369. plt.grid(axis="x", alpha=0.3)
  370. plt.grid(axis="y", visible=False)
  371. plt.tight_layout()
  372. plt.savefig("figS6A_GLMM_fixed_effects_with_fixed_dominant.pdf", format="pdf", dpi=600)
  373. plt.show()
  374. # plt.close()
  375. #%% plot figure S6B
  376. # coefs_random = pd.DataFrame({
  377. # "term": [
  378. # "Intercept",
  379. # "M1_state1",
  380. # "M1_content1",
  381. # "M1_duration1",
  382. # "M1_state1 × M1_content1",
  383. # "M1_state1 × M1_duration1",
  384. # "M1_content1 × M1_duration1",
  385. # "M1_state1 × M1_content1 × M1_duration1"
  386. # ],
  387. # "estimate": [
  388. # -2.02, 0.361, 0.543, 0.122,
  389. # -0.289, -0.0655, -0.239, 0.00232
  390. # ],
  391. # "conf.low": [
  392. # -2.48, 0.132, 0.378, -0.0765,
  393. # -0.544, -0.401, -0.475, -0.372
  394. # ],
  395. # "conf.high": [
  396. # -1.57, 0.590, 0.707, 0.320,
  397. # -0.0330, 0.270, -0.00237, 0.376
  398. # ]
  399. # })
  400. coefs_random = coefs_random.sort_values("estimate")
  401. y_pos = range(len(coefs_random))
  402. with plt.style.context('style_paper.mplstyle'):
  403. plt.figure(figsize=(6, 4))
  404. plt.hlines(
  405. y=y_pos,
  406. xmin=coefs_random["conf.low"],
  407. xmax=coefs_random["conf.high"],
  408. color="gray",
  409. linewidth=1
  410. )
  411. plt.scatter(
  412. coefs_random["estimate"],
  413. y_pos,
  414. color="blue",
  415. s=120
  416. )
  417. plt.axvline(0, linestyle="--", color="black", linewidth=0.8)
  418. plt.yticks(y_pos, coefs_random["term"])
  419. plt.xlabel("Estimate (Log Odds)")
  420. plt.title("GLMM Fixed Effects with 95% Confidence Intervals")
  421. plt.grid(axis="x", alpha=0.3)
  422. plt.grid(axis="y", visible=False)
  423. plt.tight_layout()
  424. # plt.savefig("figS6B_GLMM_fixed_effects_with_random_dominant.pdf", format="pdf", dpi=600)
  425. plt.show()
  426. # plt.close()
  427. #%% --------- figure S7 ---------
  428. #%% import figure S7 data
  429. dataS7 = pkl.load(open('figure_S7_data.pkl', 'rb'))
  430. permTestMeanPartiaRegre = dataS7['permTestMeanPartiaRegre']
  431. permTestStdPartiaRegre = dataS7['permTestStdPartiaRegre']
  432. coffMatrPartiaRegre = dataS7['coffMatrPartiaRegre']
  433. #%% plot figure S7
  434. hypoLabes = ['Content', 'State', 'Duration']
  435. areas = ['BLA','ACCg','dmPFC','OFC']
  436. with plt.style.context('style_paper.mplstyle'):
  437. fig, ax = plt.subplots(figsize=(3.45*2.35,3.54/1.5))
  438. widt = 0.2
  439. colors = sns.color_palette()
  440. i = 0
  441. for j in [1,0,2,3]:# range(0,4):
  442. # i = 0
  443. plt.bar([1+i*widt,2+i*widt,3+i*widt],coffMatrPartiaRegre[j,[1,0,2],0],width = widt*0.75,label = areas[i],color = colors[j])
  444. if i==3:
  445. plt.errorbar([1+i*widt,2+i*widt,3+i*widt],permTestMeanPartiaRegre[j,[1,0,2]], yerr=permTestStdPartiaRegre[j,[1,0,2]]*1,
  446. lw = 0.5,
  447. color = 'black',
  448. linestyle='none',
  449. label='Shuffled data ± 1 std',capsize=1,)
  450. else:
  451. plt.errorbar([1+i*widt,2+i*widt,3+i*widt],permTestMeanPartiaRegre[j,[1,0,2]],
  452. yerr=permTestStdPartiaRegre[j,[1,0,2]]*1,
  453. lw = 0.5,
  454. color = 'black',
  455. linestyle='none',
  456. capsize=1)
  457. i+=1
  458. plt.xticks([1+1.5*widt,2+1.5*widt,3+1.5*widt],hypoLabes )
  459. plt.xlabel('Model RDM')
  460. plt.ylabel('Partial regression coefficient')
  461. # plt.legend(loc='upper right', bbox_to_anchor=(1, 1.1))
  462. plt.legend(bbox_to_anchor=(1, 0.8))
  463. # plt.tight_layout()
  464. fileName = 'figS7_partRegrRDMShufPost_mini_block_updated.pdf'
  465. # plt.savefig(fileName,dpi = 600)
  466. plt.show()
  467. #%% --------- figure S9 ---------
  468. #%% import figure S9 data
  469. dataS9 = pkl.load(open('figure_S9_data.pkl', 'rb'))
  470. df_vif = dataS9['df_vif']
  471. #%% --------- plot ----------
  472. with plt.style.context('style_paper.mplstyle'):
  473. fig, axes = plt.subplots(
  474. 1, 1,
  475. figsize=(6./2/2, 2.6/1.5),
  476. # gridspec_kw={"width_ratios": [1, 1.2]}
  477. )
  478. sns.boxplot(
  479. data=df_vif,
  480. x="Predictor",
  481. y="VIF",
  482. ax=axes,
  483. palette=["#4C72B0", "#DD8452"],
  484. width=0.5,
  485. flierprops=dict(
  486. marker='o',
  487. markersize=2,
  488. markerfacecolor='gray',
  489. markeredgecolor='gray',
  490. alpha=0.6
  491. )
  492. )
  493. # VIF threshold
  494. axes.axhline(5, ls="--", lw=0.8, color="gray", alpha=0.6)
  495. axes.set_xlabel("")
  496. axes.set_ylabel("Variance inflation\nfactor (VIF)")
  497. axes.set_title("Collinearity")
  498. axes.set_ylim([0.5, 5.2])
  499. axes.set_xticks([0,1],['Content','State'])
  500. plt.tight_layout()
  501. fileName = 'figS9_pairCorrVIF_pool_neurons.pdf'
  502. # plt.savefig(fileName,dpi = 600)
  503. plt.show()
  504. #%% --------- figure S10 ---------
  505. #%% import figure S10 data
  506. dataS10 = pkl.load(open('figure_S10_data.pkl', 'rb'))
  507. PSTHColl = dataS10['PSTHColl']
  508. examNeurDataColl = dataS10['examNeurDataColl']
  509. #%% helper function for plotting mean with shaded error bars
  510. def plot_mean_with_shade(data, label, color, linestyle='-', alpha=0.3,
  511. edge_alpha=1.0, edge_lw=0.8, edge_ls='-',timepoints = np.arange(200)):
  512. mean = np.mean(data, axis=0)
  513. sem = np.std(data, axis=0) / np.sqrt(data.shape[0])
  514. lower = mean - sem
  515. upper = mean + sem
  516. # Shaded fill
  517. ax.fill_between(timepoints, lower, upper, color=color, alpha=alpha)
  518. # Edge lines as dashed or solid lines
  519. ax.plot(timepoints, upper, color=color, linestyle=edge_ls, linewidth=edge_lw, alpha=edge_alpha)
  520. ax.plot(timepoints, lower, color=color, linestyle=edge_ls, linewidth=edge_lw, alpha=edge_alpha)
  521. # Mean line
  522. ax.plot(timepoints, mean, color=color, linestyle=linestyle, label=label)
  523. #%% plot example neuron PSTHs (face vs object, high vs low state)
  524. for i in PSTHColl.keys():
  525. socialHighActiv = PSTHColl[i]['socialHighActiv']
  526. socialLowActiv = PSTHColl[i]['socialLowActiv']
  527. nonSocialHighActiv = PSTHColl[i]['nonSocialHighActiv']
  528. nonSocialLowActiv = PSTHColl[i]['nonSocialLowActiv']
  529. with plt.style.context('style_paper.mplstyle'):
  530. fig, ax = plt.subplots(figsize=[3.54/2, 3.54/2.5])
  531. timepoints = np.arange(100)
  532. # Plot all four conditions with edge-highlighted shaded error
  533. plot_mean_with_shade(socialHighActiv, 'Face High', color='#e97f26', linestyle='-',edge_ls='', alpha=0.8)
  534. plot_mean_with_shade(socialLowActiv, 'Face Low', color='#E97F26', linestyle='--', alpha=0.2, edge_ls='', edge_alpha=0.15)
  535. plot_mean_with_shade(nonSocialHighActiv, 'Object High', color='#6bba44', linestyle='-', edge_ls='',alpha=0.8)
  536. plot_mean_with_shade(nonSocialLowActiv, 'Object Low', color='#6bba44', linestyle='--', alpha=0.2, edge_ls='', edge_alpha=0.15)
  537. # Axes and ticks
  538. ax.set_xlabel('Time from gaze onset (s)')
  539. ax.set_ylabel('Firing rate\n(normalized)')
  540. plt.xticks([0,50,100,150,200],
  541. [ -1, -0.5,0,0.5,1]) # Set x-ticks to match
  542. ax.set_xlim(50, 200)
  543. plt.tight_layout()
  544. figureName = f'figS10_PSTH_number_{i}.pdf'
  545. # plt.savefig(figureName,dpi = 600)
  546. plt.show()
  547. plt.close()
  548. #%% plot example neuron firing rate bar plot (face vs object, high vs low state)
  549. for i in examNeurDataColl.keys():
  550. # means = examNeurDataColl[i]['means']
  551. # sems = examNeurDataColl[i]['sems']
  552. counts = examNeurDataColl[i]['counts']
  553. df = examNeurDataColl[i]['df']
  554. normFiringRates = df['FiringRate'].values
  555. x_labels = ['Face', 'Object']
  556. x = np.arange(len(x_labels))
  557. bar_width = 0.35
  558. with plt.style.context('style_paper.mplstyle'):
  559. fig, ax = plt.subplots(
  560. ncols=1,
  561. nrows=1,
  562. figsize=[3.54 / 2, 3.54 / 2.5]
  563. )
  564. face_color = '#e97f26'
  565. object_color = '#6bba44'
  566. for ii, content in enumerate(x_labels):
  567. color = face_color if content == 'Face' else object_color
  568. x_high = x[ii] - bar_width / 1.8
  569. x_low = x[ii] + bar_width / 1.8
  570. high_key = (content, 'High state')
  571. low_key = (content, 'Low state')
  572. high_vals = df[
  573. (df['Content'] == content)
  574. & (df['State'] == 'High state')
  575. ]['FiringRate'].values
  576. low_vals = df[
  577. (df['Content'] == content)
  578. & (df['State'] == 'Low state')
  579. ]['FiringRate'].values
  580. # -------------------------
  581. # Boxplot as distribution summary
  582. # -------------------------
  583. bp = ax.boxplot(
  584. [high_vals, low_vals],
  585. positions=[x_high, x_low],
  586. widths=0.22,
  587. patch_artist=True,
  588. showfliers=False,
  589. medianprops={
  590. 'color': 'black',
  591. 'linewidth': 1.0
  592. },
  593. boxprops={
  594. 'linewidth': 1.0
  595. },
  596. whiskerprops={
  597. 'linewidth': 0.8
  598. },
  599. capprops={
  600. 'linewidth': 0.8
  601. },
  602. zorder=2
  603. )
  604. bp['boxes'][0].set_facecolor(color)
  605. bp['boxes'][0].set_alpha(0.30)
  606. bp['boxes'][0].set_edgecolor(color)
  607. bp['boxes'][1].set_facecolor('white')
  608. bp['boxes'][1].set_alpha(1.0)
  609. bp['boxes'][1].set_edgecolor(color)
  610. bp['boxes'][1].set_linestyle('--')
  611. for whisker in bp['whiskers']:
  612. whisker.set_color(color)
  613. for cap in bp['caps']:
  614. cap.set_color(color)
  615. ax.set_xticks(x)
  616. ax.set_xticklabels(x_labels)
  617. ax.set_xlabel('Content')
  618. ax.set_ylabel('Firing rate\n(normalized)')
  619. # ax.set_ylim(0, 1.12)
  620. ax.spines['top'].set_visible(False)
  621. ax.spines['right'].set_visible(False)
  622. fileName = (
  623. 'figS10_example_neur'
  624. + '_inde_'
  625. + str(i)
  626. + '_'
  627. + '_boxplot_update.pdf'
  628. )
  629. plt.tight_layout()
  630. # Uncomment to save
  631. # plt.savefig(figPath + fileName, dpi=300, bbox_inches='tight')
  632. plt.show()
  633. #%% --------- figure S11 ---------
  634. #%% import figure S11 data
  635. dataS11 = pkl.load(open('figure_S11_data.pkl', 'rb'))
  636. psthPreNonPreColl = dataS11['psthPreNonPreColl']
  637. #%% plot population PSTHs for preferred vs non-preferred conditions, with significant clusters highlighted
  638. areas =['ACCg','BLA','dmPFC','OFC']
  639. # =========================================================
  640. # loop: content & state
  641. # =========================================================
  642. bin_size_ms = 10
  643. time_ms = (np.arange(200) - 100) * bin_size_ms
  644. time_bins = np.arange(200)
  645. for primitive in ['content', 'state']:
  646. for ss in range(4):
  647. mean_p = psthPreNonPreColl[primitive][areas[ss]]['mean_p']
  648. sem_p = psthPreNonPreColl[primitive][areas[ss]]['sem_p']
  649. mean_n = psthPreNonPreColl[primitive][areas[ss]]['mean_n']
  650. sem_n = psthPreNonPreColl[primitive][areas[ss]]['sem_n']
  651. sig_clusters = psthPreNonPreColl[primitive][areas[ss]]['sig_clusters']
  652. # ---------- plot ----------
  653. with plt.style.context('style_paper.mplstyle'):
  654. fig, ax = plt.subplots(figsize=(3.2, 2.4))
  655. ax.plot(time_bins, mean_p, label='Preferred')
  656. ax.fill_between(time_bins, mean_p-sem_p, mean_p+sem_p, alpha=0.3)
  657. ax.plot(time_bins, mean_n, label='Non-preferred')
  658. ax.fill_between(time_bins, mean_n-sem_n, mean_n+sem_n, alpha=0.3)
  659. for cl in sig_clusters:
  660. ax.plot([cl[0],cl[-1]],[0.20,0.20],color='k')
  661. ax.axvline(100, ls='--', lw=0.8, color='gray')
  662. ax.set_xticks([0, 50, 100, 150, 200])
  663. ax.set_xticklabels([-1000, -500, 0, 500, 1000])
  664. ax.set_xlabel('Time from gaze onset (ms)')
  665. ax.set_ylabel('Firing rate (normalized)')
  666. ax.set_title(f'{areas[ss]} population PSTH ({primitive})')
  667. ax.legend(frameon=False)
  668. plt.tight_layout()
  669. fileName = f'figure_S11_{areas[ss]} population PSTH ({primitive})'+'.pdf'
  670. # plt.savefig(fileName,dpi = 600)
  671. plt.show()
  672. #%% --------- figure S12 ---------
  673. #%% import figure S12 data
  674. dataS12 = pkl.load(open('figure_S12_data.pkl', 'rb'))
  675. coffMatr= dataS12['coffMatr']
  676. permTestMean= dataS12['permTestMean']
  677. permTestStd= dataS12['permTestStd']
  678. # %% plot
  679. hypoLabes = [ 'Content','State', 'Duration']
  680. areas = ['BLA','ACCg','dmPFC','OFC']
  681. with plt.style.context('style_paper.mplstyle'):
  682. fig, ax = plt.subplots(figsize=(3.45*2.35,3.54/1.5))
  683. widt = 0.2
  684. colors = sns.color_palette()
  685. i = 0
  686. # for j in range([0,4)]:
  687. for j in [1,0,2,3]:
  688. # i = 0
  689. plt.bar([1+i*widt,2+i*widt,3+i*widt],coffMatr[j,[1,0,2],0],width = widt*0.75,label = areas[i],color = colors[j])
  690. if i==3:
  691. plt.errorbar([1+i*widt,2+i*widt,3+i*widt],permTestMean[j,[1,0,2]], yerr=permTestStd[j,[1,0,2]]*1,
  692. lw = 0.5,
  693. color = 'black',
  694. linestyle='none',
  695. label='Shuffled data ± 1 std',capsize=1)
  696. else:
  697. plt.errorbar([1+i*widt,2+i*widt,3+i*widt],permTestMean[j,[1,0,2]],
  698. yerr=permTestStd[j,[1,0,2]]*1,
  699. lw = 0.5,
  700. color = 'black',
  701. linestyle='none',
  702. capsize=1)
  703. i+=1
  704. plt.xticks([1+1.5*widt,2+1.5*widt,3+1.5*widt],hypoLabes )
  705. plt.xlabel('Model RDM')
  706. plt.ylabel('β estimate')
  707. plt.legend(bbox_to_anchor=(1, 0.8))
  708. # plt.tight_layout()
  709. fileName = 'figS12_encoding_model_remove_non_selective.pdf'
  710. # plt.savefig(fileName,dpi = 600)
  711. plt.show()
  712. #%% --------- figure S13 ---------
  713. #%% import figure S13 data
  714. dataS13 = pkl.load(open('figure_S13_data.pkl', 'rb'))
  715. crossDecodingMatrixACCg = dataS13['crossDecodingMatrixACCg']
  716. crossDecodingMatrixBLA = dataS13['crossDecodingMatrixBLA']
  717. crossDecodingMatrixdmPFC = dataS13['crossDecodingMatrixdmPFC']
  718. crossDecodingMatrixOFC = dataS13['crossDecodingMatrixOFC']
  719. #%% plot the data
  720. with plt.style.context("style_paper.mplstyle"):
  721. fig, ax = plt.subplots(figsize=(3.54/1.25, 3.45/2)) # Adjust aspect ratio for horizontal layout
  722. height = 0.1 # Bar height instead of width
  723. sns.heatmap(crossDecodingMatrixBLA,# adjust the matrix you want to plot
  724. square = True,vmin=0.5, vmax=1,annot=True,fmt=".2f",
  725. annot_kws={"size": 8},
  726. cbar_kws={'label': 'Decoding accuracy'})
  727. plt.xticks([0.5,1.5],['State','Content'])
  728. plt.yticks([0.5,1.5],['State','Content'])
  729. plt.xlabel('Testing')
  730. plt.ylabel('Training')
  731. # plt.title('BLA')
  732. plt.tight_layout()
  733. fileName = 'figS13_BLA_remo_non_sele.pdf'
  734. # plt.savefig(fileName,dpi = 600)
  735. plt.show()
  736. #%% --------- figure S14 ---------
  737. #%% import figure S14 data
  738. dataS14 = pkl.load(open('figure_S14_data.pkl', 'rb'))
  739. areas1 = dataS14['areas1']
  740. areas2 = dataS14['areas2']
  741. areas_paris = dataS14['areas_paris']
  742. inpuDataContentColl = dataS14['inpuDataContentColl']
  743. inpuDataAnnoContentColl = dataS14['inpuDataAnnoContentColl']
  744. #%% plot CCA results for content
  745. # Define significance annotation
  746. def significance_marker(val):
  747. if val < 0.001:
  748. return "***"
  749. elif val < 0.01:
  750. return "**"
  751. elif val < 0.05:
  752. return "*"
  753. else:
  754. return ""
  755. areas = ['ACCg','BLA','dmPFC','OFC']
  756. areas1 = ['ACCg','ACCg','ACCg','BLA', 'BLA', 'dmPFC']
  757. areas2 = ['BLA','dmPFC','OFC','dmPFC', 'OFC', 'OFC']
  758. areas_paris = ['ACCg_BLA','ACCg_dmPFC', 'ACCg_OFC','BLA_dmPFC','BLA_OFC', 'dmPFC_OFC']
  759. for i in range(6):
  760. inpuDataContent = copy.deepcopy(inpuDataContentColl[areas_paris[i]])
  761. inpuDataAnnoContent = copy.deepcopy(inpuDataAnnoContentColl[areas_paris[i]])
  762. with plt.style.context('style_paper.mplstyle'):
  763. # sns.set(style = "ticks")
  764. f, ax1 = plt.subplots(ncols=1, nrows=1, sharey=True,figsize=[3.54/1.5,3.54/2])
  765. g1 = sns.heatmap(
  766. inpuDataContent[1:4,1:4],
  767. annot=inpuDataAnnoContent[1:4,1:4], fmt="",
  768. # cbar=False,
  769. cmap = 'viridis',
  770. square = True,
  771. linewidths=0.2,
  772. vmin=0, vmax=0.5,
  773. ax = ax1)
  774. ax1.set_yticklabels(['-0.2','0','0.2'],rotation = 0)
  775. ax1.set_xticklabels(['-0.2','0','0.2'],rotation = 0)
  776. # ax1.set_yticklabels(['-0.4','-0.2','0','0.2','0.4'],rotation = 0)
  777. # ax1.set_xticklabels(['-0.4','-0.2','0','0.2','0.4'],rotation = 0)
  778. ax1.set_xlabel(areas2[i]+' time (s)')
  779. ax1.set_ylabel(areas1[i] +' time (s)')
  780. # ax1.set_yticklabels(['1','0.5','0','-0.5'],rotation = 0)
  781. # plt.title('')
  782. # plt.title([are,'State'])
  783. plt.tight_layout()
  784. fileName = 'figS14_CCA'+'content_'+areas1[i]+'_'+areas2[i]+'.pdf'
  785. # plt.savefig(fileName,dpi = 600)
  786. plt.show()
  787. #%% --------- figure S15 ---------
  788. #%% import figure S15 data
  789. dataS15 = pkl.load(open('figure_S15_data.pkl', 'rb'))
  790. areas1 = dataS15['areas1']
  791. areas2 = dataS15['areas2']
  792. areas_paris = dataS15['areas_paris']
  793. inpuDataStateColl = dataS15['inpuDataStateColl']
  794. inpuDataAnnoStateColl = dataS15['inpuDataAnnoStateColl']
  795. #%% plot CCA results for state, with significance annotation
  796. # Define significance annotation
  797. def significance_marker(val):
  798. if val < 0.001:
  799. return "***"
  800. elif val < 0.01:
  801. return "**"
  802. elif val < 0.05:
  803. return "*"
  804. else:
  805. return ""
  806. areas = ['ACCg','BLA','dmPFC','OFC']
  807. areas1 = ['ACCg','ACCg','ACCg','BLA', 'BLA', 'dmPFC']
  808. areas2 = ['BLA','dmPFC','OFC','dmPFC', 'OFC', 'OFC']
  809. areas_paris = ['ACCg_BLA','ACCg_dmPFC', 'ACCg_OFC','BLA_dmPFC','BLA_OFC', 'dmPFC_OFC']
  810. for i in range(6):
  811. inpuDataState = copy.deepcopy(inpuDataStateColl[areas_paris[i]])
  812. inpuDataAnnoState = copy.deepcopy(inpuDataAnnoStateColl[areas_paris[i]])
  813. with plt.style.context('style_paper.mplstyle'):
  814. # sns.set(style = "ticks")
  815. f, ax1 = plt.subplots(ncols=1, nrows=1, sharey=True,figsize=[3.54/1.5,3.54/2])
  816. g1 = sns.heatmap(
  817. inpuDataState[1:4,1:4],
  818. annot=inpuDataAnnoState[1:4,1:4], fmt="",
  819. # cbar=False,
  820. cmap = 'viridis',
  821. square = True,
  822. linewidths=0.2,
  823. vmin=0, vmax=0.5,
  824. ax = ax1)
  825. ax1.set_yticklabels(['-0.2','0','0.2'],rotation = 0)
  826. ax1.set_xticklabels(['-0.2','0','0.2'],rotation = 0)
  827. # ax1.set_yticklabels(['-0.4','-0.2','0','0.2','0.4'],rotation = 0)
  828. # ax1.set_xticklabels(['-0.4','-0.2','0','0.2','0.4'],rotation = 0)
  829. ax1.set_xlabel(areas2[i]+' time (s)')
  830. ax1.set_ylabel(areas1[i] +' time (s)')
  831. # ax1.set_yticklabels(['1','0.5','0','-0.5'],rotation = 0)
  832. # plt.title('')
  833. # plt.title([are,'State'])
  834. plt.tight_layout()
  835. fileName = 'figS15_CCA'+'state_'+areas1[i]+'_'+areas2[i]+'.pdf'
  836. # plt.savefig(fileName,dpi = 600)
  837. plt.show()
  838. #%% --------- figure S16 ---------
  839. #%% import figure S16 data
  840. figure_S16A_data = pkl.load(open('figure_S16A_data.pkl','rb'))
  841. edges_content_pre = figure_S16A_data['edges_content_pre']
  842. edges_content_fixation = figure_S16A_data['edges_content_fixation']
  843. edges_content_post = figure_S16A_data['edges_content_post']
  844. edges_state_pre = figure_S16A_data['edges_state_pre']
  845. edges_state_fixation = figure_S16A_data['edges_state_fixation']
  846. edges_state_post = figure_S16A_data['edges_state_post']
  847. figure_S16B_data = pkl.load(open('figure_S16B_data.pkl','rb'))
  848. content_directionality_index_mean = figure_S16B_data['content_directionality_index_mean']
  849. content_directionality_index_SEMs = figure_S16B_data['content_directionality_index_SEMs']
  850. state_directionality_index_mean = figure_S16B_data['state_directionality_index_mean']
  851. state_directionality_index_SEMs = figure_S16B_data['state_directionality_index_SEMs']
  852. # Define 4 nodes (fixed positions)
  853. node_labels = ["OFC", "dmPFC", "ACCg", "BLA"]
  854. positions = {
  855. "OFC": (0, 0),
  856. "dmPFC": (1, 1),
  857. "ACCg": (2, 0),
  858. "BLA": (1, -1)
  859. }
  860. # Assign unique colors to each node
  861. node_colors = {
  862. "OFC": "#FF7F00", # Red
  863. "dmPFC": "#099D84", # Blue
  864. "ACCg": "#CA2521", # Green
  865. "BLA": "#456ACF" # Purple
  866. }
  867. # Define edges with significance values
  868. edges = [
  869. ("OFC", "dmPFC", 0.8), # Higher significance
  870. ("dmPFC", "ACCg", 0.3), # Lower significance
  871. ("ACCg", "BLA", 0.5),
  872. ("BLA", "OFC", 0.9), # Most significant
  873. ("OFC", "ACCg", 0.6),
  874. ("dmPFC", "BLA", 0.1)
  875. ]
  876. # Convert edges to coordinate pairs
  877. edge_coords = [([positions[start], positions[end]], significance) for start, end, significance in edges_content_post]# Using edges_content_post as example
  878. # Normalize significance values for color and width
  879. vmin, vmax = 0, 0.5 # Set fixed colorbar range
  880. norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
  881. cmap = plt.cm.Greys # Grayscale color map
  882. # Prepare edge segments and styles
  883. segments = []
  884. colors = []
  885. widths = []
  886. min_width, max_width = 1, 10 # Min and max thickness
  887. for (segment, sig) in edge_coords:
  888. segments.append(segment)
  889. colors.append(cmap(norm(sig))) # Map significance to color
  890. widths.append(min_width + (max_width - min_width) * norm(sig)) # Scale width
  891. # Plot with custom style
  892. with plt.style.context('style_paper.mplstyle'):
  893. fig, ax = plt.subplots(figsize=(3.54/1.5,3.54/1.2))
  894. ax.set_aspect('equal')
  895. # Draw edges with gradient and significance scaling
  896. lc = mcoll.LineCollection(segments, colors=colors, linewidths=widths)
  897. ax.add_collection(lc)
  898. # Draw nodes with individual colors and black edges
  899. node_size = 4000 # Adjusted for better proportion
  900. for label, (x, y) in positions.items():
  901. ax.scatter(x, y, color=node_colors[label], s=node_size, edgecolors='white', linewidth=1, zorder=3)
  902. ax.text(x, y, label, fontsize=8, ha='center', va='center', color='black', fontweight='bold')
  903. # Add colorbar for edge significance with fixed range
  904. sm = cm.ScalarMappable(cmap=cmap, norm=norm)
  905. sm.set_array([]) # Required for colorbar
  906. cbar = plt.colorbar(sm, ax=ax,orientation="horizontal")
  907. cbar.set_label("Cross Validated CC rhos")
  908. # Set fixed colorbar range
  909. sm.norm.vmin = vmin
  910. sm.norm.vmax = vmax
  911. ax.set_xlim(-0.5, 2.5)
  912. ax.set_ylim(-1.5, 1.5)
  913. # Remove all axes
  914. ax.set_xticks([])
  915. ax.set_yticks([])
  916. ax.axis("off") # Completely removes axis lines, labels, and ticks
  917. plt.tight_layout()
  918. fileName = 'figS16A_'+'CCA'+'edges_content_post'+'_func_conn'+'_without_linear_mixed_cells.pdf'
  919. # plt.savefig(fileName,bbox_inches="tight",dpi = 600)
  920. plt.show()
  921. #%% load figure S16B data for state and content directionality index distributions (for box plot)
  922. dataS16B = pkl.load(open('figure_S16B.pkl', 'rb'))
  923. directionality_index_Accg_Bla_state = dataS16B['Accg_Bla_state']
  924. directionality_index_Bla_Dmpfc_state = dataS16B['Bla_Dmpfc_state']
  925. directionality_index_Bla_Ofc_content = dataS16B['Bla_Ofc_content']
  926. directionality_index_Accg_Bla_content = dataS16B['Accg_Bla_content']
  927. #%% plot box plots for directionality index distributions, with alternating background and dual y-axis labels
  928. with plt.style.context('style_paper.mplstyle'):
  929. fig, ax = plt.subplots(figsize=(3.54/2, 3.54/2))
  930. # Y positions
  931. y_positions = np.array([1, 2]) * 1.5
  932. # Full distributions
  933. distributions = [
  934. np.asarray(directionality_index_Accg_Bla_state).flatten(),
  935. np.asarray(directionality_index_Bla_Dmpfc_state).flatten(),
  936. ]
  937. distributions = [d[~np.isnan(d)] for d in distributions]
  938. means = [np.nanmean(d) for d in distributions]
  939. errors = [np.nanstd(d) / np.sqrt(len(d)) for d in distributions]
  940. # Alternating background
  941. for i in range(len(y_positions)):
  942. ax.axhspan(
  943. y_positions[i] - 0.5,
  944. y_positions[i] + 0.5,
  945. color='lightgray' if i % 2 == 0 else 'white',
  946. alpha=0.3,
  947. zorder=1,
  948. )
  949. # ---- Box plot ----
  950. bp = ax.boxplot(
  951. distributions,
  952. positions=y_positions,
  953. vert=False,
  954. widths=0.55,
  955. patch_artist=True,
  956. showfliers=False,
  957. medianprops={'color': 'black', 'linewidth': 1.5},
  958. boxprops={'linewidth': 0.6, 'edgecolor': 'black'},
  959. whiskerprops={'linewidth': 0.6, 'color': 'black'},
  960. capprops={'linewidth': 0.6, 'color': 'black'},
  961. zorder=3,
  962. )
  963. for box in bp['boxes']:
  964. box.set_facecolor('black')
  965. box.set_alpha(0.4)
  966. # ---- Reference line ----
  967. ax.axvline(
  968. 0,
  969. color='black',
  970. linestyle=':',
  971. linewidth=0.7,
  972. alpha=0.6,
  973. zorder=1.5,
  974. )
  975. # ---- Axes ----
  976. ax.set_xlabel('Directionality Index')
  977. ax.set_yticks(y_positions)
  978. ytick_labels_left = ['ACCg → BLA', 'BLA → dmPFC']
  979. ytick_labels_right = ['BLA → ACCg', 'dmPFC → BLA']
  980. ax.set_yticklabels(ytick_labels_left)
  981. ax_right = ax.twinx()
  982. ax_right.set_yticks(y_positions)
  983. ax_right.set_yticklabels(ytick_labels_right)
  984. ax_right.set_ylim(ax.get_ylim())
  985. ax.xaxis.grid(True, linestyle='--', alpha=0.6)
  986. ax_right.spines['right'].set_visible(True)
  987. ax_right.spines['right'].set_color('black')
  988. ax_right.spines['right'].set_linewidth(1)
  989. plt.tight_layout()
  990. fileName = 'figS16B_CCA_Directionality_index_func_conn_state_BLAonly_without_linear_mixed_cells.pdf'
  991. # plt.savefig(dataPath + fileName, bbox_inches='tight', dpi=600)
  992. plt.show()
  993. with plt.style.context('style_paper.mplstyle'):
  994. fig, ax = plt.subplots(figsize=(3.54/2, 3.54/2))
  995. # Y positions
  996. y_positions = np.array([1, 2]) * 1.5
  997. # Full distributions (1000 iterations each)
  998. distributions = [
  999. np.asarray(directionality_index_Bla_Ofc_content).flatten(),
  1000. np.asarray(directionality_index_Accg_Bla_content).flatten(),
  1001. ]
  1002. distributions = [d[~np.isnan(d)] for d in distributions]
  1003. means = [np.nanmean(d) for d in distributions]
  1004. errors = [np.nanstd(d) / np.sqrt(len(d)) for d in distributions]
  1005. # Alternating background
  1006. for i in range(len(y_positions)):
  1007. ax.axhspan(
  1008. y_positions[i] - 0.5, y_positions[i] + 0.5,
  1009. color='lightgray' if i % 2 == 0 else 'white',
  1010. alpha=0.3,
  1011. zorder=1,
  1012. )
  1013. # ---- Box plot ----
  1014. bp = ax.boxplot(
  1015. distributions,
  1016. positions=y_positions,
  1017. vert=False,
  1018. widths=0.55,
  1019. patch_artist=True,
  1020. showfliers=False,
  1021. medianprops={'color': 'black', 'linewidth': 1.5},
  1022. boxprops={'linewidth': 0.6, 'edgecolor': 'black'},
  1023. whiskerprops={'linewidth': 0.6, 'color': 'black'},
  1024. capprops={'linewidth': 0.6, 'color': 'black'},
  1025. zorder=3,
  1026. )
  1027. for box in bp['boxes']:
  1028. box.set_facecolor('black')
  1029. box.set_alpha(0.4)
  1030. # ---- Reference line ----
  1031. ax.axvline(0, color='black', linestyle=':', linewidth=0.7, alpha=0.6, zorder=1.5)
  1032. # ---- Axes ----
  1033. ax.set_xlabel('Directionality Index')
  1034. ax.set_yticks(y_positions)
  1035. ytick_labels_left = ['BLA → OFC', 'ACCg → BLA']
  1036. ytick_labels_right = ['OFC → BLA', 'BLA → ACCg']
  1037. ax.set_yticklabels(ytick_labels_left)
  1038. ax_right = ax.twinx()
  1039. ax_right.set_yticks(y_positions)
  1040. ax_right.set_yticklabels(ytick_labels_right)
  1041. ax_right.set_ylim(ax.get_ylim())
  1042. ax.xaxis.grid(True, linestyle='--', alpha=0.6)
  1043. ax_right.spines['right'].set_visible(True)
  1044. ax_right.spines['right'].set_color('black')
  1045. ax_right.spines['right'].set_linewidth(1)
  1046. plt.tight_layout()
  1047. fileName = 'figS15B_CCA_Directionality_index_func_conn_content_BLAonly_without_linear_mixed_cells.pdf'
  1048. # plt.savefig(dataPath + fileName, bbox_inches='tight', dpi=600)
  1049. plt.show()
  1050. # %%

codes_for_supplementary_figuresS2-S16.py at commit fe69fce, no license · at the source

Overview

Authors: Guangyao Qi1, Olga Dal Monte1,2, Siqi Fan1,3, Steve W. C. Chang1,4,5,6
  1. Department of Psychology, Yale University,New Haven, CT USA
  2. Department of Psychology, University of Turin,Torino, Italy
  3. The Laboratory of Neural Systems, The Rockefeller University,New York, NY USA
  4. Department of Neuroscience, Yale University School of Medicine,New Haven, CT USA
  5. Kavli Institute for Neuroscience, Yale University School of Medicine,New Haven, CT USA
  6. Wu Tsai Institute, Yale University,New Haven, CT USA
Institutions: Yale University (United States); University of Turin (Italy); Rockefeller University (United States)
Journal: Nature communications, volume 17, issue 1, article 7478
Dates: received 29 September 2025; accepted 2 June 2026; published online 12 June 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41467-026-74347-8 · PMID 42285960 · PMCID PMC13407908 · OpenAlex W4412895001
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: non-human primate (organism), systems (subfield)
Methods: Spectral & time-frequency, Connectivity, Statistics, Smoothing, state filtering, decompositions, Machine learning, Preprocessing, fMRI & imaging, Single-unit activity, calcium imaging, Physiology & signal measures
Keywords: Social behaviour, Social neuroscience
MeSH: Amygdala*, Fixation, Ocular*, Prefrontal Cortex*, Social Behavior*, Animals, Female, Gyrus Cinguli, Macaca mulatta, Male, Neurons (* major topic)
Topic: Primate Behavior and Ecology (Social Psychology, Psychology), according to OpenAlex
Funding: National Institute of Mental Health (R01MH128190, R01MH120081, R01MH110750)
Citations: cited by 2 papers (Europe PMC); 80 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

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

changlabneuro/social_gaze_compositionality

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: fe69fceed216c477d8c8dbd8dab8bee14e1401d2, 6 May 2026
Languages: Python (6), MATLAB (1), R (1)
Size: 46 files, 8 scripts
Software Heritage: not archived
Found in: “Data availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (6 files), scikit-learn (4 files), Matplotlib (3 files), pandas (3 files), SciPy (3 files), seaborn (2 files), broom (1 file), car (1 file), emmeans (1 file), lme4 (1 file), Pingouin (1 file), statsmodels (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
9 files

Zenodo 20061507

License: CC-BY-4.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (6 files), scikit-learn (4 files), Matplotlib (3 files), pandas (3 files), SciPy (3 files), seaborn (2 files), broom (1 file), car (1 file), emmeans (1 file), lme4 (1 file), Pingouin (1 file), statsmodels (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
  • 27 September 2026: the link answers (HTTP 200)
9 files
At the source:

qiguangyao/social_gaze_compositionality

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: fe69fceed216c477d8c8dbd8dab8bee14e1401d2, 6 May 2026
Languages: Python (6), MATLAB (1), R (1)
Size: 46 files, 8 scripts
Software Heritage: not archived
Found in: the Zenodo archive record
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (6 files), scikit-learn (4 files), Matplotlib (3 files), pandas (3 files), SciPy (3 files), seaborn (2 files), broom (1 file), car (1 file), emmeans (1 file), lme4 (1 file), Pingouin (1 file), statsmodels (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
9 files

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-74347-8.

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:

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

No dataset and no data link were found in the paper.

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-74347-8.

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 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 2 keywords, 10 MeSH terms, 1 funder, 73 references.

Cite

This paper

Qi, G., Dal Monte, O., Fan, S., & Chang, S. W. C. (2026). Compositionality of social gaze in the prefrontal-amygdala circuits. Nature communications, 17(1), 7478. https://doi.org/10.1038/s41467-026-74347-8

BibTeX

@article{qi2026compositionality,
author = {Qi, Guangyao and Dal Monte, Olga and Fan, Siqi and Chang, Steve W. C.},
title = {{Compositionality of social gaze in the prefrontal-amygdala circuits}},
journal = {Nature communications},
year = {2026},
month = jun,
volume = {17},
number = {1},
pages = {7478},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-74347-8},
url = {https://doi.org/10.1038/s41467-026-74347-8},
pmid = {42285960},
pmcid = {PMC13407908}
}

RIS

TY - JOUR
AU - Qi, Guangyao
AU - Dal Monte, Olga
AU - Fan, Siqi
AU - Chang, Steve W. C.
TI - Compositionality of social gaze in the prefrontal-amygdala circuits
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/06/12
VL - 17
IS - 1
SP - 7478
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-74347-8
UR - https://doi.org/10.1038/s41467-026-74347-8
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-74347-8",
"type": "article-journal",
"title": "Compositionality of social gaze in the prefrontal-amygdala circuits",
"container-title": "Nature communications",
"author": [
{
"family": "Qi",
"given": "Guangyao"
},
{
"family": "Dal Monte",
"given": "Olga"
},
{
"family": "Fan",
"given": "Siqi"
},
{
"family": "Chang",
"given": "Steve W. C."
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "7478",
"DOI": "10.1038/s41467-026-74347-8",
"PMID": "42285960",
"PMCID": "PMC13407908",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-74347-8",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
12
]
]
}
}

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/s41467-026-75220-4 [code]
Causal Dynamics of Social Gaze in Primate Prefrontal-Amygdala Networks Revealed by Dynamic Bayesian Modeling.
Journal: Nature communications
In common: statsmodels, scikit-learn, pandas, 3 other tools, non-human primate, systems, 7 references, author Steve W. C. Chang
[2] doi:10.1038/s41593-026-02333-w [code]
Learning shapes neural geometry in the primate prefrontal cortex.
Journal: Nature neuroscience
In common: seaborn, scikit-learn, pandas, 3 other tools, non-human primate, 7 references
[3] doi:10.1162/imag.a.1321 [code]
Phase similarity between similar objects indicates representational merging across retrieval training but not sleep.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: Pingouin, car, broom, 8 other tools
[4] doi:10.1093/nc/niag029 [code]
A data-driven approach to identifying and evaluating connectivity-based neural correlates of conscious visual perception.
Journal: Neuroscience of consciousness
In common: Pingouin, car, broom, 8 other tools
[5] doi:10.34133/csbj.0042 [code]
Using Steady-State Visual Evoked Potentials to Characterize Wide-Ranging Retinopathy Linked to &lt;i&gt;CRB1&lt;/i&gt;: Implications for Clinical Trials.
Journal: Computational and structural biotechnology journal
In common: Pingouin, car, emmeans, 8 other tools
[6] doi:10.1038/s41593-026-02228-w [code]
Circuit response to neuromodulation characterized with simultaneous deep brain stimulation and precision neuroimaging in humans.
Journal: Nature neuroscience
In common: Pingouin, emmeans, lme4, 7 other tools, systems
[7] doi:10.1016/j.celrep.2026.117505 [code]
Impaired spatial coding and neuronal hyperactivity in the medial entorhinal cortex of aged APP knock-in mice.
Journal: Cell reports
In common: car, broom, emmeans, 4 other tools, 2 references
[8] doi:10.1016/j.isci.2026.117492 [code]
Neural subspace reorganization reflects value-based decision-making.
Journal: iScience
In common: statsmodels, scikit-learn, pandas, 3 other tools, 5 references
[9] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: car, broom, emmeans, 7 other tools
[10] doi:10.1038/s41597-026-07350-9 [code]
An open multi-center MEG-EEG dataset for studying conscious visual perception.
Journal: Scientific data
In common: Pingouin, car, emmeans, 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.