OSCR

A Novel Approach to Map the Causal Impact of Brain Stimulation on Semantic Processing With Language Models.

Code ↔ Paper

2 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 2 matches
  1. [1] § RESULTS › TMS Effects on Semantic Processing Are Still Present After Accounting for Word Length and Frequency ↔ plot01_gen_all_barplots.py, lines 1049–1104 · score 0.61 · semantic relatedness, sound feature, semantic priming, residualization, social
  2. [2] § MATERIALS AND METHODS › Models › Statistical significance testing, correction for multiple comparisons, and effect sizes ↔ utils/plot_utils.py, lines 57–70 · score 0.52 · cognitive neuroscience, literature, mid

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,558 lines · 78 KB · no license · 1 match

  1. import matplotlib
  2. import mne
  3. import numpy
  4. import os
  5. import pingouin
  6. import random
  7. import re
  8. import scipy
  9. from matplotlib import colormaps, font_manager, pyplot
  10. from mne import stats
  11. from scipy import stats
  12. from tqdm import tqdm
  13. from utils.plot_utils import font_setup, perm_against_zero, permutation_two_samples, read_effsizes, set_colors
  14. ### effect_sizes
  15. lo_e, mid_e, hi_e = read_effsizes(mode='cog_neuro')
  16. print(lo_e)
  17. font_folder = '../../fonts'
  18. font_setup(font_folder)
  19. for mode in [
  20. 'residualize',
  21. 'bootstrap',
  22. ]:
  23. for corpus in [
  24. #'opensubs',
  25. 'wac',
  26. #'cc100',
  27. ]:
  28. results = dict()
  29. for root, direc, fz in os.walk(
  30. os.path.join(
  31. 'test_results',
  32. )):
  33. for f in fz:
  34. parts = root.split('/')
  35. approach = parts[1]
  36. if approach != 'correlation':
  37. continue
  38. stat_approach = parts[2]
  39. if stat_approach != mode:
  40. continue
  41. evaluation = parts[3]
  42. if evaluation != 'spearman':
  43. continue
  44. lang = parts[4]
  45. n = '100000'
  46. if 'gpt2-small_surprisal' in root:
  47. model = 'GPT2\nsurprisal'
  48. pass
  49. elif corpus in root and n in root:
  50. model = '{}\nPPMI'.format(corpus)
  51. pass
  52. elif corpus in root and 'abs-prob' in root:
  53. if 'one-' in root:
  54. model = 'Word\nfrequency\n(neg.\nfirst w.)'
  55. elif 'two-' in root:
  56. model = 'Word\nfrequency\n(neg.\nsecond w.)'
  57. elif 'visual-' in root:
  58. model = 'Word\nfrequency\n(neg.\nvisual)'
  59. elif 'produced-' in root:
  60. model = 'Word\nfrequency\n(neg.\nuttered)'
  61. elif 'overall-' in root:
  62. model = 'Word\nfrequency\n(neg. sum)'
  63. else:
  64. raise RuntimeError()
  65. continue
  66. #print(root)
  67. #print(model.replace('\n', ' '))
  68. pass
  69. elif 'word-length' in root:
  70. if 'one-' in root:
  71. model = 'Word\nlength\n(first w.)'
  72. elif 'two-' in root:
  73. model = 'Word\nlength\n(second w.)'
  74. elif 'visual-' in root:
  75. model = 'Word\nlength\n(visual)'
  76. elif 'produced-' in root:
  77. model = 'Word\nlength\n(uttered)'
  78. elif 'overall-' in root:
  79. model = 'Word\nlength\n(sum)'
  80. else:
  81. continue
  82. pass
  83. else:
  84. print(f)
  85. continue
  86. with open(os.path.join(root, f)) as i:
  87. for l in i:
  88. line = l.strip().split('\t')
  89. lang = line[0]
  90. if lang not in results.keys():
  91. results[lang] = dict()
  92. old_model = line[1]
  93. all_task = line[2]
  94. ### modality
  95. assert all_task[:3] == '{}_'.format(lang)
  96. task = all_task[3:].split('#')[0].split('_')[0]
  97. if 'sem' in task or 'pmtg' in task:
  98. splitter = '-'
  99. else:
  100. splitter = '_'
  101. if 'sound' in task:
  102. cond_idx = -2
  103. else:
  104. cond_idx = -1
  105. case = all_task.split('#')[-1].split(splitter)[0]
  106. cond = all_task.split('#')[-1].split(splitter)[cond_idx]
  107. cond = '{}{}'.format(cond[0].lower(), cond[1:])
  108. if cond == 'cedx':
  109. cond = 'rCereb'
  110. if cond == 'cz':
  111. cond = 'vertex'
  112. if cond not in ['sham', 'vertex']:
  113. cond = 'TMS\n{}'.format(cond)
  114. if 'distr-learn' in all_task:
  115. pass
  116. elif 'pmtg-prod' in all_task:
  117. if '-but-' in all_task:
  118. continue
  119. pass
  120. elif 'sem-phon' in all_task:
  121. pass
  122. elif 'sound-act' in all_task:
  123. if 'together-pos-all' not in all_task:
  124. continue
  125. if 'all_all' in all_task:
  126. continue
  127. if 'detailed' in all_task:
  128. continue
  129. case = '{}-{}'.format(case, all_task.split('_')[-1])
  130. pass
  131. elif 'social' in all_task:
  132. if 'prime-cat' not in all_task:
  133. continue
  134. if 'cong' in all_task:
  135. continue
  136. pass
  137. else:
  138. continue
  139. if 'freq' in model:
  140. print(f)
  141. if task not in results[lang].keys():
  142. results[lang][task] = dict()
  143. if case not in results[lang][task].keys():
  144. results[lang][task][case] = dict()
  145. if cond not in results[lang][task][case].keys():
  146. results[lang][task][case][cond] = dict()
  147. non_nan_res = [v if v!='nan' else 0. for v in line[3:]]
  148. res = numpy.array(non_nan_res, dtype=numpy.float32)
  149. results[lang][task][case][cond][model] = res[:1000]
  150. colors = {
  151. '{}\nPPMI'.format(corpus) : ('navy', 'royalblue', 'lightsteelblue',),
  152. 'GPT2\nvectors' : ('lightskyblue', 'lightblue', 'paleturquoise'),
  153. '{}\nsurprisal'.format(corpus) : ('mediumorchid', 'thistle', 'plum'),
  154. 'GPT2\nsurprisal' : ('mediumvioletred', 'pink', 'palevioletred'),
  155. 'Word\nfrequency' : ('sienna', 'peru', 'sandybrown'),
  156. 'Word\nlength' : ('gray', 'darkgray', 'lightgray'),
  157. }
  158. out_f = os.path.join('plots', '00', mode, corpus)
  159. os.makedirs(out_f, exist_ok=True)
  160. for lang, l_results in results.items():
  161. for task, t_results in l_results.items():
  162. for case, c_results in t_results.items():
  163. ### getting ready to write things down...
  164. lines = list()
  165. gen_line = [mode, corpus, lang, task, case]
  166. curr_fold = os.path.join(out_f, lang, task, case)
  167. os.makedirs(curr_fold, exist_ok=True)
  168. conds = sorted(c_results.keys(), reverse=True)
  169. models = set([m for _ in c_results.values() for m in _.keys()])
  170. no_tms_cond = [c for c in conds if 'ver' in c or 'sh' in c][0]
  171. models = set([m for _ in c_results.values() for m in _.keys()])
  172. print(models)
  173. best_model = sorted(
  174. [(c_results[no_tms_cond][m], m) for m in models if 'length' not in m and 'frequency' not in m],
  175. key=lambda item : numpy.average(item[0]),
  176. reverse=True,
  177. )[0][1]
  178. sorted_models = [
  179. '{}\nPPMI'.format(corpus),
  180. ] +\
  181. ['GPT2\nsurprisal',] +\
  182. [m for m in models if 'freq' in m and ('visual' in m or 'first' in m)] +\
  183. [m for m in models if 'freq' in m and ('utter' in m or 'second' in m)] +\
  184. [m for m in models if 'freq' in m and ('sum' in m)] +\
  185. [m for m in models if 'ength' in m and ('visual' in m or 'first' in m)] +\
  186. [m for m in models if 'ength' in m and ('utter' in m or 'second' in m)] +\
  187. [m for m in models if 'ength' in m and ('sum' in m)]
  188. print(sorted_models)
  189. try:
  190. if 'together' not in case:
  191. assert len(sorted_models) > 6
  192. else:
  193. assert len(sorted_models) == 4
  194. except AssertionError:
  195. print(case)
  196. print(models)
  197. continue
  198. xs = list(range(len(sorted_models)))
  199. if len(conds) == 2:
  200. corrections = list(numpy.linspace(-.33, .33, len(conds)))
  201. txt_corrections = list(numpy.linspace(-.4, .4, len(conds)))
  202. m_sc = 2000
  203. t_s = 20
  204. else:
  205. corrections = list(numpy.linspace(-.5, .5, len(conds)))
  206. txt_corrections = list(numpy.linspace(-.55, .55, len(conds)))
  207. m_sc = 1400
  208. t_s = 15
  209. if 'together' in case:
  210. figsize=(15, 10)
  211. else:
  212. figsize=(20, 10)
  213. fig, ax = pyplot.subplots(constrained_layout=True, figsize=figsize)
  214. x_shift = 0
  215. xticks = list()
  216. counter = -1
  217. ps = list()
  218. for m_i, m in enumerate(sorted_models):
  219. if 'Resp' in m:
  220. gen_avg = numpy.average([v for _ in c_results.values() for __ in _.values() for v in __])
  221. gen_std = numpy.std([v for _ in c_results.values() for __ in _.values() for v in __])
  222. counter += 1
  223. for c_i, c in enumerate(conds):
  224. spec_line = [v for v in gen_line]
  225. spec_line.extend([m, c])
  226. if 'length' in m:
  227. color=colors['Word\nlength'][c_i]
  228. elif 'freq' in m:
  229. color=colors['Word\nfrequency'][c_i]
  230. else:
  231. color=colors[m][c_i]
  232. xticks.append((counter, m))
  233. if len(conds) == 2:
  234. w = 0.6
  235. else:
  236. w = 0.45
  237. if c_i == 0:
  238. comps = list()
  239. for other_i, other in enumerate(conds[1:]):
  240. two = c_results[other][m]
  241. t_val, p_val, fake_distr, ci = permutation_two_samples(c_results[c][m], two)
  242. print([m, c, other, p_val, t_val])
  243. ps.append((m, (c, other), p_val, t_val))
  244. comps.append('{}_{}_{}_{}_{}_{}@{}'.format(c, other, ci[0], ci[1], p_val, t_val, ','.join([str(v) for v in fake_distr])))
  245. spec_line.append('#'.join(comps))
  246. else:
  247. spec_line.append('na')
  248. ### simple p-value
  249. t, p, ci = perm_against_zero(c_results[c][m])
  250. #print(p)
  251. ps.append((m, c, p))
  252. spec_line.extend([p, t, ci])
  253. ### bar
  254. ax.bar(
  255. m_i+corrections[c_i]+x_shift,
  256. numpy.average(c_results[c][m]),
  257. width=w,
  258. color=color,
  259. edgecolor='gray',
  260. zorder=2.
  261. )
  262. ax.errorbar(
  263. m_i+corrections[c_i]+x_shift,
  264. numpy.average(c_results[c][m]),
  265. yerr=numpy.std(c_results[c][m]),
  266. color='black',
  267. capsize=5,
  268. zorder=3.
  269. )
  270. spec_line.extend([m_i+corrections[c_i]+x_shift, m_i+txt_corrections[c_i]+x_shift])
  271. spec_line.append(numpy.average(c_results[c][m]))
  272. spec_line.append(','.join([str(val) for val in c_results[c][m]]))
  273. lines.append(spec_line)
  274. if len(c_results[c][m]) == 1000:
  275. alpha = 0.2
  276. elif len(c_results[c][m]) == 10000:
  277. alpha = 0.02
  278. ax.scatter(
  279. [m_i+corrections[c_i]+x_shift+(random.randrange(-m_sc, m_sc)*0.0001) for rand in range(len(c_results[c][m]))],
  280. c_results[c][m],
  281. color=color,
  282. edgecolor='white',
  283. alpha=alpha,
  284. zorder=2.5
  285. )
  286. ax.text(
  287. m_i+txt_corrections[c_i]+x_shift,
  288. -.05,
  289. s=c,
  290. fontsize=t_s,
  291. ha='center',
  292. va='center',
  293. )
  294. x_shift += 1
  295. counter += 1
  296. if m_i in [0, 1, 4]:
  297. x_shift += 1
  298. counter += 1
  299. ax.set_ylim(bottom=-.08, top=.38)
  300. ax.hlines(xmin=-.8, xmax=len(sorted_models)+x_shift-2.2, color='black', y=0)
  301. ax.hlines(xmin=-.8, xmax=len(sorted_models)+x_shift-2.2, color='silver',alpha=0.5,linestyle='dashed', y=[y*0.01 for y in range(-5, 35, 5)], zorder=1)
  302. pyplot.ylabel('Spearman correlation (RSA RT-model)', fontsize=23)
  303. pyplot.xticks(
  304. [x[0] for x in xticks],
  305. [x[1] for x in xticks],
  306. fontsize=25,
  307. fontweight='bold')
  308. print(curr_fold)
  309. pyplot.savefig(os.path.join(curr_fold, '{}_00.jpg'.format(case)), dpi=300)
  310. ### writing to file
  311. with open(os.path.join(curr_fold, '{}_00.txt'.format(case)), 'w') as o:
  312. o.write('mode\tcorpus\tlang\ttask\tcase\tmodel\tcondition\t')
  313. o.write('comparisons\t')
  314. o.write('p_val_raw\tt_val\tci_constant\tx_bar\tx_label\tperms_avg\tperms\n')
  315. for lin in lines:
  316. for li in lin:
  317. o.write('{}\t'.format(str(li).replace('\n', '$')))
  318. o.write('\n')
  319. ### running correction for multiple comparisons
  320. corr_f = os.path.join('plots', 'stats_after_correction')
  321. os.makedirs(corr_f, exist_ok=True)
  322. for corpus in [
  323. 'wac',
  324. ]:
  325. final_corr = list()
  326. final_to_be_corr = list()
  327. results = dict()
  328. fakes = list()
  329. for approach in [
  330. 'residualize',
  331. 'bootstrap',
  332. ]:
  333. fold = os.path.join('plots', '00', approach, corpus)
  334. for lang in ['de', 'it']:
  335. for root, direc, fz in os.walk(os.path.join(fold, lang)):
  336. for f in fz:
  337. if 'txt' in f:
  338. assert '00' in f
  339. with open(os.path.join(root, f)) as i:
  340. for l_i, l in enumerate(i):
  341. line = l.strip().split('\t')
  342. if l_i == 0:
  343. header = line.copy()
  344. continue
  345. task = line[header.index('task')]
  346. case = line[header.index('case')]
  347. if 'sound' in task:
  348. full_task = '{}_{}_{}'.format(approach, task, case[0])
  349. elif 'social' in task:
  350. full_task = '{}_{}_{}'.format(approach, task, case.split('-')[0])
  351. else:
  352. full_task = '{}_{}'.format(approach, task)
  353. if full_task not in results.keys():
  354. results[full_task] = list()
  355. cond = line[header.index('condition')]
  356. model = line[header.index('model')]
  357. p_raw = float(line[header.index('p_val_raw')])
  358. t_val = float(line[header.index('t_val')])
  359. bar_y = float(line[header.index('perms_avg')])
  360. bar_x = float(line[header.index('x_bar')])
  361. ci_constant = float(line[header.index('ci_constant')])
  362. label_x = float(line[header.index('x_label')])
  363. perms = [float(val) for val in line[header.index('perms')].split(',')]
  364. assert len(perms) in [1000, 10000]
  365. comparisons = [val.split('@')[0].split('_') for val in line[header.index('comparisons')].split('#')]
  366. curr_dict = {
  367. 'cond' : cond,
  368. 'case' : case,
  369. 'model' : model,
  370. 'p_raw' : p_raw,
  371. 't_val' : t_val,
  372. 'bar_y' : bar_y,
  373. 'bar_x' : bar_x,
  374. 'label_x' : label_x,
  375. 'perms' : perms,
  376. 'ci_constant' : ci_constant,
  377. 'comparisons' : comparisons,
  378. }
  379. results[full_task].append(curr_dict)
  380. print(results.keys())
  381. ### correcting p-values only once
  382. to_be_corr = list()
  383. counter = 0
  384. for k, v in results.items():
  385. for case in v:
  386. to_be_corr.append(
  387. (
  388. (k,
  389. case['case'],
  390. case['cond'],
  391. case['model'],
  392. numpy.mean(case['perms']),
  393. case['ci_constant'],
  394. ),
  395. case['t_val'],
  396. case['p_raw']
  397. )
  398. )
  399. for cmpr in case['comparisons']:
  400. #print(cmpr)
  401. if cmpr != ['na']:
  402. counter += 1
  403. to_be_corr.append(
  404. (
  405. (k,
  406. case['case'],
  407. case['cond'],
  408. case['model'],
  409. cmpr[:4]
  410. ),
  411. ### t-val
  412. float(cmpr[5]),
  413. ### p-val
  414. float(cmpr[4])
  415. )
  416. )
  417. print(counter)
  418. ### baseline
  419. corr = mne.stats.fdr_correction([v[2] for v in to_be_corr])[1]
  420. final_corr.extend(corr)
  421. final_to_be_corr.extend(to_be_corr)
  422. with open(os.path.join(corr_f, '{}_corrected_baseline_p-vals.tsv'.format(corpus)), 'w') as o:
  423. o.write('approach\tdataset\tcase\tcondition\tmodel\tci_min\tci_max\tperms_avg\tt_value\traw_p\tfdr_corrected_p\n')
  424. for d, cp in zip(final_to_be_corr, final_corr):
  425. if len(d[0]) == 6:
  426. approach = d[0][0].split('_')[0]
  427. task = d[0][0].split('_')[1]
  428. case = d[0][1]
  429. cond = d[0][2]
  430. model = d[0][3]
  431. avg = d[0][4]
  432. ci_constant = d[0][5]
  433. ci_min = float(avg)-float(ci_constant)
  434. ci_max = float(avg)+float(ci_constant)
  435. raw_p = d[2]
  436. t = d[1]
  437. o.write('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n'.format(approach, task, case, cond, model, ci_min, ci_max, avg, t, raw_p, cp))
  438. with open(os.path.join(corr_f, '{}_corrected_comparisons_p-vals.tsv'.format(corpus)), 'w') as o:
  439. o.write('approach\tdataset\tcase\tcondition_one\tcondition_two\tmodel\tci_min\tci_max\tt_value\traw_p\tfdr_corrected_p\n')
  440. for d, cp in zip(final_to_be_corr, final_corr):
  441. if len(d[0]) == 5:
  442. #print(d)
  443. approach = d[0][0].split('_')[0]
  444. task = d[0][0].split('_')[1]
  445. case = d[0][1]
  446. model = d[0][3]
  447. cond_one = d[0][4][0]
  448. cond_two = d[0][4][1]
  449. ci_min = d[0][4][2]
  450. ci_max = d[0][4][3]
  451. raw_p = d[2]
  452. t = d[1]
  453. o.write('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n'.format(
  454. approach,
  455. task,
  456. case,
  457. cond_one,
  458. cond_two,
  459. model,
  460. ci_min,
  461. ci_max,
  462. t,
  463. raw_p,
  464. cp)
  465. )
  466. font_folder = '../../fonts'
  467. font_setup(font_folder)
  468. for model_sel in [
  469. 'ppmi',
  470. 'both',
  471. ]:
  472. for mode in [
  473. 'residualize',
  474. 'bootstrap',
  475. ]:
  476. for corpus in [
  477. 'wac',
  478. ]:
  479. baseline = list()
  480. with open(os.path.join(corr_f, '{}_corrected_baseline_p-vals.tsv'.format(corpus))) as i:
  481. for l_i, l in enumerate(i):
  482. line = l.strip().split('\t')
  483. if l_i == 0:
  484. continue
  485. baseline.append(line)
  486. comparisons = list()
  487. with open(os.path.join(corr_f, '{}_corrected_comparisons_p-vals.tsv'.format(corpus))) as i:
  488. for l_i, l in enumerate(i):
  489. line = l.strip().split('\t')
  490. if l_i == 0:
  491. continue
  492. comparisons.append(line)
  493. results = dict()
  494. for root, direc, fz in os.walk(
  495. os.path.join(
  496. 'test_results',
  497. )):
  498. for f in fz:
  499. parts = root.split('/')
  500. approach = parts[1]
  501. if approach != 'correlation':
  502. continue
  503. stat_approach = parts[2]
  504. if stat_approach != mode:
  505. continue
  506. evaluation = parts[3]
  507. if evaluation != 'spearman':
  508. continue
  509. lang = parts[4]
  510. n = '100000'
  511. if 'gpt2-small_surprisal' in root:
  512. model = 'GPT2\nsurprisal'
  513. pass
  514. elif corpus in root and n in root:
  515. model = '{}\nPPMI'.format(corpus)
  516. pass
  517. elif corpus in root and 'abs-prob' in root:
  518. if 'one-' in root:
  519. model = 'Word\nfrequency\n(neg.\nfirst w.)'
  520. elif 'two-' in root:
  521. model = 'Word\nfrequency\n(neg.\nsecond w.)'
  522. elif 'visual-' in root:
  523. model = 'Word\nfrequency\n(neg.\nvisual)'
  524. elif 'produced-' in root:
  525. model = 'Word\nfrequency\n(neg.\nuttered)'
  526. elif 'overall-' in root:
  527. model = 'Word\nfrequency\n(neg. sum)'
  528. else:
  529. continue
  530. print(root)
  531. print(model.replace('\n', ' '))
  532. pass
  533. elif 'word-length' in root:
  534. if 'one-' in root:
  535. model = 'Word\nlength\n(first w.)'
  536. elif 'two-' in root:
  537. model = 'Word\nlength\n(second w.)'
  538. elif 'visual-' in root:
  539. model = 'Word\nlength\n(visual)'
  540. elif 'produced-' in root:
  541. model = 'Word\nlength\n(uttered)'
  542. elif 'overall-' in root:
  543. model = 'Word\nlength\n(sum)'
  544. else:
  545. continue
  546. pass
  547. else:
  548. continue
  549. with open(os.path.join(root, f)) as i:
  550. for l in i:
  551. line = l.strip().split('\t')
  552. lang = line[0]
  553. if lang not in results.keys():
  554. results[lang] = dict()
  555. old_model = line[1]
  556. all_task = line[2]
  557. ### modality
  558. assert all_task[:3] == '{}_'.format(lang)
  559. task = all_task[3:].split('#')[0].split('_')[0]
  560. if 'sem' in task or 'pmtg' in task:
  561. splitter = '-'
  562. else:
  563. splitter = '_'
  564. if 'sound' in task:
  565. cond_idx = -2
  566. else:
  567. cond_idx = -1
  568. case = all_task.split('#')[-1].split(splitter)[0]
  569. cond = all_task.split('#')[-1].split(splitter)[cond_idx]
  570. cond = '{}{}'.format(cond[0].lower(), cond[1:])
  571. if cond == 'cedx':
  572. cond = 'rCereb'
  573. if cond == 'cz':
  574. cond = 'vertex'
  575. if cond not in ['sham', 'vertex']:
  576. cond = 'TMS\n{}'.format(cond)
  577. if 'distr-learn' in all_task:
  578. pass
  579. elif 'pmtg-prod' in all_task:
  580. if '-but-' in all_task:
  581. continue
  582. pass
  583. elif 'sem-phon' in all_task:
  584. pass
  585. elif 'sound-act' in all_task:
  586. if 'together-pos-all' not in all_task:
  587. continue
  588. if 'all_all' in all_task:
  589. continue
  590. if 'detailed' in all_task:
  591. continue
  592. case = '{}-{}'.format(case, all_task.split('_')[-1])
  593. pass
  594. elif 'social' in all_task:
  595. if 'prime-cat' not in all_task:
  596. continue
  597. if 'cong' in all_task:
  598. continue
  599. pass
  600. else:
  601. continue
  602. if task not in results[lang].keys():
  603. results[lang][task] = dict()
  604. if case not in results[lang][task].keys():
  605. results[lang][task][case] = dict()
  606. if cond not in results[lang][task][case].keys():
  607. results[lang][task][case][cond] = dict()
  608. non_nan_res = [v if v!='nan' else 0. for v in line[3:]]
  609. res = numpy.array(non_nan_res, dtype=numpy.float32)
  610. results[lang][task][case][cond][model] = res[:1000]
  611. colors = {
  612. '{}\nPPMI'.format(corpus) : ('seagreen', 'mediumaquamarine', 'mediumseagreen'),
  613. 'GPT2\nvectors' : ('lightskyblue', 'lightblue', 'paleturquoise'),
  614. '{}\nsurprisal'.format(corpus) : ('mediumorchid', 'thistle', 'plum'),
  615. 'GPT2\nsurprisal' : ('mediumvioletred', 'pink', 'palevioletred'),
  616. 'Word\nfrequency' : ('sienna', 'peru', 'sandybrown'),
  617. 'Word\nlength' : ('gray', 'darkgray', 'lightgray'),
  618. }
  619. out_f = os.path.join('plots', 'corrected', model_sel, mode, corpus)
  620. os.makedirs(out_f, exist_ok=True)
  621. for lang, l_results in results.items():
  622. for task, t_results in l_results.items():
  623. for case, c_results in t_results.items():
  624. ### getting ready to write things down...
  625. lines = list()
  626. gen_line = [mode, corpus, lang, task, case]
  627. curr_fold = os.path.join(out_f, lang, task, case)
  628. os.makedirs(curr_fold, exist_ok=True)
  629. conds = sorted(c_results.keys(), reverse=True)
  630. models = set([m for _ in c_results.values() for m in _.keys()])
  631. print(models)
  632. no_tms_cond = [c for c in conds if 'ver' in c or 'sh' in c][0]
  633. models = set([m for _ in c_results.values() for m in _.keys()])
  634. best_model = sorted(
  635. [(c_results[no_tms_cond][m], m) for m in models if 'length' not in m and 'frequency' not in m],
  636. key=lambda item : numpy.average(item[0]),
  637. reverse=True,
  638. )[0][1]
  639. print('best: {}'.format(best_model))
  640. if model_sel == 'ppmi':
  641. sorted_models = ['{}\nPPMI'.format(corpus)] +\
  642. [m for m in models if 'freq' in m and 'sum' in m] +\
  643. [m for m in models if 'ength' in m and 'sum' in m]
  644. elif model_sel == 'both':
  645. sorted_models = [
  646. '{}\nPPMI'.format(corpus),
  647. ] +\
  648. ['GPT2\nsurprisal',] +\
  649. [m for m in models if 'freq' in m and ('visual' in m or 'first' in m)] +\
  650. [m for m in models if 'freq' in m and ('utter' in m or 'second' in m)] +\
  651. [m for m in models if 'freq' in m and ('sum' in m)] +\
  652. [m for m in models if 'ength' in m and ('visual' in m or 'first' in m)] +\
  653. [m for m in models if 'ength' in m and ('utter' in m or 'second' in m)] +\
  654. [m for m in models if 'ength' in m and ('sum' in m)]
  655. try:
  656. assert len(sorted_models) in [3, 4, 6, 8]
  657. except AssertionError:
  658. print(case)
  659. print(models)
  660. continue
  661. xs = list(range(len(sorted_models)))
  662. if len(conds) == 2:
  663. corrections = list(numpy.linspace(-.33, .33, len(conds)))
  664. txt_corrections = list(numpy.linspace(-.4, .4, len(conds)))
  665. m_sc = 2000
  666. t_s = 20
  667. else:
  668. corrections = list(numpy.linspace(-.5, .5, len(conds)))
  669. txt_corrections = list(numpy.linspace(-.55, .55, len(conds)))
  670. m_sc = 1400
  671. t_s = 15
  672. fig, ax = pyplot.subplots(constrained_layout=True, figsize=(20, 10))
  673. x_shift = 0
  674. xticks = list()
  675. counter = -1
  676. ps = list()
  677. for m_i, m in enumerate(sorted_models):
  678. if 'Resp' in m:
  679. gen_avg = numpy.average([v for _ in c_results.values() for __ in _.values() for v in __])
  680. gen_std = numpy.std([v for _ in c_results.values() for __ in _.values() for v in __])
  681. counter += 1
  682. for c_i, c in enumerate(conds):
  683. spec_line = [v for v in gen_line]
  684. spec_line.extend([m, c])
  685. if 'length' in m:
  686. color=colors['Word\nlength'][c_i]
  687. elif 'freq' in m:
  688. color=colors['Word\nfrequency'][c_i]
  689. else:
  690. color=colors[m][c_i]
  691. xticks.append((counter, m))
  692. if len(conds) == 2:
  693. w = 0.6
  694. else:
  695. w = 0.45
  696. if c_i == 0:
  697. comps = list()
  698. for other_i, other in enumerate(conds[1:]):
  699. two = c_results[other][m]
  700. ### collecting corrected pvalue
  701. for line in comparisons:
  702. if line[0] != mode:
  703. continue
  704. if line[1] != task:
  705. continue
  706. if line[2] != case:
  707. continue
  708. if line[3] != c.replace('\n', '$'):
  709. continue
  710. if line[4] != other.replace('\n', '$'):
  711. continue
  712. if line[5] != m.replace('\n', '$'):
  713. continue
  714. print(line)
  715. t_val = float(line[-3])
  716. raw_p = float(line[-2])
  717. p_val = float(line[-1])
  718. print(line)
  719. print('comp {}'.format(comparisons))
  720. ps.append((m, (c, other), p_val, t_val))
  721. fake_distr = ['na']
  722. comps.append('{}_{}_{}_{}_{}@{}'.format(c, other, raw_p, p_val, t_val, ','.join([str(v) for v in fake_distr])))
  723. spec_line.append('#'.join(comps))
  724. else:
  725. spec_line.append('na')
  726. for line in baseline:
  727. if line[0] != mode:
  728. continue
  729. if line[1] != task:
  730. continue
  731. if line[2] != case:
  732. continue
  733. if line[3] != c.replace('\n', '$'):
  734. continue
  735. if line[4] != m.replace('\n', '$'):
  736. continue
  737. t = float(line[-3])
  738. raw_p = float(line[-2])
  739. p = float(line[-1])
  740. ps.append((m, c, p, t))
  741. spec_line.extend([raw_p, p, t])
  742. ### bar
  743. ax.bar(
  744. m_i+corrections[c_i]+x_shift,
  745. numpy.average(c_results[c][m]),
  746. width=w,
  747. color=color,
  748. edgecolor='gray',
  749. zorder=2.
  750. )
  751. ax.bar(
  752. m_i+corrections[c_i]+x_shift,
  753. numpy.average(c_results[c][m]),
  754. width=w,
  755. fill=False,
  756. edgecolor='dimgray',
  757. zorder=3.
  758. )
  759. ax.errorbar(
  760. m_i+corrections[c_i]+x_shift,
  761. numpy.average(c_results[c][m]),
  762. yerr=numpy.std(c_results[c][m]),
  763. color='dimgray',
  764. capsize=5,
  765. zorder=3.
  766. )
  767. spec_line.extend([m_i+corrections[c_i]+x_shift, m_i+txt_corrections[c_i]+x_shift])
  768. spec_line.append(numpy.average(c_results[c][m]))
  769. spec_line.append(','.join([str(val) for val in c_results[c][m]]))
  770. spec_line.append(c_i)
  771. lines.append(spec_line)
  772. if len(c_results[c][m]) == 1000:
  773. alpha = 0.2
  774. elif len(c_results[c][m]) == 10000:
  775. alpha = 0.02
  776. ax.scatter(
  777. [m_i+corrections[c_i]+x_shift+(random.randrange(-m_sc, m_sc)*0.0001) for rand in range(len(c_results[c][m]))],
  778. c_results[c][m],
  779. color=color,
  780. edgecolor='white',
  781. alpha=alpha,
  782. zorder=2.5
  783. )
  784. ax.text(
  785. m_i+txt_corrections[c_i]+x_shift,
  786. -.08,
  787. s=c,
  788. fontsize=t_s,
  789. ha='center',
  790. va='center',
  791. )
  792. x_shift += 1
  793. counter += 1
  794. if m_i in [11, 33]:
  795. x_shift += 1
  796. counter += 1
  797. nonshaded = list()
  798. ### absolute p-values
  799. corr_ps = mne.stats.fdr_correction([v[2] for v in ps])[1]
  800. corr_ps = [(ps[i][0], ps[i][1], ps[i][2], ps[i][3]) for i, p in enumerate(corr_ps) if type(ps[i][1]!=tuple)]
  801. x_shift = 0
  802. counter = -1
  803. for m_i, m in enumerate(sorted_models):
  804. counter += 1
  805. for c_i, c in enumerate(conds):
  806. for pm, pc, pp, t in corr_ps:
  807. if pm == m and pc == c:
  808. if abs(t)>lo_e:
  809. print('FOTTUTO D {}'.format(t))
  810. if pp < 0.005 and abs(t)>lo_e:
  811. print(pp)
  812. ax.scatter(
  813. m_i+corrections[c_i]+x_shift-.075,
  814. 0.01,
  815. color='black',
  816. edgecolor='white',
  817. zorder=3.,
  818. marker='*',
  819. s=300
  820. )
  821. ax.scatter(
  822. m_i+corrections[c_i]+x_shift+.075,
  823. 0.01,
  824. color='black',
  825. edgecolor='white',
  826. zorder=3.,
  827. marker='*',
  828. s=300
  829. )
  830. elif (str(pp)[:4] == '0.05' or pp<0.05) and abs(t)>lo_e:
  831. print(pp)
  832. ax.scatter(
  833. m_i+corrections[c_i]+x_shift,
  834. 0.01,
  835. color='black',
  836. edgecolor='white',
  837. zorder=3.,
  838. marker='*',
  839. s=400
  840. )
  841. x_shift += 1
  842. counter += 1
  843. if m_i in [11, 33]:
  844. x_shift += 1
  845. counter += 1
  846. print('nonshaded {}'.format(nonshaded))
  847. ### relative p-values
  848. corr_ps = mne.stats.fdr_correction([v[2] for v in ps])[1]
  849. corr_ps = [(ps[i][0], ps[i][1], ps[i][2], ps[i][3]) for i, p in enumerate(corr_ps) if type(ps[i][1])==tuple]
  850. x_shift = 0
  851. counter = -1
  852. for m_i, m in enumerate(sorted_models):
  853. counter += 1
  854. for c_i, c in enumerate(conds):
  855. for pm, pc, pp, t in corr_ps:
  856. alpha = 1.
  857. if pm == m and pc[0] == c:
  858. for other_i, other in enumerate(conds[1:]):
  859. if pc[1] == other:
  860. if 'length' in m:
  861. color=colors['Word\nlength'][other_i+1]
  862. elif 'freq' in m:
  863. color=colors['Word\nfrequency'][other_i+1]
  864. else:
  865. color=colors[m][c_i]
  866. if pp < 0.05 and abs(t)>lo_e:
  867. ax.vlines(
  868. ymin=0.41-(other_i*0.03),
  869. ymax=0.41-(other_i*0.03)-0.01,
  870. x=m_i+corrections[c_i]+x_shift,
  871. color=color,
  872. alpha=alpha,
  873. zorder=3.,
  874. linewidth=5.
  875. )
  876. ax.vlines(
  877. ymin=0.41-(other_i*0.03),
  878. ymax=0.41-(other_i*0.03)-0.01,
  879. x=m_i+corrections[c_i+1+other_i]+x_shift,
  880. color=color,
  881. alpha=alpha,
  882. zorder=3.,
  883. linewidth=5.
  884. )
  885. ax.hlines(
  886. xmin=m_i+corrections[c_i]+x_shift-0.025,
  887. xmax=m_i+corrections[c_i+1+other_i]+x_shift+0.03,
  888. y=0.41-(other_i*0.03),
  889. color=color,
  890. zorder=3.,
  891. alpha=alpha,
  892. linewidth=5.
  893. )
  894. xmin=m_i+corrections[c_i]+x_shift
  895. xmax=m_i+corrections[c_i+1+other_i]+x_shift
  896. middle = xmin + ((xmax-xmin)*.5)
  897. if pp < 0.005 and abs(t)>lo_e:
  898. if abs(t) > hi_e:
  899. ax.text(
  900. middle-0.275,
  901. y=0.42-(other_i*0.03),
  902. s='L',
  903. fontweight='bold',
  904. fontsize=15,
  905. color=color,
  906. ha='center',
  907. va='center',
  908. )
  909. elif abs(t) > mid_e:
  910. ax.text(
  911. middle-0.275,
  912. y=0.42-(other_i*0.03),
  913. s='M',
  914. fontweight='bold',
  915. fontsize=15,
  916. ha='center',
  917. va='center',
  918. color=color,
  919. )
  920. elif abs(t) > lo_e:
  921. ax.text(
  922. middle-0.275,
  923. y=0.42-(other_i*0.03),
  924. s='S',
  925. fontweight='bold',
  926. fontsize=15,
  927. ha='center',
  928. va='center',
  929. color=color,
  930. )
  931. print(pp)
  932. ax.scatter(
  933. middle-0.075,
  934. y=0.42-(other_i*0.03),
  935. color=color,
  936. edgecolor='gray',
  937. zorder=3.,
  938. marker='*',
  939. alpha=alpha,
  940. s=300
  941. )
  942. ax.scatter(
  943. middle+0.075,
  944. y=0.42-(other_i*0.03),
  945. color=color,
  946. edgecolor='gray',
  947. alpha=alpha,
  948. zorder=3.,
  949. marker='*',
  950. s=300
  951. )
  952. elif pp < 0.05 and abs(t)>lo_e:
  953. if abs(t) > hi_e:
  954. ax.text(
  955. middle-0.15,
  956. y=0.42-(other_i*0.03),
  957. s='L',
  958. fontweight='bold',
  959. fontsize=15,
  960. ha='center',
  961. va='center',
  962. color=color,
  963. )
  964. elif abs(t) > mid_e:
  965. ax.text(
  966. middle-0.15,
  967. y=0.42-(other_i*0.03),
  968. s='M',
  969. color=color,
  970. fontweight='bold',
  971. fontsize=15,
  972. ha='center',
  973. va='center',
  974. )
  975. elif abs(t) > lo_e:
  976. ax.text(
  977. middle-0.15,
  978. y=0.42-(other_i*0.03),
  979. s='S',
  980. color=color,
  981. fontweight='bold',
  982. fontsize=15,
  983. ha='center',
  984. va='center',
  985. )
  986. print(pp)
  987. ax.scatter(
  988. middle,
  989. y=0.42-(other_i*0.03),
  990. color=color,
  991. edgecolor='gray',
  992. alpha=alpha,
  993. zorder=3.,
  994. marker='*',
  995. s=300
  996. )
  997. x_shift += 1
  998. counter += 1
  999. if m_i in [11, 33]:
  1000. x_shift += 1
  1001. counter += 1
  1002. ax.set_ylim(bottom=-.1, top=.43)
  1003. ax.hlines(xmin=-.8, xmax=len(sorted_models)+x_shift-1.2, color='black', y=0)
  1004. ax.hlines(xmin=-.8, xmax=len(sorted_models)+x_shift-1.2, color='silver',alpha=0.5,linestyle='dashed', y=[y*0.01 for y in range(-5, 40, 5)], zorder=1)
  1005. pyplot.ylabel('Spearman correlation (RT-model)', fontsize=23)
  1006. pyplot.xticks(
  1007. [x[0] for x in xticks],
  1008. [x[1] for x in xticks],
  1009. fontsize=25,
  1010. fontweight='bold')
  1011. print(curr_fold)
  1012. pyplot.savefig(os.path.join(curr_fold, '{}.jpg'.format(case)), dpi=300)
  1013. pyplot.savefig(os.path.join(curr_fold, '{}.svg'.format(case)),)
  1014. pyplot.clf()
  1015. pyplot.close()
  1016. ### writing to file
  1017. with open(os.path.join(curr_fold, '{}.txt'.format(case)), 'w') as o:
  1018. o.write('mode\tcorpus\tlang\ttask\tcase\tmodel\tcondition\t')
  1019. o.write('comparisons\t')
  1020. o.write('raw_p\tfdr_corrected_p_val\tt_val\tx_bar\tx_label\tperms_avg\tperms\trel_idx\n')
  1021. for lin in lines:
  1022. for li in lin:
  1023. o.write('{}\t'.format(str(li).replace('\n', '$')))
  1024. o.write('\n')
  1025. font_folder = '../../fonts'
  1026. font_setup(font_folder)
  1027. plot_info = {
  1028. 'bootstrap' : [
  1029. {
  1030. 'figsize' : (16, 10),
  1031. 'correction' : (.7, 1.),
  1032. 'jump' : 6.5,
  1033. 'font_size' : 16,
  1034. 'title_size' : 25,
  1035. 'width' : (0.4, 0.4),
  1036. 'xticks' : [2., 7.5],
  1037. 'xlabels' : ['Picture naming w/\ninterference', 'Semantic production'],
  1038. },
  1039. {
  1040. 'figsize' : (16, 10),
  1041. 'correction' : (.7, .7, .7),
  1042. 'jump' : 6,
  1043. 'font_size' : 15,
  1044. 'title_size' : 25,
  1045. 'width' : (0.4, 0.4, 0.4),
  1046. 'xticks' : [1.5, 7.5, 13.5],
  1047. 'xlabels' : ['Semantic relatedness\njudgement', 'Action feature\njudgement', 'Sound feature\njudgement'],
  1048. },
  1049. #{
  1050. #'figsize' : (8, 10),
  1051. #'correction' : (.7,),
  1052. #'jump' : 0.,
  1053. #'font_size' : 16,
  1054. #'title_size' : 25,
  1055. #'width' : (0.4,),
  1056. #'xticks' : [1.5],
  1057. #'xlabels' : ['Semantic relatedness\njudgement'],
  1058. #},
  1059. {
  1060. 'figsize' : (16, 10),
  1061. 'correction' : (1., 1.),
  1062. 'jump' : 8,
  1063. 'font_size' : 15,
  1064. 'title_size' : 25,
  1065. 'width' : (0.4, 0.4),
  1066. 'xticks' : [2., 10.],
  1067. 'xlabels' : ['Semantic priming\n(quantity)', 'Semantic priming\n(social)'],
  1068. },
  1069. ],
  1070. 'residualize' : [
  1071. {
  1072. 'figsize' : (16, 10),
  1073. 'correction' : (.75, .9, .75, .75, .75, .9, .9),
  1074. 'jump' : 2.,
  1075. 'font_size' : 15,
  1076. 'title_size' : 20,
  1077. 'width' : (0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4),
  1078. 'xticks' : [0., 2., 4., 6., 8., 10., 12.],
  1079. 'xlabels' : ['Picture\nnaming w/\ninterference', 'Semantic\nproduction','Semantic\nrelatedness\njudgement', 'Action\nfeature\njudgement', 'Sound\nfeature\njudgement', 'Semantic\npriming\n(quantity)', 'Semantic\npriming\n(social)'],
  1080. },
  1081. ],
  1082. }
  1083. corpus = 'wac'
  1084. plots = {
  1085. 'bootstrap' : [
  1086. ('pmtg-production','sem-phon'),
  1087. ('distr-learn', 'sound-action_A', 'sound-action_S'),
  1088. ('social-quantity_quantity', 'social-quantity_social'),
  1089. ],
  1090. 'residualize' : [
  1091. ('pmtg-production', 'sem-phon',
  1092. 'distr-learn',
  1093. 'sound-action_A', 'sound-action_S',
  1094. 'social-quantity_quantity', 'social-quantity_social',
  1095. ),
  1096. ],
  1097. }
  1098. results = dict()
  1099. fold = os.path.join('plots', 'corrected', 'ppmi')
  1100. for root, direc, fz in os.walk(fold):
  1101. for f in fz:
  1102. if 'txt' not in f:
  1103. continue
  1104. splt_root = root.split('/')
  1105. if 'wac' not in splt_root:
  1106. continue
  1107. dataset = splt_root[-2]
  1108. if 'sound' in dataset:
  1109. full_task = '{}_{}'.format(dataset, splt_root[-1][0])
  1110. elif 'social' in dataset:
  1111. full_task = '{}_{}'.format(dataset, splt_root[-1].split('-')[0])
  1112. else:
  1113. full_task = '{}'.format(dataset)
  1114. approach = splt_root[3]
  1115. if approach not in results.keys():
  1116. results[approach] = dict()
  1117. if full_task not in results[approach].keys():
  1118. results[approach][full_task] = list()
  1119. with open(os.path.join(root, f)) as i:
  1120. for l_i, l in enumerate(i):
  1121. line = l.strip().split('\t')
  1122. if l_i == 0:
  1123. header = line.copy()
  1124. #print(header)
  1125. continue
  1126. ### just checking
  1127. task = line[header.index('task')]
  1128. case = line[header.index('case')]
  1129. if 'sound' in task:
  1130. new_full_task = '{}_{}'.format(task, case[0])
  1131. elif 'social' in task:
  1132. new_full_task = '{}_{}'.format(task, case.split('-')[0])
  1133. else:
  1134. new_full_task = '{}'.format(task)
  1135. assert new_full_task == full_task
  1136. ### collecting results
  1137. cond = line[header.index('condition')]
  1138. model = line[header.index('model')]
  1139. p_raw = float(line[header.index('raw_p')])
  1140. p_fdr = float(line[header.index('fdr_corrected_p_val')])
  1141. t_val = float(line[header.index('t_val')])
  1142. bar_y = float(line[header.index('perms_avg')])
  1143. bar_x = float(line[header.index('x_bar')])
  1144. rel_idx = int(line[header.index('rel_idx')])
  1145. label_x = float(line[header.index('x_label')])
  1146. perms = [float(val) for val in line[header.index('perms')].split(',')]
  1147. assert len(perms) in [1000, 10000]
  1148. #print([model, cond])
  1149. comparisons = [val.split('@')[0].split('_') for val in line[header.index('comparisons')].split('#')]
  1150. curr_dict = {
  1151. 'cond' : cond,
  1152. 'model' : model,
  1153. 'p_raw' : p_raw,
  1154. 'p_fdr' : p_fdr,
  1155. 't_val' : t_val,
  1156. 'bar_y' : bar_y,
  1157. 'bar_x' : bar_x,
  1158. 'label_x' : label_x,
  1159. 'rel_idx' : rel_idx,
  1160. 'perms' : perms,
  1161. 'comparisons' : comparisons,
  1162. }
  1163. print(os.path.join(root, f))
  1164. results[approach][full_task].append(curr_dict)
  1165. ### just checking...
  1166. for a, a_r in results.items():
  1167. for t, t_r in a_r.items():
  1168. assert len(t_r) in [6, 9]
  1169. out_f = os.path.join('plots', 'main_text')
  1170. os.makedirs(out_f, exist_ok=True)
  1171. for plot, cases in plots.items():
  1172. colors = set_colors(plot)
  1173. plot_n = 0
  1174. for datasets in cases:
  1175. print(datasets)
  1176. plot_n += 1
  1177. figsize = plot_info[plot][plot_n-1]['figsize']
  1178. out = os.path.join(out_f, 'R{:02}_{}.jpg'.format(plot_n, plot))
  1179. #figsize=(13, 10)
  1180. fig, ax = pyplot.subplots(figsize=figsize, constrained_layout=True)
  1181. ax.set_ylim(bottom=-.09, top=.42)
  1182. ax.spines['bottom'].set_visible(False)
  1183. ax.spines['right'].set_visible(False)
  1184. ax.spines['top'].set_visible(False)
  1185. pyplot.ylabel('Spearman correlation (RT-model)', fontsize=23)
  1186. pyplot.yticks(fontsize=20)
  1187. lgnds = list()
  1188. comps = list()
  1189. mapper = dict()
  1190. xs = list()
  1191. for start_i, dataset in enumerate(datasets):
  1192. all_data = results[plot][dataset]
  1193. w = plot_info[plot][plot_n-1]['width'][start_i]
  1194. jump = plot_info[plot][plot_n-1]['jump']
  1195. corr = plot_info[plot][plot_n-1]['correction'][start_i]
  1196. t_s = plot_info[plot][plot_n-1]['font_size']
  1197. title_size = plot_info[plot][plot_n-1]['title_size']
  1198. m_sc = 1000
  1199. start = start_i * jump
  1200. for data in all_data:
  1201. label = data['cond']
  1202. model = data['model']
  1203. if plot == 'residualize' and ('length' in model or 'frequency' in model):
  1204. continue
  1205. p_abs = data['p_fdr']
  1206. t_abs = data['t_val']
  1207. perms = data['perms']
  1208. rel_idx = data['rel_idx']
  1209. color = colors[model][rel_idx]
  1210. if rel_idx == 0:
  1211. if plot == 'residualize':
  1212. label_mapper = {
  1213. 'GPT2$surprisal' : 'GPT2 surprisal',
  1214. 'wac$PPMI' : 'Semantic dissimilarity (beyond word length and freq.)',
  1215. 'Word$frequency$(neg. sum)' : 'Word frequency (neg.)',
  1216. 'Word$length$(sum)': 'Word length',
  1217. }
  1218. else:
  1219. label_mapper = {
  1220. 'GPT2$surprisal' : 'GPT2 surprisal',
  1221. 'wac$PPMI' : 'Semantic dissimilarity',
  1222. #'Word$frequency' : 'Word frequency (neg.)',
  1223. #'Word$length': 'Word length',
  1224. 'Word$frequency$(neg. sum)' : 'Word frequency (neg.)',
  1225. 'Word$length$(sum)': 'Word length',
  1226. }
  1227. if 'distr' not in dataset:
  1228. if start_i in [0, 2] and ('length' in model or 'frequency' in model):
  1229. pass
  1230. else:
  1231. legend_label = label_mapper[model]
  1232. if legend_label not in lgnds:
  1233. lgnds.append(legend_label)
  1234. lgnd_w = 2.
  1235. ax.bar(0, 0, color=color, label=legend_label)
  1236. else:
  1237. legend_label = label_mapper[model]
  1238. if legend_label not in lgnds:
  1239. lgnds.append(legend_label)
  1240. lgnd_w = 0.6
  1241. ax.bar(0, 0, color=color, label=legend_label)
  1242. x_bar = data['bar_x']*corr
  1243. xs.append(x_bar+start)
  1244. x_label = data['label_x']*corr
  1245. mapper[(label, model, dataset)] = (x_bar+start, rel_idx)
  1246. for cmpr in data['comparisons']:
  1247. if cmpr != ['na']:
  1248. print(cmpr)
  1249. p_comp = float(cmpr[-2])
  1250. t_comp = float(cmpr[-1])
  1251. if p_comp < 0.05 and abs(t_comp)>lo_e:
  1252. comps.append([
  1253. label,
  1254. model,
  1255. dataset,
  1256. cmpr[0],
  1257. cmpr[1],
  1258. p_comp,
  1259. t_comp,
  1260. ])
  1261. ax.bar(
  1262. x_bar+(start),
  1263. numpy.average(perms),
  1264. width=w,
  1265. color=color,
  1266. edgecolor='gray',
  1267. zorder=1.5
  1268. )
  1269. ax.bar(
  1270. x_bar+(start),
  1271. numpy.average(perms),
  1272. width=w,
  1273. fill=False,
  1274. edgecolor='dimgray',
  1275. zorder=2.5
  1276. )
  1277. ax.errorbar(
  1278. x_bar+(start),
  1279. numpy.average(perms),
  1280. yerr=numpy.std(perms),
  1281. color='dimgray',
  1282. capsize=5,
  1283. zorder=3.
  1284. )
  1285. ax.scatter(
  1286. [x_bar+start+(random.randrange(-m_sc, m_sc)*0.0001) for rand in range(len(perms))],
  1287. perms,
  1288. color=color,
  1289. edgecolor='white',
  1290. alpha=0.2,
  1291. zorder=2.
  1292. )
  1293. if rel_idx == 0:
  1294. ax.text(
  1295. x_label+start,
  1296. -.02,
  1297. s=label.replace('$', '\n'),
  1298. fontsize=t_s,
  1299. #fontweight='bold',
  1300. ha='center',
  1301. va='center',
  1302. )
  1303. ### absolute p-value
  1304. if p_abs < 0.005 and abs(t_abs)>lo_e:
  1305. '''
  1306. if abs(t_abs) > 0.8:
  1307. ax.text(
  1308. x_bar+start,
  1309. 0.035,
  1310. s='H',
  1311. fontweight='bold',
  1312. fontsize=15,
  1313. color='black',
  1314. ha='center',
  1315. va='center',
  1316. )
  1317. elif abs(t_abs) > 0.5:
  1318. ax.text(
  1319. x_bar+start,
  1320. 0.035,
  1321. s='M',
  1322. fontweight='bold',
  1323. fontsize=15,
  1324. ha='center',
  1325. va='center',
  1326. color='black',
  1327. )
  1328. '''
  1329. ax.scatter(
  1330. x_bar+start-0.08,
  1331. 0.02,
  1332. color='black',
  1333. edgecolor='white',
  1334. zorder=3.,
  1335. marker='*',
  1336. s=200
  1337. )
  1338. ax.scatter(
  1339. x_bar+start+0.08,
  1340. 0.02,
  1341. color='black',
  1342. edgecolor='white',
  1343. zorder=3.,
  1344. marker='*',
  1345. s=200
  1346. )
  1347. elif (str(p_abs)[:4] == '0.05' or p_abs<0.05) and abs(t_abs)>lo_e:
  1348. '''
  1349. if abs(t_abs) > 0.8:
  1350. ax.text(
  1351. x_bar+start,
  1352. 0.035,
  1353. s='H',
  1354. fontweight='bold',
  1355. fontsize=15,
  1356. color='black',
  1357. ha='center',
  1358. va='center',
  1359. )
  1360. elif abs(t_abs) > 0.5:
  1361. ax.text(
  1362. x_bar+start,
  1363. 0.035,
  1364. s='M',
  1365. fontweight='bold',
  1366. fontsize=15,
  1367. ha='center',
  1368. va='center',
  1369. color='black',
  1370. )
  1371. '''
  1372. ax.scatter(
  1373. x_bar+start,
  1374. 0.02,
  1375. color='black',
  1376. edgecolor='white',
  1377. zorder=3.,
  1378. marker='*',
  1379. s=200
  1380. )
  1381. ### comparative p-value
  1382. for l, m, d, start, end, p, t in comps:
  1383. st, st_idx = mapper[(start, m, d)]
  1384. nd, nd_idx = mapper[(end, m, d)]
  1385. ax.vlines(
  1386. ymin=0.39-(nd_idx*0.03),
  1387. ymax=0.39-(nd_idx*0.03)-0.01,
  1388. x=st,
  1389. color=colors[m][nd_idx],
  1390. #alpha=alpha,
  1391. zorder=3.,
  1392. linewidth=5.
  1393. )
  1394. ax.vlines(
  1395. ymin=0.39-(nd_idx*0.03),
  1396. ymax=0.39-(nd_idx*0.03)-0.01,
  1397. x=nd,
  1398. color=colors[m][nd_idx],
  1399. #alpha=alpha,
  1400. zorder=3.,
  1401. linewidth=5.
  1402. )
  1403. ax.hlines(
  1404. xmin=st-0.025,
  1405. xmax=nd+0.03,
  1406. y=0.39-(nd_idx*0.03),
  1407. color=colors[m][nd_idx],
  1408. zorder=3.,
  1409. #alpha=alpha,
  1410. linewidth=5.
  1411. )
  1412. if p < 0.005:
  1413. if abs(t) > hi_e:
  1414. ax.text(
  1415. st+((nd-st)*.5)-0.28,
  1416. .3975-(nd_idx*0.03),
  1417. s='L',
  1418. fontweight='bold',
  1419. fontsize=15,
  1420. color=colors[m][0],
  1421. ha='center',
  1422. va='center',
  1423. )
  1424. elif abs(t) > mid_e:
  1425. ax.text(
  1426. st+((nd-st)*.5)-0.28,
  1427. .3975-(nd_idx*0.03),
  1428. s='M',
  1429. fontweight='bold',
  1430. fontsize=15,
  1431. ha='center',
  1432. va='center',
  1433. color=colors[m][0],
  1434. )
  1435. elif abs(t) > lo_e:
  1436. ax.text(
  1437. st+((nd-st)*.5)-0.28,
  1438. .3975-(nd_idx*0.03),
  1439. s='S',
  1440. fontweight='bold',
  1441. fontsize=15,
  1442. ha='center',
  1443. va='center',
  1444. color=colors[m][0],
  1445. )
  1446. ax.scatter(
  1447. st+((nd-st)*.5)-0.08,
  1448. .3975-(nd_idx*0.03),
  1449. color=colors[m][0],
  1450. edgecolor='gray',
  1451. zorder=3.,
  1452. marker='*',
  1453. s=200
  1454. )
  1455. ax.scatter(
  1456. st+((nd-st)*.5)+0.08,
  1457. .3975-(nd_idx*0.03),
  1458. color=colors[m][0],
  1459. edgecolor='gray',
  1460. zorder=3.,
  1461. marker='*',
  1462. s=200
  1463. )
  1464. elif p < 0.05:
  1465. if abs(t) > hi_e:
  1466. ax.text(
  1467. st+((nd-st)*.5)-0.2,
  1468. .3975-(nd_idx*0.03),
  1469. s='L',
  1470. fontweight='bold',
  1471. fontsize=15,
  1472. color=colors[m][0],
  1473. ha='center',
  1474. va='center',
  1475. )
  1476. elif abs(t) > mid_e:
  1477. ax.text(
  1478. st+((nd-st)*.5)-0.2,
  1479. .3975-(nd_idx*0.03),
  1480. s='M',
  1481. fontweight='bold',
  1482. fontsize=15,
  1483. ha='center',
  1484. va='center',
  1485. color=colors[m][0],
  1486. )
  1487. elif abs(t) > lo_e:
  1488. ax.text(
  1489. st+((nd-st)*.5)-0.2,
  1490. .3975-(nd_idx*0.03),
  1491. s='S',
  1492. fontweight='bold',
  1493. fontsize=15,
  1494. ha='center',
  1495. va='center',
  1496. color=colors[m][0],
  1497. )
  1498. ax.scatter(
  1499. st+((nd-st)*.5),
  1500. .3975-(nd_idx*0.03),
  1501. color=colors[m][0],
  1502. edgecolor='gray',
  1503. zorder=3.,
  1504. marker='*',
  1505. s=200
  1506. )
  1507. ax.hlines(
  1508. xmin=min(xs),
  1509. xmax=max(xs),
  1510. color='black',
  1511. y=0,
  1512. )
  1513. ax.hlines(
  1514. xmin=min(xs),
  1515. xmax=max(xs),
  1516. color='silver',
  1517. alpha=0.5,
  1518. linestyle='dashed',
  1519. y=[y*0.01 for y in range(-5, 40, 5)],
  1520. zorder=1,
  1521. )
  1522. ax.legend(ncol=4, loc=9, columnspacing=lgnd_w, fontsize=17)
  1523. ax.set_xticks(
  1524. plot_info[plot][plot_n-1]['xticks'],
  1525. plot_info[plot][plot_n-1]['xlabels'],
  1526. fontsize = title_size,
  1527. fontweight = 'bold',
  1528. linespacing=1.5,
  1529. #fontstyle='italic',
  1530. )
  1531. ax.tick_params(axis='x',pad=30)
  1532. pyplot.savefig(out, dpi=600)
  1533. pyplot.clf()
  1534. pyplot.close()

plot01_gen_all_barplots.py, no license · at the source

Overview

  1. Research Group Cognition and Plasticity, Max Planck Institute for Human Cognitive and Brain Sciences, Leipzig, Germany
  2. Cognitive and Biological Psychology, Wilhelm Wundt Institute for Psychology, Leipzig University, Leipzig, Germany
Journal: Neurobiology of language (Cambridge, Mass.), volume 7, article NOL.a.244
Dates: received 4 July 2025; accepted 5 February 2026; published online 5 May 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1162/nol.a.244 · PMID 42137738 · PMCID PMC13171204 · OpenAlex W7128715304
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: other (modality)
Methods: Connectivity, Statistics, Machine learning
Keywords: brain stimulation, causality, language models, semantics, semantic models, semantic similarity, surprisal, transcranial magnetic stimulation (TMS)
Topic: Transcranial Magnetic Stimulation Studies (Neurology, Neuroscience), according to OpenAlex
Citations: not cited yet (Europe PMC); 167 references in the paper

Abstract

Noninvasive brain stimulation studies on semantic cognition hold the promise of revealing the functional relevance of brain areas through causal intervention. A primary challenge, however, is that findings are often interpreted through binary distinctions between sets of stimuli (e.g., related/unrelated words, same/different semantic category). This approach ignores the analysis of individual words, which mirrors every day language use and is crucial for understanding semantic cognition. In this work, we used semantic similarity, as measured by a language model, to investigate how transcranial magnetic stimulation (TMS) effects on semantic cognition unfold at the level of individual words. We reanalyzed five publicly available TMS data sets, covering multiple stimulation sites and lexical semantics tasks. We propose a simple methodology that can straightforwardly be applied to any TMS experiment on semantic cognition and showcase its potential to generate new insights. We modeled trial-level response times using the language model and computed the correlation between the two. We also repeated the analyses for two lower-level variables (word frequency and length). Importantly, for each data set, we compared correlations for effective and control (sham or vertex) stimulation conditions. We found that, for the language model, correlation was almost always significantly different depending on the type of stimulation (effective or control). Our results provide evidence that the stimulation effect interacts with the meaning of individual words. However, a similar pattern emerged in some cases for word frequency and length, suggesting that the effects of TMS on cognition can be widespread, well beyond their intended functional target. Collectively, our results demonstrate that language models provide new insight into the impact of neurostimulation on semantic processing, complementing standard measures.

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

Repository

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

OSF r3pwk

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Languages: Python (17)
Size: 35 files, 17 scripts
Software Heritage: not checked
Found in: “DATA AND CODE AVAILABILITY STATEMENT”
Holds: environment (requirements.txt), tests
Not found: README, license file, CITATION.cff, continuous integration, documentation
Tools: NumPy (11 files), Matplotlib (4 files), SciPy (4 files), Pingouin (2 files), MNE-Python (1 file), PyTorch (1 file), scikit-learn (1 file), Hugging Face Transformers (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
  • 28 September 2026: the link answers (HTTP 200)
17 files
At the source: osf.io/r3pwk

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:

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

Data and code availability statement

All the code, models, and (previously published) experimental data are available on the Open Science Framework website: https://osf.io/r3pwk.

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

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 28 September 2026: the first record

Recorded: type, language, journal, volume, pages, dates, 2 authors, 8 keywords, 2 funders, 162 references.

Cite

This paper

Bruera, A., & Hartwigsen, G. (2026). A Novel Approach to Map the Causal Impact of Brain Stimulation on Semantic Processing With Language Models. Neurobiology of language (Cambridge, Mass.), 7, NOL.a.244. https://doi.org/10.1162/nol.a.244

BibTeX

@article{bruera2026novel,
author = {Bruera, Andrea and Hartwigsen, Gesa},
title = {{A Novel Approach to Map the Causal Impact of Brain Stimulation on Semantic Processing With Language Models}},
journal = {Neurobiology of language (Cambridge, Mass.)},
year = {2026},
month = may,
volume = {7},
pages = {NOL.a.244},
publisher = {MIT Press},
issn = {2641-4368},
doi = {10.1162/nol.a.244},
url = {https://doi.org/10.1162/nol.a.244},
pmid = {42137738},
pmcid = {PMC13171204}
}

RIS

TY - JOUR
AU - Bruera, Andrea
AU - Hartwigsen, Gesa
TI - A Novel Approach to Map the Causal Impact of Brain Stimulation on Semantic Processing With Language Models
T2 - Neurobiology of language (Cambridge, Mass.)
J2 - Neurobiol Lang (Camb)
PY - 2026
DA - 2026/05/05
VL - 7
SP - NOL.a.244
SN - 2641-4368
PB - MIT Press
DO - 10.1162/nol.a.244
UR - https://doi.org/10.1162/nol.a.244
LA - en
ER -

CSL-JSON

{
"id": "10.1162/nol.a.244",
"type": "article-journal",
"title": "A Novel Approach to Map the Causal Impact of Brain Stimulation on Semantic Processing With Language Models",
"container-title": "Neurobiology of language (Cambridge, Mass.)",
"author": [
{
"family": "Bruera",
"given": "Andrea"
},
{
"family": "Hartwigsen",
"given": "Gesa"
}
],
"container-title-short": "Neurobiol Lang (Camb)",
"volume": "7",
"page": "NOL.a.244",
"DOI": "10.1162/nol.a.244",
"PMID": "42137738",
"PMCID": "PMC13171204",
"ISSN": "2641-4368",
"publisher": "MIT Press",
"URL": "https://doi.org/10.1162/nol.a.244",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
5
]
]
}
}

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-75841-9 [code]
Model-based semantic distance reveals adaptive coordination of distinct cognitive systems in flexible knowledge retrieval.
Journal: Nature communications
In common: Hugging Face Transformers, PyTorch, NumPy, 11 references
[2] doi:10.3758/s13415-026-01439-9
Stimulation success!? Improved response inhibition performance after prefrontal single-site and condition-and-perturb transcranial magnetic stimulation.
Journal: Cognitive, affective & behavioral neuroscience
In common: other, 7 references, author Gesa Hartwigsen
[3] doi:10.7554/elife.107933 [code]
Modality-agnostic decoding of vision and language from fMRI.
Journal: eLife
In common: Hugging Face Transformers, PyTorch, scikit-learn, 3 other tools, 8 references
[4] doi:10.1038/s41467-026-72253-7 [code]
Spurious alignment between large language models and brains can emerge from non-robust methods and overlooked confounds.
Journal: Nature communications
In common: Hugging Face Transformers, PyTorch, scikit-learn, 3 other tools, 5 references
[5] doi:10.7554/elife.106543 [code]
Stimulus dependencies-rather than next-word prediction-can explain pre-onset brain encoding in naturalistic listening designs.
Journal: eLife
In common: Hugging Face Transformers, MNE-Python, PyTorch, 4 other tools, 3 references
[6] doi:10.1162/imag.a.1227 [code]
Large language models reveal the neural tracking of linguistic context in attended and unattended multi-talker speech.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: Hugging Face Transformers, MNE-Python, PyTorch, 4 other tools, 3 references
[7] doi:10.1038/s42003-026-10169-0 [code]
Shared representations in brains and models reveal a two-route cortical organization during scene perception.
Journal: Communications biology
In common: Hugging Face Transformers, PyTorch, scikit-learn, 3 other tools, 5 references
[8] doi:10.1038/s41586-026-10691-5 [code]
Mapping the neuronal building blocks of human language with language models.
Journal: Nature
In common: scikit-learn, SciPy, Matplotlib, 1 other tool, 6 references
[9] doi:10.1162/imag.a.1281
Syntactic processing engages the semantic control network.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: 7 references
[10] doi:10.1162/nol.a.271 [code]
Compositional Complexity in Text and Images.
Journal: Neurobiology of language (Cambridge, Mass.)
In common: Pingouin, PyTorch, scikit-learn, 3 other tools, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

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.