├── .gitignore
├── 01-behavioral_data_analysis
├── .ipynb_checkpoints
│ ├── 01-training_progress_analysis-checkpoint.ipynb
│ └── 02-fmri_performance_analysis-checkpoint.ipynb
├── 00-log_processing.ipynb
├── 01-training_progress_analysis.ipynb
├── 02-fmri_performance_analysis.ipynb
└── 03-exclusion_variability.ipynb
├── 02-fmri_data_preparation
├── 01-aCompCor_denoising.ipynb
├── 02-timeseries_extraction.ipynb
├── 03-static_FC_estimation.ipynb
├── 04-dynamic_FC_estimation.ipynb
├── 05-motion_and_outliers_control.ipynb
└── 06-FC_density_plots.ipynb
├── 03-static_FC_analyses
├── 00-degree_distribution.ipynb
├── 01-static_modularity_calculation.m
├── 02-tidying_normalized_modularity.ipynb
├── 03-normalized_modularity_stats.ipynb
├── 04-modularity-behaviour_stats.ipynb
└── load_data.py
├── 04-dynamic_FC_analyses
├── 01-multilayer_modularity_calculation.m
├── 02-module_allegiance_matrix_calculation.ipynb
├── 03-fp_dm_plotting.ipynb
├── 04-whole-brain_normalized_recr_integ.ipynb
├── 05-whole-brain_normalized_recr_integ_stats.ipynb
├── 06-whole-brain_mlm_networks_summary.ipynb
├── 07-behavioral_variability_and_recruitmnent_stats.ipynb
├── 08-multilayer_modularity_calculation_signed.m
└── 10-dm_temporal_expansion.ipynb
├── 05-glm_analysis
├── 01-first_level_GLM_analysis.ipynb
├── 02-group_level_GLM_analysis.ipynb
├── 03-changes_in_brain_activity_stats.ipynb
└── 04-activity_vs_recruitment_stats.ipynb
├── LICENCE.txt
├── README.md
├── environment.yml
├── fctools
├── __init__.py
├── denoise.py
├── figures.py
├── networks.py
└── stats.py
└── support
├── modules.txt
└── onsets_dualnback.csv
/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 | */.ipynb_checkpoints/*
3 | */*/.ipynb_checkpoints/*.ipynb
4 |
5 |
--------------------------------------------------------------------------------
/01-behavioral_data_analysis/00-log_processing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: processing behavioral logs\n",
8 | "**Last edited:** 12-20-2019"
9 | ]
10 | },
11 | {
12 | "cell_type": "code",
13 | "execution_count": 1,
14 | "metadata": {},
15 | "outputs": [],
16 | "source": [
17 | "import matplotlib.pyplot as plt\n",
18 | "import pandas as pd\n",
19 | "import numpy as np\n",
20 | "import json\n",
21 | "import os\n",
22 | "from scipy.stats import norm"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 2,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "def convert_logfile(fname: str, task_meta: dict) -> pd.DataFrame:\n",
32 | " '''Converts logfile into concise and easy to work DataFrame\n",
33 | " \n",
34 | " Args:\n",
35 | " fname: path to log file\n",
36 | " task_meta: task metadata\n",
37 | " \n",
38 | " Returns:\n",
39 | " Table containing information about each trial. Each row contain block\n",
40 | " number, task condition, correct and actual response for both visual and\n",
41 | " auditory stimuli. \n",
42 | " '''\n",
43 | " # Setup local variables\n",
44 | " n_stims = task_meta['n_stims']\n",
45 | " n_blocks = task_meta['n_blocks']\n",
46 | " n_conditions = task_meta['n_conditions']\n",
47 | " n_trials = n_stims * n_blocks * n_conditions\n",
48 | " ttr = task_meta['ttr']\n",
49 | " \n",
50 | " # Create block and condition indices\n",
51 | " ind_block = np.repeat(np.arange(n_blocks), n_stims * n_conditions)[:, np.newaxis]\n",
52 | " ind_cond = np.tile(\n",
53 | " np.concatenate((np.ones(n_stims), 2*np.ones(n_stims))), n_blocks\n",
54 | " )[:, np.newaxis]\n",
55 | "\n",
56 | " df_ind = pd.DataFrame(\n",
57 | " np.hstack((ind_block, ind_cond)), \n",
58 | " columns=['block', 'condition']).astype('int')\n",
59 | "\n",
60 | " # Load stimulus data\n",
61 | " df = pd.read_csv(fname, delimiter='\\t', skiprows=3)\n",
62 | "\n",
63 | " stim_filter = df['Code'].str.contains('yes') | df['Code'].str.contains('no')\n",
64 | " df_stim = df.loc[stim_filter, :]\n",
65 | "\n",
66 | " # Split visual and audio stimuli\n",
67 | " df_stim_vis = df_stim.loc[df_stim['Event Type'] == 'Picture', \n",
68 | " ['xs(str)', 'Time']].reset_index(drop=True)\n",
69 | " df_stim_aud = df_stim.loc[df_stim['Event Type'] == 'Sound', \n",
70 | " 'xs(str)'].reset_index(drop=True)\n",
71 | " df_stim_vis.columns = ['ans_vis', 'stim_onset']\n",
72 | " df_stim_aud.name = 'ans_aud'\n",
73 | "\n",
74 | " # Merge visual and audio stimuli again & add response columns\n",
75 | " df_stim = pd.concat([df_ind, df_stim_vis, df_stim_aud], axis=1, sort=False)\n",
76 | " df_stim['resp_aud'], df_stim['resp_aud_time'], \\\n",
77 | " df_stim['resp_vis'], df_stim['resp_vis_time'] = np.zeros((4, n_trials), dtype='int')\n",
78 | " \n",
79 | " # Load response data\n",
80 | " resp_filer = df['Code'].isin(['1', '2'])\n",
81 | " df_resp = df.loc[resp_filer, :]\n",
82 | "\n",
83 | " # Analyze trialwise responses\n",
84 | " for i, row in df_stim.iterrows():\n",
85 | "\n",
86 | " r = df_resp.loc[(df_resp['Time'] > row['stim_onset']) & \\\n",
87 | " (df_resp['Time'] < row['stim_onset'] + ttr), \n",
88 | " ['Code', 'Time']]\n",
89 | "\n",
90 | " if '2' in r['Code'].unique():\n",
91 | " df_stim.loc[i, 'resp_aud'] = 1\n",
92 | " df_stim.loc[i, 'resp_aud_time'] = r.loc[r['Code']=='2', 'Time'].values[0] \n",
93 | " if '1' in r['Code'].unique():\n",
94 | " df_stim.loc[i, 'resp_vis'] = 1\n",
95 | " df_stim.loc[i, 'resp_vis_time'] = r.loc[r['Code']=='1', 'Time'].values[0] \n",
96 | "\n",
97 | " for modality in ['vis', 'aud']:\n",
98 | " df_stim[f'resp_{modality}_time'] -= df_stim['stim_onset'] \n",
99 | " df_stim.loc[df_stim[f'resp_{modality}_time'] < 0, \n",
100 | " f'resp_{modality}_time'] = np.nan\n",
101 | " df_stim[f'resp_{modality}_time'] /= 10\n",
102 | " df_stim[f'ans_{modality}'] = df_stim[f'ans_{modality}'].map({' yes': 1, ' no': 0})\n",
103 | "\n",
104 | " # Drop and reorder columns\n",
105 | " df_stim = df_stim[['block', 'condition', \n",
106 | " 'ans_vis', 'resp_vis', 'resp_vis_time',\n",
107 | " 'ans_aud', 'resp_aud', 'resp_aud_time']]\n",
108 | " \n",
109 | " return df_stim"
110 | ]
111 | },
112 | {
113 | "cell_type": "markdown",
114 | "metadata": {},
115 | "source": [
116 | "# Behavioral measures\n",
117 | "\n",
118 | "## Introduction\n",
119 | "\n",
120 | "We assume that each measure is calculated separately for single subject, session, task condition (1-back or 2-back) and stimuli modality (visual or auditory). Each behavioral response can be divided into one of four categories: *hit*, *miss*, *correct rejection* or *false alarm*:\n",
121 | "\n",
122 | "| Stimuli\\Response \t| Congruent \t| Incongruent \t|\n",
123 | "|------------------\t|-------------\t|-------------------\t|\n",
124 | "| Congruent \t| hit \t| miss \t|\n",
125 | "| Incongruent \t| false alarm \t| correct rejection \t|\n",
126 | "\n",
127 | "Subjects were instructed to respond with their thumb to congruent stimuli and omit response to incongruent stimuli. Note that in this task setting \"real misses\", i.e. when subject failed to respond within required time window cannot be distinguished from correct rejections and misses. Number of responses of each type was calculated on the level of entire run and for individual task blocks. Reaction time (RT) was calculated for hits and false alarms.\n",
128 | "\n",
129 | "## Measures\n",
130 | "\n",
131 | "### Accuracy\n",
132 | "\n",
133 | "Accuracy was calculated as the actual number of hits divided by the maximum number of hits.\n",
134 | "$$accuracy = \\frac{\\#hits}{N_{congruent}}$$\n",
135 | "\n",
136 | "This imperfect definition is prone to *respond to all stimuli* behavior. In this case accuracy will be one.\n",
137 | "\n",
138 | "### Penalized reaction time\n",
139 | "\n",
140 | "Penalized reaction time (PRT) tries to combine accuracy with the reaction time. Calculating PRT consists of three steps. First, all labeled reaction times are selected. Second, all reaction times for false alarms are set to 2000ms (maximal possible RT). Third, fake reaction times for misses are added to penalize for not responding. Then mean is calculated for task runs and individual blocks. Note that mean PRT over blocks is usually different than the one calculated for the enire task mean (some blocks consist of more responses than others). Formally, PRT is defined as\n",
141 | "$$prt = \\frac{1}{\\#false\\ alarms + \\#hits + \\#misses}(\\sum_{r=1}^{N_{responses}} prt_{r} + \\#misses \\times 2000\\text{ms})$$\n",
142 | "where $prt_{r}$ is 2000ms for false alarms and RT for hits.\n",
143 | "\n",
144 | "### D-prime\n",
145 | "\n",
146 | "D-prime based on signal detection theory takes into account both response sensitivity and specificity. First, *hit rate* $hr$ and *false alarm rate* $fr$ is calculated as:\n",
147 | "$$hr = \\frac{\\#hits}{\\#hits + \\#misses}$$\n",
148 | "$$fr = \\frac{\\#false\\ alarms}{\\#false\\ alarms + \\#correct\\ rejections}$$\n",
149 | "Second, to avoid problems with infinite values, all $hr$ or $fr$ values equal to 1 are set to 0.99 and all $hr$ or $fr$ values equal to 0 are set to 0.01. Finally, d-prime is calculated as difference between pdf transormed values of $hr$ and $fr$:\n",
150 | "$$d'=f(hr)-f(fr)$$\n",
151 | "where $f(x)$ is the inverse of the cumulative distribution function for Gaussian distribution.\n",
152 | "Note that mean d-prime over task blocks is not equal to mean calculated for the entire task."
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "execution_count": 3,
158 | "metadata": {},
159 | "outputs": [],
160 | "source": [
161 | "def calculate_behavioral_measures(df_stim: pd.DataFrame, task_meta: dict) -> tuple:\n",
162 | " '''Calculates main three behavioral measures: accuracy, pRT and D-prime.\n",
163 | " \n",
164 | " Args: \n",
165 | " df_stim: trialwise task information\n",
166 | " task_meta: task_meta\n",
167 | " \n",
168 | " Returns:\n",
169 | " Aggregated behavioral measures for entire task. \n",
170 | " (n_measures x n_conditions x n_modalities) \n",
171 | " Aggregated behavioral measures for specific blocks.\n",
172 | " (n_measures x n_conditions x n_modalities x n_blocks)\n",
173 | " '''\n",
174 | "\n",
175 | " def _get_resp_patterns(df_signal, filt_rows, modality):\n",
176 | " '''Calculates number of hits, correct rejections, misses and false alarms.\n",
177 | "\n",
178 | " Args: \n",
179 | " modality (str): either 'vis' or 'aud'\n",
180 | "\n",
181 | " Returns:\n",
182 | " Number of hits, correct rejections, misses and false alarms.\n",
183 | "\n",
184 | " '''\n",
185 | " no_hit = df_signal.loc[filt_rows, f'hit_{modality}'].sum()\n",
186 | " no_crr = df_signal.loc[filt_rows, f'crr_{modality}'].sum()\n",
187 | " no_mis = df_signal.loc[filt_rows, f'mis_{modality}'].sum()\n",
188 | " no_fal = df_signal.loc[filt_rows, f'fal_{modality}'].sum()\n",
189 | "\n",
190 | " return (no_hit, no_crr, no_mis, no_fal)\n",
191 | "\n",
192 | " def _calculate_dprime(no_hit, no_crr, no_mis, no_fal):\n",
193 | " '''Calculates d-prime signal detection index\n",
194 | "\n",
195 | " Args: \n",
196 | " no_hit (int): number of hits\n",
197 | " no_crr (int): number of correct rejections\n",
198 | " no_mis (int): number of misses\n",
199 | " no_fal (int): number of false alarms\n",
200 | "\n",
201 | " Returns:\n",
202 | " (float) D-prime index. \n",
203 | " '''\n",
204 | "\n",
205 | " hit_rate = no_hit / (no_hit + no_mis)\n",
206 | " fal_rate = no_fal / (no_fal + no_crr)\n",
207 | "\n",
208 | " # Corner cases (infinity problem)\n",
209 | " if fal_rate == 0: fal_rate = 0.01\n",
210 | " if fal_rate == 1: fal_rate = 0.99\n",
211 | "\n",
212 | " if hit_rate == 0: hit_rate = 0.01\n",
213 | " if hit_rate == 1: hit_rate = 0.99\n",
214 | "\n",
215 | " return norm.ppf(hit_rate) - norm.ppf(fal_rate)\n",
216 | "\n",
217 | " df_signal = df_stim[['block', 'condition']].copy()\n",
218 | " n_modalities = task_meta['n_modalities']\n",
219 | " n_conditions = task_meta['n_conditions']\n",
220 | " n_blocks = task_meta['n_blocks']\n",
221 | " ttr = task_meta['ttr'] / 10\n",
222 | "\n",
223 | " # Signal theory measures\n",
224 | " for s in ['vis', 'aud']:\n",
225 | " df_signal[f'hit_{s}'] = (df_stim[f'ans_{s}'] == 1) & (df_stim[f'resp_{s}'] == 1)\n",
226 | " df_signal[f'crr_{s}'] = (df_stim[f'ans_{s}'] == 0) & (df_stim[f'resp_{s}'] == 0)\n",
227 | " df_signal[f'mis_{s}'] = (df_stim[f'ans_{s}'] == 1) & (df_stim[f'resp_{s}'] == 0)\n",
228 | " df_signal[f'fal_{s}'] = (df_stim[f'ans_{s}'] == 0) & (df_stim[f'resp_{s}'] == 1)\n",
229 | " df_signal[f'hit_time_{s}'] = df_signal[f'hit_{s}'].replace(False, np.nan) \\\n",
230 | " * df_stim[f'resp_{s}_time']\n",
231 | " df_signal[f'fal_time_{s}'] = df_signal[f'fal_{s}'].replace(False, np.nan) \\\n",
232 | " * df_stim[f'resp_{s}_time']\n",
233 | "\n",
234 | " acc_block, prt_block, dpr_block = np.zeros((3, n_conditions, n_modalities, n_blocks))\n",
235 | " acc, prt, dpr = np.zeros((3, n_conditions, n_modalities))\n",
236 | " hit_rate, fal_rate = np.zeros((2, n_conditions, n_modalities))\n",
237 | "\n",
238 | " for idx_c, condition in enumerate([1, 2]):\n",
239 | " for idx_m, modality in enumerate(['vis', 'aud']):\n",
240 | "\n",
241 | " filt_rows = (df_signal['condition'] == condition)\n",
242 | "\n",
243 | " # Count hits, correct rejections, misses and false alarms\n",
244 | " no_hit, no_crr, no_mis, no_fal = _get_resp_patterns(df_signal, filt_rows, modality)\n",
245 | "\n",
246 | " # Calculate behavioral measures (whole task)\n",
247 | " prt[idx_c, idx_m] = \\\n",
248 | " (df_signal.loc[filt_rows, f'hit_time_{modality}'].sum() + ttr * (no_fal + no_mis)) \\\n",
249 | " / (no_hit + no_fal + no_mis)\n",
250 | " dpr[idx_c, idx_m] = _calculate_dprime(no_hit, no_crr, no_mis, no_fal)\n",
251 | " \n",
252 | " # Grab also simpler measures for exclusion criteria\n",
253 | " hit_rate[idx_c, idx_m] = no_hit / (no_hit + no_mis)\n",
254 | " fal_rate[idx_c, idx_m] = no_fal / (no_fal + no_crr)\n",
255 | "\n",
256 | " for idx_b in range(n_blocks):\n",
257 | "\n",
258 | " filt_rows = (df_signal['condition'] == condition) \\\n",
259 | " & (df_signal['block'] == idx_b)\n",
260 | "\n",
261 | " # Count hits, correct rejections, misses and false alarms\n",
262 | " no_hit, no_crr, no_mis, no_fal = _get_resp_patterns(\n",
263 | " df_signal, filt_rows, modality\n",
264 | " )\n",
265 | "\n",
266 | " # Calculate behavioral measures (block level)\n",
267 | " acc_block[idx_c, idx_m, idx_b] = no_hit / (no_hit + no_mis)\n",
268 | " prt_block[idx_c, idx_m, idx_b] = \\\n",
269 | " (df_signal.loc[filt_rows, f'hit_time_{modality}'].sum() + ttr * (no_fal + no_mis)) \\\n",
270 | " / (no_hit + no_fal + no_mis)\n",
271 | " dpr_block[idx_c, idx_m, idx_b] = _calculate_dprime(no_hit, no_crr, no_mis, no_fal)\n",
272 | "\n",
273 | " acc = np.nanmean(acc_block, axis=2)\n",
274 | " \n",
275 | " return (np.stack((acc, prt, dpr, hit_rate, fal_rate)), np.stack((acc_block, prt_block, dpr_block)))"
276 | ]
277 | },
278 | {
279 | "cell_type": "markdown",
280 | "metadata": {},
281 | "source": [
282 | "Load group assignment table and exclude subjects with incomplete data."
283 | ]
284 | },
285 | {
286 | "cell_type": "code",
287 | "execution_count": 4,
288 | "metadata": {},
289 | "outputs": [
290 | {
291 | "data": {
292 | "text/html": [
293 | "
\n",
294 | "\n",
307 | "
\n",
308 | " \n",
309 | " \n",
310 | " | \n",
311 | " sub | \n",
312 | " group | \n",
313 | "
\n",
314 | " \n",
315 | " \n",
316 | " \n",
317 | " 0 | \n",
318 | " sub-01 | \n",
319 | " Control | \n",
320 | "
\n",
321 | " \n",
322 | " 1 | \n",
323 | " sub-02 | \n",
324 | " Control | \n",
325 | "
\n",
326 | " \n",
327 | " 3 | \n",
328 | " sub-04 | \n",
329 | " Control | \n",
330 | "
\n",
331 | " \n",
332 | " 4 | \n",
333 | " sub-05 | \n",
334 | " Experimental | \n",
335 | "
\n",
336 | " \n",
337 | " 5 | \n",
338 | " sub-06 | \n",
339 | " Experimental | \n",
340 | "
\n",
341 | " \n",
342 | "
\n",
343 | "
"
344 | ],
345 | "text/plain": [
346 | " sub group\n",
347 | "0 sub-01 Control\n",
348 | "1 sub-02 Control\n",
349 | "3 sub-04 Control\n",
350 | "4 sub-05 Experimental\n",
351 | "5 sub-06 Experimental"
352 | ]
353 | },
354 | "execution_count": 4,
355 | "metadata": {},
356 | "output_type": "execute_result"
357 | }
358 | ],
359 | "source": [
360 | "df_group = pd.read_csv('data/group_assignment.csv')\n",
361 | "df_group = df_group.loc[~df_group['group'].isna(), :]\n",
362 | "df_group.head()"
363 | ]
364 | },
365 | {
366 | "cell_type": "markdown",
367 | "metadata": {},
368 | "source": [
369 | "Process all logs and save aggregated behavioral data to file. Data description:\n",
370 | "- `beh`: np.array containing behavioral measures calculated for entire dual n-back run\n",
371 | "- `beh_block`: contains the same measures calculated for individual task blocks\n",
372 | "- `meta`: dictionary describing fields in `beh` and `beh_block`"
373 | ]
374 | },
375 | {
376 | "cell_type": "code",
377 | "execution_count": 5,
378 | "metadata": {},
379 | "outputs": [
380 | {
381 | "name": "stdout",
382 | "output_type": "stream",
383 | "text": [
384 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_1-dual_n-back_modified.log\n",
385 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_1-dual_n-back_modified.log\n",
386 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_1-dual_n-back_modified.log\n",
387 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_1-dual_n-back_modified.log\n",
388 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_1-dual_n-back_modified.log\n",
389 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_1-dual_n-back_modified.log\n",
390 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_1-dual_n-back_modified.log\n",
391 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_1-dual_n-back_modified.log\n",
392 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_1-dual_n-back_modified.log\n",
393 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_1-dual_n-back_modified.log\n",
394 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_1-dual_n-back_modified.log\n",
395 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_1-dual_n-back_modified.log\n",
396 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_1-dual_n-back_modified.log\n",
397 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_1-dual_n-back_modified.log\n",
398 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_1-dual_n-back_modified.log\n",
399 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_1-dual_n-back_modified.log\n",
400 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_1-dual_n-back_modified.log\n",
401 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_1-dual_n-back_modified.log\n",
402 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_1-dual_n-back_modified.log\n",
403 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_1-dual_n-back_modified.log\n",
404 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_1-dual_n-back_modified.log\n",
405 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_1-dual_n-back_modified.log\n",
406 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_1-dual_n-back_modified.log\n",
407 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_1-dual_n-back_modified.log\n",
408 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_1-dual_n-back_modified.log\n",
409 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_1-dual_n-back_modified.log\n",
410 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_1-dual_n-back_modified.log\n",
411 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_1-dual_n-back_modified.log\n",
412 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_1-dual_n-back_modified.log\n",
413 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_1-dual_n-back_modified.log\n",
414 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_1-dual_n-back_modified.log\n",
415 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_1-dual_n-back_modified.log\n",
416 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_1-dual_n-back_modified.log\n",
417 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_1-dual_n-back_modified.log\n",
418 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_1-dual_n-back_modified.log\n",
419 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_1-dual_n-back_modified.log\n",
420 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_1-dual_n-back_modified.log\n",
421 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_1-dual_n-back_modified.log\n",
422 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_1-dual_n-back_modified.log\n",
423 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_1-dual_n-back_modified.log\n",
424 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_1-dual_n-back_modified.log\n",
425 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_1-dual_n-back_modified.log\n",
426 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_1-dual_n-back_modified.log\n",
427 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_1-dual_n-back_modified.log\n",
428 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_1-dual_n-back_modified.log\n",
429 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_1-dual_n-back_modified.log\n",
430 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_2-dual_n-back_modified.log\n",
431 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_2-dual_n-back_modified.log\n",
432 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_2-dual_n-back_modified.log\n",
433 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_2-dual_n-back_modified.log\n",
434 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_2-dual_n-back_modified.log\n",
435 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_2-dual_n-back_modified.log\n",
436 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_2-dual_n-back_modified.log\n",
437 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_2-dual_n-back_modified.log\n",
438 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_2-dual_n-back_modified.log\n",
439 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_2-dual_n-back_modified.log\n",
440 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_2-dual_n-back_modified.log\n",
441 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_2-dual_n-back_modified.log\n",
442 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_2-dual_n-back_modified.log\n",
443 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_2-dual_n-back_modified.log\n",
444 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_2-dual_n-back_modified.log\n",
445 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_2-dual_n-back_modified.log\n",
446 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_2-dual_n-back_modified.log\n",
447 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_2-dual_n-back_modified.log\n",
448 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_2-dual_n-back_modified.log\n",
449 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_2-dual_n-back_modified.log\n",
450 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_2-dual_n-back_modified.log\n",
451 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_2-dual_n-back_modified.log\n",
452 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_2-dual_n-back_modified.log\n",
453 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_2-dual_n-back_modified.log\n",
454 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_2-dual_n-back_modified.log\n",
455 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_2-dual_n-back_modified.log\n",
456 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_2-dual_n-back_modified.log\n",
457 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_2-dual_n-back_modified.log\n",
458 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_2-dual_n-back_modified.log\n",
459 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_2-dual_n-back_modified.log\n",
460 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_2-dual_n-back_modified.log\n",
461 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_2-dual_n-back_modified.log\n",
462 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_2-dual_n-back_modified.log\n",
463 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_2-dual_n-back_modified.log\n",
464 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_2-dual_n-back_modified.log\n",
465 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_2-dual_n-back_modified.log\n",
466 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_2-dual_n-back_modified.log\n",
467 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_2-dual_n-back_modified.log\n",
468 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_2-dual_n-back_modified.log\n",
469 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_2-dual_n-back_modified.log\n",
470 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_2-dual_n-back_modified.log\n",
471 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_2-dual_n-back_modified.log\n",
472 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_2-dual_n-back_modified.log\n",
473 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_2-dual_n-back_modified.log\n",
474 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_2-dual_n-back_modified.log\n",
475 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_2-dual_n-back_modified.log\n",
476 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_3-dual_n-back_modified.log\n",
477 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_3-dual_n-back_modified.log\n",
478 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_3-dual_n-back_modified.log\n",
479 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_3-dual_n-back_modified.log\n",
480 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_3-dual_n-back_modified.log\n",
481 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_3-dual_n-back_modified.log\n",
482 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_3-dual_n-back_modified.log\n",
483 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_3-dual_n-back_modified.log\n",
484 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_3-dual_n-back_modified.log\n",
485 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_3-dual_n-back_modified.log\n",
486 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_3-dual_n-back_modified.log\n",
487 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_3-dual_n-back_modified.log\n",
488 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_3-dual_n-back_modified.log\n",
489 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_3-dual_n-back_modified.log\n",
490 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_3-dual_n-back_modified.log\n",
491 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_3-dual_n-back_modified.log\n",
492 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_3-dual_n-back_modified.log\n",
493 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_3-dual_n-back_modified.log\n",
494 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_3-dual_n-back_modified.log\n",
495 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_3-dual_n-back_modified.log\n",
496 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_3-dual_n-back_modified.log\n",
497 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_3-dual_n-back_modified.log\n",
498 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_3-dual_n-back_modified.log\n",
499 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_3-dual_n-back_modified.log\n",
500 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_3-dual_n-back_modified.log\n",
501 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_3-dual_n-back_modified.log\n",
502 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_3-dual_n-back_modified.log\n",
503 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_3-dual_n-back_modified.log\n",
504 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_3-dual_n-back_modified.log\n",
505 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_3-dual_n-back_modified.log\n",
506 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_3-dual_n-back_modified.log\n",
507 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_3-dual_n-back_modified.log\n",
508 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_3-dual_n-back_modified.log\n",
509 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_3-dual_n-back_modified.log\n",
510 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_3-dual_n-back_modified.log\n",
511 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_3-dual_n-back_modified.log\n",
512 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_3-dual_n-back_modified.log\n",
513 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_3-dual_n-back_modified.log\n",
514 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_3-dual_n-back_modified.log\n",
515 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_3-dual_n-back_modified.log\n",
516 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_3-dual_n-back_modified.log\n",
517 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_3-dual_n-back_modified.log\n",
518 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_3-dual_n-back_modified.log\n",
519 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_3-dual_n-back_modified.log\n",
520 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_3-dual_n-back_modified.log\n",
521 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_3-dual_n-back_modified.log\n",
522 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/001d_4-dual_n-back_modified.log\n",
523 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/002d_4-dual_n-back_modified.log\n",
524 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/004d_4-dual_n-back_modified.log\n",
525 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/005d_4-dual_n-back_modified.log\n",
526 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/006d_4-dual_n-back_modified.log\n",
527 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/007d_4-dual_n-back_modified.log\n",
528 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/008d_4-dual_n-back_modified.log\n",
529 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/010d_4-dual_n-back_modified.log\n",
530 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/011d_4-dual_n-back_modified.log\n",
531 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/012d_4-dual_n-back_modified.log\n",
532 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/013d_4-dual_n-back_modified.log\n",
533 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/014d_4-dual_n-back_modified.log\n",
534 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/015d_4-dual_n-back_modified.log\n",
535 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/016d_4-dual_n-back_modified.log\n",
536 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/018d_4-dual_n-back_modified.log\n",
537 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/019d_4-dual_n-back_modified.log\n",
538 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/020d_4-dual_n-back_modified.log\n",
539 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/021d_4-dual_n-back_modified.log\n",
540 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/023d_4-dual_n-back_modified.log\n",
541 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/024d_4-dual_n-back_modified.log\n",
542 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/025d_4-dual_n-back_modified.log\n",
543 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/026d_4-dual_n-back_modified.log\n",
544 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/027d_4-dual_n-back_modified.log\n",
545 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/028d_4-dual_n-back_modified.log\n",
546 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/029d_4-dual_n-back_modified.log\n",
547 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/030d_4-dual_n-back_modified.log\n",
548 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/033d_4-dual_n-back_modified.log\n",
549 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/035d_4-dual_n-back_modified.log\n",
550 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/036d_4-dual_n-back_modified.log\n",
551 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/037d_4-dual_n-back_modified.log\n",
552 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/039d_4-dual_n-back_modified.log\n",
553 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/041d_4-dual_n-back_modified.log\n",
554 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/042d_4-dual_n-back_modified.log\n",
555 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/043d_4-dual_n-back_modified.log\n",
556 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/044d_4-dual_n-back_modified.log\n",
557 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/045d_4-dual_n-back_modified.log\n",
558 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/046d_4-dual_n-back_modified.log\n",
559 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/047d_4-dual_n-back_modified.log\n",
560 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/048d_4-dual_n-back_modified.log\n",
561 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/050d_4-dual_n-back_modified.log\n",
562 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/051d_4-dual_n-back_modified.log\n",
563 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/052d_4-dual_n-back_modified.log\n",
564 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/053d_4-dual_n-back_modified.log\n",
565 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/054d_4-dual_n-back_modified.log\n",
566 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/055d_4-dual_n-back_modified.log\n",
567 | "/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral/056d_4-dual_n-back_modified.log\n"
568 | ]
569 | }
570 | ],
571 | "source": [
572 | "root = '/home/kmb/Desktop/Neuroscience/Projects/FINC_learning_brain/data/sourcedata/behavioral'\n",
573 | "\n",
574 | "task_meta = {\n",
575 | " 'n_stims': 12,\n",
576 | " 'n_blocks': 10,\n",
577 | " 'n_modalities': 2,\n",
578 | " 'n_conditions': 2,\n",
579 | " 'n_sessions': 4,\n",
580 | " 'n_measures': 3,\n",
581 | " 'ttr': 20000,\n",
582 | " 'n_subjects': df_group.shape[0]\n",
583 | "}\n",
584 | "\n",
585 | "beh = np.full((task_meta['n_subjects'], task_meta['n_sessions'], \n",
586 | " task_meta['n_measures'] + 2, task_meta['n_conditions'], \n",
587 | " task_meta['n_modalities']), \n",
588 | " np.nan)\n",
589 | "beh_block = np.full((task_meta['n_subjects'], task_meta['n_sessions'], \n",
590 | " task_meta['n_measures'], task_meta['n_conditions'], \n",
591 | " task_meta['n_modalities'], task_meta['n_blocks']), \n",
592 | " np.nan)\n",
593 | "\n",
594 | "for ix_ses, ses in enumerate(['1', '2', '3', '4']):\n",
595 | " for ix_sub, sub in enumerate(df_group['sub']):\n",
596 | " \n",
597 | " logpath = os.path.join(root, f'0{sub[-2:]}d_{ses}-dual_n-back_modified.log')\n",
598 | " print(logpath)\n",
599 | " \n",
600 | " if os.path.exists(logpath):\n",
601 | "\n",
602 | " beh[ix_sub, ix_ses], beh_block[ix_sub, ix_ses] = \\\n",
603 | " calculate_behavioral_measures(convert_logfile(logpath, task_meta), task_meta)\n",
604 | " \n",
605 | "# Create metadata describing beh and beh_block fields\n",
606 | "meta = {\n",
607 | " 'dim1': df_group['sub'].tolist(),\n",
608 | " 'dim2': [f'ses-{ses}' for ses in range(1, task_meta['n_sessions'] + 1)],\n",
609 | " 'dim3': ['acc', 'prt', 'dpr', 'hit_rate', 'fal_rate'],\n",
610 | " 'dim4': ['1-back', '2-back'],\n",
611 | " 'dim5': ['vis', 'aud'],\n",
612 | " 'dim6': [f'block-{block:02}' for block in range(1, task_meta['n_blocks'] + 1)],\n",
613 | " 'exp': list(df_group['group'] == 'Experimental'),\n",
614 | " 'con': list(df_group['group'] == 'Control'),\n",
615 | "}\n",
616 | "\n",
617 | "# Save aggregated behavioral measures\n",
618 | "np.save('data/aggregated_behavioral_data.npy', beh)\n",
619 | "np.save('data/aggregated_behavioral_data_block.npy', beh_block)\n",
620 | "with open('data/aggregated_behavioral_data.json', 'w') as f:\n",
621 | " json.dump(meta, f)"
622 | ]
623 | }
624 | ],
625 | "metadata": {
626 | "kernelspec": {
627 | "display_name": "Python 3",
628 | "language": "python",
629 | "name": "python3"
630 | },
631 | "language_info": {
632 | "codemirror_mode": {
633 | "name": "ipython",
634 | "version": 3
635 | },
636 | "file_extension": ".py",
637 | "mimetype": "text/x-python",
638 | "name": "python",
639 | "nbconvert_exporter": "python",
640 | "pygments_lexer": "ipython3",
641 | "version": "3.7.3"
642 | }
643 | },
644 | "nbformat": 4,
645 | "nbformat_minor": 4
646 | }
647 |
--------------------------------------------------------------------------------
/02-fmri_data_preparation/02-timeseries_extraction.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: Timeseries extraction\n",
8 | "\n",
9 | "Timeseries extraction of data from working memory training experiment.\n",
10 | "\n",
11 | "Filtering:\n",
12 | "- 0.008 - 0.25 Hz\n",
13 | "\n",
14 | "**Last edited:** 09-11-2018\n"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "Step 0: Loading libraries\n",
22 | "-----------------------"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 2,
28 | "metadata": {},
29 | "outputs": [],
30 | "source": [
31 | "%matplotlib inline\n",
32 | "\n",
33 | "import sys\n",
34 | "sys.path.append(\"..\")\n",
35 | "\n",
36 | "import os\n",
37 | "import pandas as pd\n",
38 | "import nibabel as nib\n",
39 | "import numpy as np \n",
40 | "import matplotlib.pyplot as plt \n",
41 | "import warnings\n",
42 | "warnings.filterwarnings('ignore')\n",
43 | "\n",
44 | "from nilearn import datasets, plotting, input_data, signal, image \n",
45 | "from nilearn.input_data import NiftiLabelsMasker\n",
46 | "\n",
47 | "from fctools import denoise"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "Step 1: Preparing paths to files\n",
55 | "------------------------------"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": 3,
61 | "metadata": {},
62 | "outputs": [
63 | {
64 | "name": "stdout",
65 | "output_type": "stream",
66 | "text": [
67 | "Sample size: 46\n"
68 | ]
69 | }
70 | ],
71 | "source": [
72 | "# Setting directories for input and output files\n",
73 | "top_dir = '/media/finc/Elements/LearningBrain_fmriprep/'\n",
74 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n",
75 | "\n",
76 | "# Selecting subjects who finished the study\n",
77 | "groups = pd.read_csv('../data/behavioral/group_assignment.csv')\n",
78 | "subs = pd.Series.tolist(groups['sub'][groups['group'].isin(['Experimental', 'Control'])])\n",
79 | "\n",
80 | "# Setting sessions and task names\n",
81 | "sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4']\n",
82 | "tasks = {'rest': 305, 'dualnback': 340}\n",
83 | "t_r = 2\n",
84 | "\n",
85 | "suffix = '_bold_space-MNI152NLin2009cAsym_preproc.nii.gz'\n",
86 | "denoising = '_denoised_acompcor_task_effects.nii.gz'\n",
87 | "\n",
88 | "print(f'Sample size: {len(subs)}')"
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {},
94 | "source": [
95 | "Step 2: Creating parcellations \n",
96 | "--------------------------------"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 4,
102 | "metadata": {},
103 | "outputs": [
104 | {
105 | "data": {
106 | "image/png": "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\n",
107 | "text/plain": [
108 | ""
109 | ]
110 | },
111 | "metadata": {},
112 | "output_type": "display_data"
113 | }
114 | ],
115 | "source": [
116 | "# Loading Power ROIs coordinates\n",
117 | "power = datasets.fetch_coords_power_2011()\n",
118 | "power_coords = np.vstack((power.rois['x'], power.rois['y'], power.rois['z'])).T\n",
119 | "\n",
120 | "# Creating masker file\n",
121 | "power = input_data.NiftiSpheresMasker(\n",
122 | " seeds = power_coords, \n",
123 | " radius = 5,\n",
124 | ")\n",
125 | "\n",
126 | "# Loading Schaefer atlas (300 regions)\n",
127 | "atlas_filename = '/home/finc/Dropbox/Projects/LearningBrain/support/Schaefer2018_300Parcels_7Networks_order_FSLMNI152_2mm.nii.gz'\n",
128 | "plotting.plot_roi(atlas_filename)\n",
129 | "schaefer = input_data.NiftiLabelsMasker(atlas_filename)\n",
130 | "\n",
131 | "\n",
132 | "parcellations = np.asarray([[power, 'power', 264], \n",
133 | " [schaefer, 'schaefer', 300]])\n"
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "Step 3: Extracting timeseries\n",
141 | "----------------------"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "execution_count": 47,
147 | "metadata": {},
148 | "outputs": [
149 | {
150 | "name": "stdout",
151 | "output_type": "stream",
152 | "text": [
153 | "Extracting timeseries: schaefer_new parcellation, rest\n",
154 | "Extracting timeseries sub-01\n",
155 | "Extracting timeseries sub-02\n",
156 | "Extracting timeseries sub-04\n",
157 | "Extracting timeseries sub-05\n",
158 | "Extracting timeseries sub-06\n",
159 | "Extracting timeseries sub-07\n",
160 | "Extracting timeseries sub-08\n",
161 | "Extracting timeseries sub-10\n",
162 | "Extracting timeseries sub-11\n",
163 | "Extracting timeseries sub-12\n",
164 | "Extracting timeseries sub-13\n",
165 | "Extracting timeseries sub-14\n",
166 | "Extracting timeseries sub-15\n",
167 | "Extracting timeseries sub-16\n",
168 | "Extracting timeseries sub-18\n",
169 | "Extracting timeseries sub-19\n",
170 | "Extracting timeseries sub-20\n",
171 | "sub-20ses-2rest does not exist\n",
172 | "Extracting timeseries sub-21\n",
173 | "Extracting timeseries sub-23\n",
174 | "Extracting timeseries sub-24\n",
175 | "Extracting timeseries sub-25\n",
176 | "Extracting timeseries sub-26\n",
177 | "Extracting timeseries sub-27\n",
178 | "Extracting timeseries sub-28\n",
179 | "Extracting timeseries sub-29\n",
180 | "Extracting timeseries sub-30\n",
181 | "Extracting timeseries sub-33\n",
182 | "Extracting timeseries sub-35\n",
183 | "Extracting timeseries sub-36\n",
184 | "Extracting timeseries sub-37\n",
185 | "Extracting timeseries sub-39\n",
186 | "Extracting timeseries sub-41\n",
187 | "Extracting timeseries sub-42\n",
188 | "Extracting timeseries sub-43\n",
189 | "Extracting timeseries sub-44\n",
190 | "sub-44ses-2rest does not exist\n",
191 | "Extracting timeseries sub-45\n",
192 | "Extracting timeseries sub-46\n",
193 | "Extracting timeseries sub-47\n",
194 | "Extracting timeseries sub-48\n",
195 | "Extracting timeseries sub-50\n",
196 | "Extracting timeseries sub-51\n",
197 | "Extracting timeseries sub-52\n",
198 | "Extracting timeseries sub-53\n",
199 | "Extracting timeseries sub-54\n",
200 | "Extracting timeseries sub-55\n",
201 | "Extracting timeseries sub-56\n",
202 | "Extracting timeseries: schaefer_new parcellation, dualnback\n",
203 | "Extracting timeseries sub-01\n",
204 | "Extracting timeseries sub-02\n",
205 | "Extracting timeseries sub-04\n",
206 | "Extracting timeseries sub-05\n",
207 | "Extracting timeseries sub-06\n",
208 | "Extracting timeseries sub-07\n",
209 | "Extracting timeseries sub-08\n",
210 | "Extracting timeseries sub-10\n",
211 | "Extracting timeseries sub-11\n",
212 | "Extracting timeseries sub-12\n",
213 | "Extracting timeseries sub-13\n",
214 | "Extracting timeseries sub-14\n",
215 | "Extracting timeseries sub-15\n",
216 | "Extracting timeseries sub-16\n",
217 | "Extracting timeseries sub-18\n",
218 | "Extracting timeseries sub-19\n",
219 | "Extracting timeseries sub-20\n",
220 | "Extracting timeseries sub-21\n",
221 | "Extracting timeseries sub-23\n",
222 | "Extracting timeseries sub-24\n",
223 | "Extracting timeseries sub-25\n",
224 | "Extracting timeseries sub-26\n",
225 | "Extracting timeseries sub-27\n",
226 | "Extracting timeseries sub-28\n",
227 | "Extracting timeseries sub-29\n",
228 | "Extracting timeseries sub-30\n",
229 | "Extracting timeseries sub-33\n",
230 | "Extracting timeseries sub-35\n",
231 | "Extracting timeseries sub-36\n",
232 | "Extracting timeseries sub-37\n",
233 | "Extracting timeseries sub-39\n",
234 | "Extracting timeseries sub-41\n",
235 | "Extracting timeseries sub-42\n",
236 | "Extracting timeseries sub-43\n",
237 | "Extracting timeseries sub-44\n",
238 | "Extracting timeseries sub-45\n",
239 | "Extracting timeseries sub-46\n",
240 | "Extracting timeseries sub-47\n",
241 | "Extracting timeseries sub-48\n",
242 | "Extracting timeseries sub-50\n",
243 | "Extracting timeseries sub-51\n",
244 | "Extracting timeseries sub-52\n",
245 | "Extracting timeseries sub-53\n",
246 | "Extracting timeseries sub-54\n",
247 | "Extracting timeseries sub-55\n",
248 | "Extracting timeseries sub-56\n"
249 | ]
250 | }
251 | ],
252 | "source": [
253 | "# Iterating over parcellations\n",
254 | "for p in range(parcellations.shape[0]):\n",
255 | " n_roi = parcellations[p,2]\n",
256 | " \n",
257 | " # Iterating over tasks\n",
258 | " for task, n_scans in tasks.items():\n",
259 | " print(f'Extracting timeseries: {parcellations[p,1]} parcellation, {task}')\n",
260 | " timeseries_all = np.zeros((len(subs), len(sess), n_scans, n_roi))\n",
261 | " \n",
262 | " # Iterating over subjects, sessiosns\n",
263 | " for i, sub in enumerate(subs):\n",
264 | " print(f'Extracting timeseries {sub}')\n",
265 | " for j, ses in enumerate(sess):\n",
266 | " \n",
267 | " # Getting directory/file names\n",
268 | " sub_dir = f'{top_dir}{sub}/{ses}/func/'\n",
269 | " sub_name = f'{sub}_{ses}_task-{task}' \n",
270 | " denoised_data = f'{sub_dir}{sub_name}{suffix[:-7]}{denoising}'\n",
271 | "\n",
272 | " if not os.path.exists(denoised_data):\n",
273 | " print(f'{sub}{ses}{task} does not exist')\n",
274 | " else:\n",
275 | " # Extracting timeseries for specified atlas\n",
276 | " timeseries = parcellations[p,0].fit_transform(denoised_data, confounds=None)\n",
277 | " # Filtering data\n",
278 | " timeseries = signal.clean(timeseries, \n",
279 | " low_pass=0.25, \n",
280 | " high_pass=0.008, \n",
281 | " t_r=t_r, \n",
282 | " detrend=False, \n",
283 | " standardize=True,\n",
284 | " )\n",
285 | " timeseries_all[i, j, :, :] = timeseries\n",
286 | " np.save(f'{out_dir}/{task}/LB_{task}_timeseries_{parcellations[p,1]}_denoised_acompcor_no_smooth.npy', timeseries_all)"
287 | ]
288 | }
289 | ],
290 | "metadata": {
291 | "kernelspec": {
292 | "display_name": "Python 3",
293 | "language": "python",
294 | "name": "python3"
295 | },
296 | "language_info": {
297 | "codemirror_mode": {
298 | "name": "ipython",
299 | "version": 3
300 | },
301 | "file_extension": ".py",
302 | "mimetype": "text/x-python",
303 | "name": "python",
304 | "nbconvert_exporter": "python",
305 | "pygments_lexer": "ipython3",
306 | "version": "3.7.3"
307 | }
308 | },
309 | "nbformat": 4,
310 | "nbformat_minor": 2
311 | }
312 |
--------------------------------------------------------------------------------
/02-fmri_data_preparation/03-static_FC_estimation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: Static connectivity estimation"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "Step 0: Loading libraries\n",
15 | "--------------------------------"
16 | ]
17 | },
18 | {
19 | "cell_type": "code",
20 | "execution_count": 2,
21 | "metadata": {},
22 | "outputs": [
23 | {
24 | "name": "stderr",
25 | "output_type": "stream",
26 | "text": [
27 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:855: MatplotlibDeprecationWarning: \n",
28 | "examples.directory is deprecated; in the future, examples will be found relative to the 'datapath' directory.\n",
29 | " \"found relative to the 'datapath' directory.\".format(key))\n",
30 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:846: MatplotlibDeprecationWarning: \n",
31 | "The text.latex.unicode rcparam was deprecated in Matplotlib 2.2 and will be removed in 3.1.\n",
32 | " \"2.2\", name=key, obj_type=\"rcparam\", addendum=addendum)\n"
33 | ]
34 | }
35 | ],
36 | "source": [
37 | "%matplotlib inline\n",
38 | "\n",
39 | "\n",
40 | "import sys\n",
41 | "sys.path.append(\"..\")\n",
42 | "\n",
43 | "import os\n",
44 | "\n",
45 | "import pandas as pd\n",
46 | "import numpy as np \n",
47 | "import matplotlib.pyplot as plt \n",
48 | "\n",
49 | "from nilearn import datasets, plotting, input_data, signal # for fetching atlas\n",
50 | "\n",
51 | "from nilearn.input_data import NiftiLabelsMasker\n",
52 | "from nilearn.connectome import ConnectivityMeasure\n",
53 | "from nistats.reporting import plot_design_matrix\n",
54 | "from nistats.design_matrix import make_first_level_design_matrix\n",
55 | "from sklearn.covariance import EmpiricalCovariance\n",
56 | "\n",
57 | "import seaborn as sns\n",
58 | "sns.reset_orig()\n",
59 | "\n",
60 | "from fctools import denoise, stats"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "Step 1: Design specification\n",
68 | "--------------------------------"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": 3,
74 | "metadata": {},
75 | "outputs": [
76 | {
77 | "name": "stderr",
78 | "output_type": "stream",
79 | "text": [
80 | "/home/finc/anaconda3/lib/python3.7/site-packages/nistats/utils.py:276: UserWarning: Matrix is singular at working precision, regularizing...\n",
81 | " warn('Matrix is singular at working precision, regularizing...')\n"
82 | ]
83 | },
84 | {
85 | "data": {
86 | "text/plain": [
87 | "[]"
88 | ]
89 | },
90 | "execution_count": 3,
91 | "metadata": {},
92 | "output_type": "execute_result"
93 | },
94 | {
95 | "data": {
96 | "image/png": "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\n",
97 | "text/plain": [
98 | ""
99 | ]
100 | },
101 | "metadata": {
102 | "needs_background": "light"
103 | },
104 | "output_type": "display_data"
105 | }
106 | ],
107 | "source": [
108 | "t_r = 2\n",
109 | "n_scans = 340\n",
110 | "\n",
111 | "onsets_dir = '/home/finc/Dropbox/Projects/LearningBrain/github/LearningBrain_networks/support/onsets_dualnback.csv'\n",
112 | "events = pd.read_csv(onsets_dir)\n",
113 | "frame_times = np.arange(n_scans) * t_r\n",
114 | "\n",
115 | "# Step 1\n",
116 | "box = make_first_level_design_matrix(frame_times, events, hrf_model = None)\n",
117 | "box = box.reset_index()\n",
118 | "\n",
119 | "# Step 2\n",
120 | "box_hrf = make_first_level_design_matrix(frame_times, events, hrf_model = 'glover')\n",
121 | "box_hrf = box_hrf.reset_index()\n",
122 | "\n",
123 | "plt.plot(box_hrf['1-back'])"
124 | ]
125 | },
126 | {
127 | "cell_type": "markdown",
128 | "metadata": {},
129 | "source": [
130 | "Step 2: Loading data\n",
131 | "----------------------------------------------------\n"
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": 4,
137 | "metadata": {},
138 | "outputs": [],
139 | "source": [
140 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n",
141 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/02-correlation_matrices/'\n",
142 | "\n",
143 | "dual_power = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_power_denoised_acompcor_no_smooth.npy')\n",
144 | "dual_schaefer = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n",
145 | "\n",
146 | "rest_power = np.load(f'{top_dir}rest/LB_rest_timeseries_power_denoised_acompcor_no_smooth.npy')\n",
147 | "rest_schaefer = np.load(f'{top_dir}rest/LB_rest_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n",
148 | "\n",
149 | "dual = np.asarray([\n",
150 | " [dual_power, 'dual_power'], \n",
151 | " [dual_schaefer, 'dual_schaefer']])\n",
152 | "rest = np.asarray([\n",
153 | " [rest_power, 'rest_power'], \n",
154 | " [rest_schaefer, 'rest_chaefer']])"
155 | ]
156 | },
157 | {
158 | "cell_type": "markdown",
159 | "metadata": {},
160 | "source": [
161 | "Step 3: Calculating correlation matrices - resting-state\n",
162 | "-------------------------"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 7,
168 | "metadata": {},
169 | "outputs": [
170 | {
171 | "name": "stderr",
172 | "output_type": "stream",
173 | "text": [
174 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:359: RuntimeWarning: divide by zero encountered in true_divide\n",
175 | " diagonal = np.atleast_2d(1. / np.sqrt(np.diag(covariance)))\n",
176 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:360: RuntimeWarning: invalid value encountered in multiply\n",
177 | " correlation = covariance * diagonal * diagonal.T\n",
178 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:359: RuntimeWarning: divide by zero encountered in true_divide\n",
179 | " diagonal = np.atleast_2d(1. / np.sqrt(np.diag(covariance)))\n",
180 | "/home/finc/anaconda/lib/python3.6/site-packages/nilearn/connectome/connectivity_matrices.py:360: RuntimeWarning: invalid value encountered in multiply\n",
181 | " correlation = covariance * diagonal * diagonal.T\n"
182 | ]
183 | },
184 | {
185 | "name": "stdout",
186 | "output_type": "stream",
187 | "text": [
188 | "(46, 4, 300, 300)\n"
189 | ]
190 | }
191 | ],
192 | "source": [
193 | "from sklearn.covariance import EmpiricalCovariance\n",
194 | "\n",
195 | "for p in range(rest.shape[0]):\n",
196 | "\n",
197 | " data = rest[p,0]\n",
198 | " sub_n = len(data[:, 0, 0, 0])\n",
199 | " ses_n = len(data[0, :, 0, 0])\n",
200 | " rois_n = len(data[0, 0, 0, :])\n",
201 | "\n",
202 | " correlation_matrices = np.zeros((sub_n, \n",
203 | " ses_n, \n",
204 | " #len(cond), \n",
205 | " rois_n, rois_n))\n",
206 | "\n",
207 | " for sub in range(sub_n):\n",
208 | " for ses in range(ses_n): \n",
209 | " correlation_measure = ConnectivityMeasure(cov_estimator=EmpiricalCovariance(store_precision=True, assume_centered=False), kind = 'correlation', discard_diagonal=True)\n",
210 | "\n",
211 | " timeseries_dual = data[sub, ses, 0:180, : ] #rect_box_hrf > 0, :]\n",
212 | " #timeseries_dual = (timeseries_dual.T * rect_nnz).T\n",
213 | "\n",
214 | " fc = correlation_measure.fit_transform([timeseries_dual])[0]\n",
215 | " np.fill_diagonal(fc, 0)\n",
216 | "\n",
217 | " correlation_matrices[sub, ses, :, :] = np.arctanh(fc)\n",
218 | "\n",
219 | " print(correlation_matrices.shape)\n",
220 | " np.save(f'{out_dir}static/rest/LB_{rest[p,1]}_static_correlation_matrices.npy', correlation_matrices)\n"
221 | ]
222 | },
223 | {
224 | "cell_type": "markdown",
225 | "metadata": {},
226 | "source": [
227 | "Step 4: Calculating correlation matrices - dual n-back\n",
228 | "-------------------------"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": 8,
234 | "metadata": {},
235 | "outputs": [
236 | {
237 | "name": "stdout",
238 | "output_type": "stream",
239 | "text": [
240 | "Calculating correlations: sub 0\n",
241 | "Calculating correlations: sub 1\n",
242 | "Calculating correlations: sub 2\n",
243 | "Calculating correlations: sub 3\n",
244 | "Calculating correlations: sub 4\n",
245 | "Calculating correlations: sub 5\n",
246 | "Calculating correlations: sub 6\n",
247 | "Calculating correlations: sub 7\n",
248 | "Calculating correlations: sub 8\n",
249 | "Calculating correlations: sub 9\n",
250 | "Calculating correlations: sub 10\n",
251 | "Calculating correlations: sub 11\n",
252 | "Calculating correlations: sub 12\n",
253 | "Calculating correlations: sub 13\n",
254 | "Calculating correlations: sub 14\n",
255 | "Calculating correlations: sub 15\n",
256 | "Calculating correlations: sub 16\n",
257 | "Calculating correlations: sub 17\n",
258 | "Calculating correlations: sub 18\n",
259 | "Calculating correlations: sub 19\n",
260 | "Calculating correlations: sub 20\n",
261 | "Calculating correlations: sub 21\n",
262 | "Calculating correlations: sub 22\n",
263 | "Calculating correlations: sub 23\n",
264 | "Calculating correlations: sub 24\n",
265 | "Calculating correlations: sub 25\n",
266 | "Calculating correlations: sub 26\n",
267 | "Calculating correlations: sub 27\n",
268 | "Calculating correlations: sub 28\n",
269 | "Calculating correlations: sub 29\n",
270 | "Calculating correlations: sub 30\n",
271 | "Calculating correlations: sub 31\n",
272 | "Calculating correlations: sub 32\n",
273 | "Calculating correlations: sub 33\n",
274 | "Calculating correlations: sub 34\n",
275 | "Calculating correlations: sub 35\n",
276 | "Calculating correlations: sub 36\n",
277 | "Calculating correlations: sub 37\n",
278 | "Calculating correlations: sub 38\n",
279 | "Calculating correlations: sub 39\n",
280 | "Calculating correlations: sub 40\n",
281 | "Calculating correlations: sub 41\n",
282 | "Calculating correlations: sub 42\n",
283 | "Calculating correlations: sub 43\n",
284 | "Calculating correlations: sub 44\n",
285 | "Calculating correlations: sub 45\n",
286 | "(46, 4, 2, 300, 300)\n"
287 | ]
288 | }
289 | ],
290 | "source": [
291 | "for p in range(rest.shape[0]):\n",
292 | " data = dual[p,0]\n",
293 | " \n",
294 | " sub_n = len(data[:, 0, 0, 0])\n",
295 | " ses_n = len(data[0, :, 0, 0])\n",
296 | " cond = ['1-back', '2-back']\n",
297 | " rois_n = len(data[0, 0, 0, :])\n",
298 | " A = np.zeros((rois_n, rois_n))\n",
299 | " correlation_matrices_wei = np.zeros((sub_n, ses_n, len(cond), rois_n, rois_n))\n",
300 | "\n",
301 | "\n",
302 | " for sub in range(sub_n):\n",
303 | " print(f'Calculating correlations: sub {sub}')\n",
304 | " for ses in range(ses_n): \n",
305 | " for con in range(len(cond)):\n",
306 | " #--- zeroing negative values\n",
307 | " rect_box_hrf = np.array([0 if elem < 0 else elem for elem in box_hrf[cond[con]]])\n",
308 | " #--- concatenating nonzeros blocs\n",
309 | " rect_nnz = rect_box_hrf[np.nonzero(rect_box_hrf)]\n",
310 | " #--- filtering \n",
311 | " timeseries_dual = data[sub, ses, rect_box_hrf > 0, :]\n",
312 | " #--- calculating weighted correlation coefficient\n",
313 | " for i in range(rois_n):\n",
314 | " for j in range(i):\n",
315 | " if i == j:\n",
316 | " continue\n",
317 | " else:\n",
318 | " A[i, j] = stats.corr_wei(timeseries_dual[:, i], timeseries_dual[:, j], rect_nnz)\n",
319 | "\n",
320 | " fc = A + A.T\n",
321 | " correlation_matrices_wei[sub, ses, con, :, :] = np.arctanh(fc)\n",
322 | " print(correlation_matrices_wei.shape)\n",
323 | " np.save(f'{out_dir}static/dualnback/LB_{dual[p,1]}_static_correlation_matrices.npy', correlation_matrices_wei)"
324 | ]
325 | }
326 | ],
327 | "metadata": {
328 | "kernelspec": {
329 | "display_name": "Python 3",
330 | "language": "python",
331 | "name": "python3"
332 | },
333 | "language_info": {
334 | "codemirror_mode": {
335 | "name": "ipython",
336 | "version": 3
337 | },
338 | "file_extension": ".py",
339 | "mimetype": "text/x-python",
340 | "name": "python",
341 | "nbconvert_exporter": "python",
342 | "pygments_lexer": "ipython3",
343 | "version": "3.7.3"
344 | }
345 | },
346 | "nbformat": 4,
347 | "nbformat_minor": 2
348 | }
349 |
--------------------------------------------------------------------------------
/02-fmri_data_preparation/04-dynamic_FC_estimation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: Dynamic connectivity estimation\n",
8 | "\n",
9 | "**Last edited:** 09-11-2018\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "Step 0: Loading libraries\n",
17 | "--------------------------------"
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": 4,
23 | "metadata": {},
24 | "outputs": [
25 | {
26 | "name": "stderr",
27 | "output_type": "stream",
28 | "text": [
29 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:855: MatplotlibDeprecationWarning: \n",
30 | "examples.directory is deprecated; in the future, examples will be found relative to the 'datapath' directory.\n",
31 | " \"found relative to the 'datapath' directory.\".format(key))\n",
32 | "/home/finc/anaconda3/lib/python3.7/site-packages/matplotlib/__init__.py:846: MatplotlibDeprecationWarning: \n",
33 | "The text.latex.unicode rcparam was deprecated in Matplotlib 2.2 and will be removed in 3.1.\n",
34 | " \"2.2\", name=key, obj_type=\"rcparam\", addendum=addendum)\n"
35 | ]
36 | }
37 | ],
38 | "source": [
39 | "%matplotlib inline\n",
40 | "\n",
41 | "import sys\n",
42 | "sys.path.append(\"..\")\n",
43 | "import os\n",
44 | "\n",
45 | "import pandas as pd\n",
46 | "import numpy as np \n",
47 | "import matplotlib.pyplot as plt \n",
48 | "\n",
49 | "from nilearn import datasets, plotting, input_data, signal # for fetching atlas\n",
50 | "\n",
51 | "from nilearn.input_data import NiftiLabelsMasker\n",
52 | "from nilearn.connectome import ConnectivityMeasure\n",
53 | "from nistats.reporting import plot_design_matrix\n",
54 | "from nistats.design_matrix import make_first_level_design_matrix\n",
55 | "from sklearn.covariance import EmpiricalCovariance\n",
56 | "\n",
57 | "import seaborn as sns\n",
58 | "sns.reset_orig()\n",
59 | "\n",
60 | "from fctools import denoise, stats"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "Step 1: Loading data\n",
68 | "----------------------------------------------------\n"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": 7,
74 | "metadata": {},
75 | "outputs": [],
76 | "source": [
77 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/01-extracted_timeseries/'\n",
78 | "out_dir = '/home/finc/Dropbox/Projects/LearningBrain/data/neuroimaging/02-correlation_matrices/'\n",
79 | "\n",
80 | "dual_power = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_power_denoised_acompcor_no_smooth.npy')\n",
81 | "dual_schaefer = np.load(f'{top_dir}dualnback/LB_dualnback_timeseries_schaefer_denoised_acompcor_no_smooth.npy')\n",
82 | "\n",
83 | "dual = np.asarray([[dual_power, 'dual_power'], [dual_schaefer, 'dual_schaefer']])"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Step 2: Design specification\n",
91 | "----------------------------------------------------\n"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": 8,
97 | "metadata": {},
98 | "outputs": [
99 | {
100 | "data": {
101 | "text/plain": [
102 | "[]"
103 | ]
104 | },
105 | "execution_count": 8,
106 | "metadata": {},
107 | "output_type": "execute_result"
108 | },
109 | {
110 | "data": {
111 | "image/png": "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\n",
112 | "text/plain": [
113 | ""
114 | ]
115 | },
116 | "metadata": {
117 | "needs_background": "light"
118 | },
119 | "output_type": "display_data"
120 | }
121 | ],
122 | "source": [
123 | "t_r = 2\n",
124 | "n_scans = 340\n",
125 | "\n",
126 | "onsets_dir = '../support/onsets_dualnback.csv'\n",
127 | "events = pd.read_csv(onsets_dir)\n",
128 | "frame_times = np.arange(n_scans) * t_r\n",
129 | "\n",
130 | "events = events[(events.trial_type == '1-back') | (events.trial_type == '2-back')].reset_index()\n",
131 | "events['trial_type'] = np.arange(20)\n",
132 | "\n",
133 | "# Step 1\n",
134 | "box = make_first_level_design_matrix(frame_times, events, hrf_model = None)\n",
135 | "box = box.reset_index()\n",
136 | "\n",
137 | "# Step 2\n",
138 | "box_hrf = make_first_level_design_matrix(frame_times, events, hrf_model = 'glover')\n",
139 | "box_hrf = box_hrf.reset_index()\n",
140 | "plt.plot(box_hrf.iloc[:,6])\n",
141 | "plt.plot(box.iloc[:,6])"
142 | ]
143 | },
144 | {
145 | "cell_type": "markdown",
146 | "metadata": {},
147 | "source": [
148 | "Step 3: Weighted correlation - dynamic connectivity\n",
149 | "---------------------------"
150 | ]
151 | },
152 | {
153 | "cell_type": "code",
154 | "execution_count": 9,
155 | "metadata": {},
156 | "outputs": [
157 | {
158 | "name": "stdout",
159 | "output_type": "stream",
160 | "text": [
161 | "Calculating correlations: sub 0\n"
162 | ]
163 | },
164 | {
165 | "ename": "KeyboardInterrupt",
166 | "evalue": "",
167 | "output_type": "error",
168 | "traceback": [
169 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
170 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
171 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[0;32mcontinue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m \u001b[0mA\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstats\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeseries_dual\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeseries_dual\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrect_nnz\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 31\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0mfc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mA\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mA\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mT\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
172 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/fctools/stats.py\u001b[0m in \u001b[0;36mcorr_wei\u001b[0;34m(x, y, w)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;34m\"\"\"Weighted Correlation\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msqrt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mbootstrap_replicate_1d\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
173 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/fctools/stats.py\u001b[0m in \u001b[0;36mcov_wei\u001b[0;34m(x, y, w)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcov_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\"\"\"Weighted Covariance\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mw\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mm_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mm_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcorr_wei\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
174 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
175 | ]
176 | }
177 | ],
178 | "source": [
179 | "for p in range(1,2): #range(rest.shape[0]):\n",
180 | " data = dual[p,0]\n",
181 | "\n",
182 | " n_sub = len(data[:, 0, 0, 0])\n",
183 | " n_ses = len(data[0, :, 0, 0])\n",
184 | " cond = np.arange(0,20)\n",
185 | " n_roi = len(data[0, 0, 0, :])\n",
186 | " A = np.zeros((n_roi, n_roi))\n",
187 | " correlation_matrices_dyn_wei = np.zeros((n_sub, n_ses, len(cond), n_roi, n_roi))\n",
188 | "\n",
189 | "\n",
190 | " for sub in range(n_sub):\n",
191 | " print(f'Calculating correlations: sub {sub}')\n",
192 | " for ses in range(n_ses): \n",
193 | " #correlation_measure = ConnectivityMeasure(cov_estimator=EmpiricalCovariance(store_precision=True, assume_centered=False), kind = 'correlation', discard_diagonal=True)\n",
194 | "\n",
195 | " for con in range(len(cond)):\n",
196 | " # Zeroing negative values\n",
197 | " rect_box_hrf = np.array([0 if elem < 0 else elem for elem in box_hrf[cond[con]]])\n",
198 | " # Concatenating nonzeros blocs\n",
199 | " rect_nnz = rect_box_hrf[np.nonzero(rect_box_hrf)]\n",
200 | " # Filtering \n",
201 | " timeseries_dual = data[sub, ses, rect_box_hrf > 0, :]\n",
202 | " # Calculating weighted correlation coefficient\n",
203 | " for i in range(n_roi):\n",
204 | " for j in range(i):\n",
205 | " if i == j:\n",
206 | " continue\n",
207 | " else:\n",
208 | " A[i, j] = stats.corr_wei(timeseries_dual[:, i], timeseries_dual[:, j], rect_nnz)\n",
209 | "\n",
210 | " fc = A + A.T\n",
211 | " correlation_matrices_dyn_wei[sub, ses, con, :, :] = np.arctanh(fc)\n",
212 | "\n",
213 | " print(correlation_matrices_dyn_wei.shape)\n",
214 | "\n",
215 | " np.save(f'{out_dir}dynamic/LB_{dual[p,1]}_dynamic_correlation_matrices.npy', correlation_matrices_dyn_wei)\n",
216 | " sio.savemat(f'{out_dir}dynamic/LB_{dual[p,1]}_dynamic_correlation_matrices.mat', {'correlation_matrices_dyn_wei': correlation_matrices_dyn_wei})\n",
217 | " "
218 | ]
219 | }
220 | ],
221 | "metadata": {
222 | "kernelspec": {
223 | "display_name": "Python 3",
224 | "language": "python",
225 | "name": "python3"
226 | },
227 | "language_info": {
228 | "codemirror_mode": {
229 | "name": "ipython",
230 | "version": 3
231 | },
232 | "file_extension": ".py",
233 | "mimetype": "text/x-python",
234 | "name": "python",
235 | "nbconvert_exporter": "python",
236 | "pygments_lexer": "ipython3",
237 | "version": "3.7.3"
238 | }
239 | },
240 | "nbformat": 4,
241 | "nbformat_minor": 2
242 | }
243 |
--------------------------------------------------------------------------------
/03-static_FC_analyses/01-static_modularity_calculation.m:
--------------------------------------------------------------------------------
1 | %----------------------------------------------------
2 | % Working memory training: Static normalized modularity calculation
3 |
4 | % Karolina Finc | Centre for Modern Interdisciplinary Technologies, Nicolaus Copernicus University in Toruń, Poland
5 | % Last edited: 09-01-2019
6 | %----------------------------------------------------
7 |
8 | % Mere the input is 5D matrix where:
9 | % 1st dim --> subject
10 | % 2nd dim --> session
11 | % 3rd dim --> condition
12 | % 4th and 5th dim --> correlation matrix
13 |
14 | %% Loading data
15 |
16 | M = load('WM_all_static_power_correlation_matrices.mat');
17 |
18 | M = M.all_conditions_new_power;
19 | M = squeeze(M);
20 |
21 | %% Params
22 | n_sub = size(M,1);
23 | n_ses = size(M,2);
24 | n_con = size(M,3);
25 | n_rep = 100;
26 | n_null = 100;
27 | n_rew = 1;
28 |
29 | q = zeros(n_sub, n_ses, n_con);
30 | q_null_mean = zeros(n_sub, n_ses, n_con);
31 |
32 | %% Static modularity calculation
33 | for sub = 1: n_sub
34 | sub
35 | for ses = 1: n_ses
36 | for con = 1: n_con
37 | Qb = 0;
38 | for rep = 1: n_rep
39 | A = squeeze(M(sub,ses,con,:,:)).* squeeze(M(sub, ses, con, :, :) > 0);
40 | [~, Qt] = community_louvain(A, 1, []);
41 | if Qt > Qb
42 | Qb = Qt;
43 | end
44 | q(sub, ses, con) = Qb;
45 | end
46 | end
47 | end
48 |
49 | end
50 | save('mean_power_static_modularity.mat', 'q');
51 |
52 | %% Randomized modularity calculation
53 | for sub = 1: n_sub
54 | q_null = zeros(1, n_null);
55 |
56 | sub
57 | for ses = 1: n_ses
58 | for con = 1: n_con
59 | A = squeeze(M(sub,ses,con,:,:)).* squeeze(M(sub, ses, con, :, :) > 0);
60 | if sum(isnan(A(:))) > 0
61 | q_null = 0;
62 | else
63 | for null = 1 : n_null
64 | B = randmio_und(A, n_rew);
65 | Qb = 0;
66 | for rep = 1: n_rep
67 | [~, Qt] = community_louvain(B, 1, []);
68 | if Qt > Qb
69 | Qb = Qt;
70 | end
71 | end
72 | q_null(1, null) = Qb;
73 | end
74 | end
75 | q_null_mean(sub, ses, con) = mean(q_null);
76 |
77 | end
78 | end
79 | end
80 |
81 | %% Normalized modularity calculation
82 | q_norm = q_mean ./ q_null_mean;
83 | save('mean_power_normalized_modularity.mat', 'q_norm');
--------------------------------------------------------------------------------
/03-static_FC_analyses/02-tidying_normalized_modularity.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: Preparation of normalized modularity\n",
8 | "\n",
9 | "Turning MATLAB array into tidy .csv table for further statistical analyses.\n",
10 | "\n",
11 | "**Last edited:** 06-01-2018"
12 | ]
13 | },
14 | {
15 | "cell_type": "markdown",
16 | "metadata": {},
17 | "source": [
18 | "Step 0: Loading libraries\n",
19 | "-----------------------"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 4,
25 | "metadata": {},
26 | "outputs": [],
27 | "source": [
28 | "import numpy as np\n",
29 | "import pandas as pd"
30 | ]
31 | },
32 | {
33 | "cell_type": "markdown",
34 | "metadata": {},
35 | "source": [
36 | "Step 1: Preparing data\n",
37 | "-----------------------"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": 6,
43 | "metadata": {},
44 | "outputs": [],
45 | "source": [
46 | "# Selecting subjects which finished the study\n",
47 | "groups = pd.read_csv('../data/behavioral/group_assignment.csv')\n",
48 | "\n",
49 | "trained = (groups.group == 'Experimental') | (groups.group == 'Control')\n",
50 | "trained_subs = groups[trained].reset_index()\n",
51 | "subs = trained_subs['sub'].values\n",
52 | "\n",
53 | "# Creating vectors to filter by group\n",
54 | "experimental = (trained_subs == 'Experimental')\n",
55 | "control = (trained_subs == 'Control')\n",
56 | "exp_vector = experimental['group'].values\n",
57 | "con_vector = control['group'].values\n",
58 | "\n",
59 | "# Loading normalized modularity values\n",
60 | "mat = scipy.io.loadmat('mean_power_normalized_modularity.mat')\n",
61 | "Q = mat['q_norm']"
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "Step 2: Creating tidy dataframe\n",
69 | "-----------------------"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 9,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "sess = ['Naive', 'Early', 'Middle', 'Late']\n",
79 | "cond = ['Rest', '1-back', '2-back']\n",
80 | "g = trained_subs['group'].values\n",
81 | "\n",
82 | "Q_results = pd.DataFrame()#pd.DataFrame(columns=['sub', 'group', 'ses', 'cond', 'Q'])\n",
83 | "for i, sub in enumerate(subs):\n",
84 | " for j, ses in enumerate(sess):\n",
85 | " for k, con in enumerate(cond):\n",
86 | " val = Q[i, j, k]\n",
87 | " result = pd.DataFrame({'Subject': sub, \n",
88 | " 'Group': trained_subs['group'].values[i], \n",
89 | " 'Session': ses, \n",
90 | " 'Condition': con, \n",
91 | " 'Q_norm': val},\n",
92 | " index=[0])\n",
93 | " Q_results = pd.concat([Q_results, result], axis = 0)\n",
94 | "\n",
95 | "Q_results.to_csv('../data/neuroimaging/03-modularity/static/Q_normalized_power_tidy.csv', index=False)\n",
96 | "Q_results"
97 | ]
98 | }
99 | ],
100 | "metadata": {
101 | "kernelspec": {
102 | "display_name": "Python 3",
103 | "language": "python",
104 | "name": "python3"
105 | },
106 | "language_info": {
107 | "codemirror_mode": {
108 | "name": "ipython",
109 | "version": 3
110 | },
111 | "file_extension": ".py",
112 | "mimetype": "text/x-python",
113 | "name": "python",
114 | "nbconvert_exporter": "python",
115 | "pygments_lexer": "ipython3",
116 | "version": "3.7.3"
117 | }
118 | },
119 | "nbformat": 4,
120 | "nbformat_minor": 2
121 | }
122 |
--------------------------------------------------------------------------------
/03-static_FC_analyses/load_data.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 |
4 | ex_dual_mot = ['sub-13', 'sub-21', 'sub-23', 'sub-50'] # Higly motion subjects in one of four sessions
5 | ex_rest_mot = ['sub-21', 'sub-46', 'sub-47'] # Higly motion subjects in one of four sessions / missing data(20-44)
6 | ex_rest_mis = ['sub-20', 'sub-44'] # Missing data in resting (2nd session)
7 | ex_firs_mot = ['sub-21'] # Subject with highly motion on first session
8 |
9 | # path_fc_pow = 'data/matrices/LB_static_all_conditions_power.npy'
10 | path_fc_pow = 'data/matrices/LB_static_all_conditions_power.npy'
11 | path_fc_sch = 'data/matrices/LB_static_all_conditions_schaefer.npy'
12 | path_ma_pow = 'data/support/Power_modules.txt'
13 | path_ma_sch = 'data/support/Schaefer2018_300Parcels_7Networks_order.csv'
14 | path_bh_tra = 'data/behavioral/LB_training_mean_tidy.csv'
15 | path_bh_mri = 'data/behavioral/LB_fmri_behaviour_mean_tidy.csv'
16 | path_gr_ass = 'data/behavioral/LB_group_assignment.csv'
17 |
18 | # Functional connectivity
19 | print('=== Imaging data ===')
20 | mat_pow = np.load(path_fc_pow)
21 | mat_sch = np.load(path_fc_sch)
22 | print('mat_pow is {} having shape {}'.format(type(mat_pow), mat_pow.shape))
23 | print('mat_sch is {} having shape {}'.format(type(mat_sch), mat_sch.shape))
24 | print('\n')
25 |
26 | # A priori module assignment
27 | with open(path_ma_pow, 'r') as f:
28 | ma_pow = f.readlines()
29 | ma_pow = [ma.rstrip('\n') for ma in ma_pow]
30 | ma_sch = pd.read_csv(path_ma_sch, usecols=[6])
31 |
32 | # Behavioral
33 | print('=== Behavioral data ===')
34 | beh_tra = pd.read_csv(path_bh_tra)
35 | beh_mri = pd.read_csv(path_bh_mri)
36 | grp_ass = pd.read_csv(path_gr_ass)
37 | print(beh_tra.head(3))
38 | print('\nbeh_tra shape is {}\n'.format(beh_tra.shape))
39 | print(beh_mri.head(3))
40 | print('\nbeh_mri shape is {}\n'.format(beh_mri.shape))
41 | print(grp_ass.head(3))
42 | print('\ngrp_ass shape is {}\n'.format(grp_ass.shape))
43 |
44 | # Exclusion
45 | print('=== Excluded subjects ===')
46 | print('Excluded due to motion in first session {}'.format(ex_firs_mot))
47 | print('Excluded due to motion in dual {}'.format(ex_dual_mot))
48 | print('Excluded due to motion in rest {}'.format(ex_rest_mot))
49 | print('Excluded due to missing data in rest {}'.format(ex_rest_mis))
50 | ex_rest = ex_rest_mis + ex_rest_mot
51 |
--------------------------------------------------------------------------------
/04-dynamic_FC_analyses/01-multilayer_modularity_calculation.m:
--------------------------------------------------------------------------------
1 | %----------------------------------------------------
2 | % Multilayer community detection algoritm
3 |
4 | % Karolina Finc | Centre for Modern Interdisciplinary Technologies, Nicolaus Copernicus University in Toruń, Poland
5 | % Last edited: 12-09-2018
6 | %----------------------------------------------------
7 |
8 | % Mere the input is 5D matrix where:
9 | % 1st dim --> subject
10 | % 2nd dim --> session
11 | % 3rd dim --> time windows
12 | % 4th and 5th dim --> correlation matrix
13 |
14 | clc; clear;
15 |
16 | %% Loading data
17 | large = load('LB_dualnback_power_dynamic_correlation_matrices.mat');
18 | M = squeeze(large.correlation_matrices_dyn_wei);
19 |
20 | n_sub = size(M,1);
21 | n_ses = size(M,2);
22 | n_win = size(M,3);
23 | n_roi = size(M,4);
24 |
25 |
26 | %% Parameters
27 | gamma = 1;
28 | omega = 1;
29 | n_rep = 100;
30 |
31 | %% Empty matrices to store data
32 | modularity_mean = zeros(n_sub, n_rep, n_ses); % Mean modularity
33 | modules = zeros(n_sub, n_ses, n_rep, n_roi, n_win); % Module assigment labels
34 |
35 | %%
36 | for sub = 1 : n_sub
37 | for ses = 1 : n_ses
38 | %--- define objects ---------------------------------------------------
39 | A = cell(1, n_win);
40 | B = spalloc(n_roi * n_win, n_roi * n_win,(n_roi + n_win) * n_roi* n_win);
41 | twomu = 0;
42 |
43 | %--- null model -------------------------------------------------------
44 | for win = 1 : n_win
45 | %--- copy network with positive weights thresholding --------------
46 | A{win} = squeeze(M(sub, ses, win, :, :) .* (M(sub, ses, win, :, :) > 0));
47 | k = sum(A{win}); % node degree
48 | twom = sum(k); % mean network degree
49 | twomu = twomu + twom; % increment
50 | indx = [1:n_roi] + (win-1)*n_roi; % find indices
51 | B(indx,indx) = A{win} - gamma * [k'*k]/twom; % fill B matrix
52 | end
53 | twomu = twomu + 2*omega* n_roi*(n_win-1);
54 |
55 | B = B + omega/2*spdiags(ones(n_roi*n_win,2),[-n_roi, n_roi], n_roi*n_win, n_roi*n_win);
56 | B = B + omega*spdiags(ones(n_roi*n_win,2),[-2*n_roi, 2*n_roi], n_roi*n_win, n_roi*n_win);
57 | %B = B + omega * spdiags(ones(n_roi * n_win,2),[-n_roi, n_roi], n_roi*n_win, n_roi*n_win);
58 |
59 | %--- calculate multilayer modules -------------------------------------
60 | %Qb = 0;
61 | for rep = 1 : n_rep
62 | clc;
63 | fprintf('Subject = %i\n',sub);
64 | [S,Q] = genlouvain(B);
65 | Q = Q / twomu;
66 | S = reshape(S, n_roi, n_win);
67 |
68 | modularity_mean(sub, rep, ses) = Q;
69 | modules(sub, ses, rep, :, :) = S;
70 | end
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/04-dynamic_FC_analyses/02-module_allegiance_matrix_calculation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **Working memory training**: Module allegiance matrix calculation\n",
8 | "\n",
9 | "**Last edited:** 04-10-2018\n"
10 | ]
11 | },
12 | {
13 | "cell_type": "markdown",
14 | "metadata": {},
15 | "source": [
16 | "Step 0: Loading libraries\n",
17 | "--------------------------------"
18 | ]
19 | },
20 | {
21 | "cell_type": "code",
22 | "execution_count": 2,
23 | "metadata": {},
24 | "outputs": [],
25 | "source": [
26 | "import sys\n",
27 | "sys.path.append(\"..\")\n",
28 | "import os\n",
29 | "\n",
30 | "%matplotlib inline\n",
31 | "\n",
32 | "import scipy.io as sio\n",
33 | "import numpy as np\n",
34 | "from nilearn import plotting \n",
35 | "import pandas as pd\n",
36 | "import seaborn as sns\n",
37 | "import matplotlib.pyplot as plt\n",
38 | "\n",
39 | "from scipy import stats\n",
40 | "from fctools import networks, figures\n",
41 | "\n",
42 | "#---- matplotlib settings\n",
43 | "import matplotlib.pyplot as plt\n",
44 | "plt.style.use('seaborn-white')\n",
45 | "plt.rcParams['font.family'] = 'Helvetica'"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "Step 1: Getting modules names and color pallete\n",
53 | "----------------------------------------"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": 3,
59 | "metadata": {},
60 | "outputs": [
61 | {
62 | "data": {
63 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuMAAABECAYAAAAr+zvbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAAyxJREFUeJzt2z2LXHUYxuFnMoPLGkPejGRSWGZIaWGjbik2gqDfQbCxlxRCilR+Agst/BpCik2XwsbC6YSAE8iLLrLKmt0Zi2hYlZ3umTueva7y/Ju7OvM7hzOj1WpVAADA5p1JDwAAgNNKjAMAQIgYBwCAEDEOAAAhk5MOZrPZVlW9WVWLqjra2CIAABiWcVVNq+refD4/OH5wYozXsxDf7VwFAACnyE5V3T1+YV2ML6qqbr37WV0+e6lzVMz3b7+entDq/kd30hPaHOx+k57Q6pP399MTWm19ez49odV3P3yantDq81u30xNavfXFV+kJra5/sJOe0ObDm+kFvW5c/Dg9odV7X7+RntDm6XKvfjz4suqvvj5uXYwfVVVdPnupXnvlStO0rAuvTtMTWj05HG7wjK8O++8O02V6Qa/t6Tg9odX9h8N8gfG30WiUntBq+8rV9IRW5w8P0xPaXDuXXtDr8MLL6QmtXjpzMT1hE/7z6fewiwYAAF5gYhwAAELEOAAAhIhxAAAIEeMAABAixgEAIESMAwBAiBgHAIAQMQ4AACFiHAAAQsQ4AACEiHEAAAgR4wAAECLGAQAgRIwDAECIGAcAgBAxDgAAIWIcAABCxDgAAISIcQAACBHjAAAQIsYBACBEjAMAQIgYBwCAEDEOAAAhYhwAAELEOAAAhIhxAAAIEeMAABAixgEAIESMAwBAiBgHAIAQMQ4AACFiHAAAQsQ4AACEiHEAAAgR4wAAECLGAQAgRIwDAECIGAcAgBAxDgAAIWIcAABCxDgAAISIcQAACBHjAAAQIsYBACBEjAMAQIgYBwCAEDEOAAAhYhwAAELEOAAAhEzWnI2rqh7vP9nQlM375dF2ekKr/cleekKbgwfL9IRWi4E/Jm8tjtITWj16PNz7ZlXVarVKT2j1+8MH6Qmt9ibrfvr/3376Nb2g12TyW3pCqz+WP6cntHm6fN5k43+fjU66qc5ms3eqardvFgAAnCo78/n87vEL6x6P71XVTlUtqmrYr7EAAKDPuKqm9ayv/+HEN+MAAECvgX+ZCgAALy4xDgAAIWIcAABCxDgAAIT8CWitXhDKYeylAAAAAElFTkSuQmCC\n",
64 | "text/plain": [
65 | ""
66 | ]
67 | },
68 | "metadata": {
69 | "needs_background": "light"
70 | },
71 | "output_type": "display_data"
72 | }
73 | ],
74 | "source": [
75 | "labels = pd.read_csv(f'../support/modules.txt', sep = \" \", header = None)\n",
76 | "\n",
77 | "power_colors_new = {'AU':'#d182c6', \n",
78 | " 'CER':'#9fc5e8', \n",
79 | " 'CO':'#7d009d', \n",
80 | " 'DA':'#75df33', \n",
81 | " 'DM':'#ed1126', \n",
82 | " 'FP':'#f6e838', \n",
83 | " 'MEM':'#bebab5', \n",
84 | " 'SAL':'#2a2a2a', \n",
85 | " 'SOM':'#6ccadf', \n",
86 | " 'SUB':'#980000', \n",
87 | " 'UNC':'#f58c00', \n",
88 | " 'VA':'#00a074', \n",
89 | " 'VIS':'#5131ac',}\n",
90 | "\n",
91 | "modules = sorted(labels[0].values)\n",
92 | "network_pal = (sns.color_palette(power_colors_new.values()))\n",
93 | "sns.palplot(sns.color_palette(power_colors_new.values()))\n",
94 | "\n",
95 | "network_lut = dict(zip(map(str, np.unique(modules)), network_pal))\n",
96 | "\n",
97 | "network_colors = pd.Series(modules).map(network_lut)\n",
98 | "network_colors = np.asarray(network_colors)\n",
99 | "\n",
100 | "n_roi = len(labels)\n",
101 | "n_net = len(np.unique(modules))"
102 | ]
103 | },
104 | {
105 | "cell_type": "markdown",
106 | "metadata": {},
107 | "source": [
108 | "Step 2: Loading module assignment matrices\n",
109 | "-------------------------------------------------------------------------------"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": 5,
115 | "metadata": {},
116 | "outputs": [],
117 | "source": [
118 | "top_dir = '/home/finc/Dropbox/Projects/LearningBrain/'\n",
119 | "mat = sio.loadmat(f'{top_dir}data/neuroimaging/03-modularity/dynamic/02-module_assignment/power_modules.mat')\n",
120 | "\n",
121 | "idx = np.argsort(labels[0])\n",
122 | "\n",
123 | "module_assignment = mat['modules']\n",
124 | "module_assignment = module_assignment[:, :, :, idx, :]"
125 | ]
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "metadata": {},
130 | "source": [
131 | "Step 3: calculating allegiance matrices\n",
132 | "-------------------------------------------"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": 8,
138 | "metadata": {},
139 | "outputs": [
140 | {
141 | "name": "stdout",
142 | "output_type": "stream",
143 | "text": [
144 | "Subject 1\n"
145 | ]
146 | },
147 | {
148 | "ename": "KeyboardInterrupt",
149 | "evalue": "",
150 | "output_type": "error",
151 | "traceback": [
152 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
153 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
154 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'Subject {i+1}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_ses\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0mP\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnetworks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mallegiance_matrix_opti\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_assignment\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msave\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/allegiance_matrix_power_opt_mean.npy'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mP\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
155 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/04-dynamic_FC_analyses/fctools/networks.py\u001b[0m in \u001b[0;36mallegiance_matrix_opti\u001b[0;34m(M)\u001b[0m\n",
156 | "\u001b[0;32m~/Dropbox/Projects/LearningBrain/github/WM_training_modularity/04-dynamic_FC_analyses/fctools/networks.py\u001b[0m in \u001b[0;36mallegiance_matrix\u001b[0;34m(M)\u001b[0m\n",
157 | "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py\u001b[0m in \u001b[0;36msum\u001b[0;34m(a, axis, dtype, out, keepdims, initial)\u001b[0m\n\u001b[1;32m 2074\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2075\u001b[0m return _wrapreduction(a, np.add, 'sum', axis, dtype, out, keepdims=keepdims,\n\u001b[0;32m-> 2076\u001b[0;31m initial=initial)\n\u001b[0m\u001b[1;32m 2077\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2078\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
158 | "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py\u001b[0m in \u001b[0;36m_wrapreduction\u001b[0;34m(obj, ufunc, method, axis, dtype, out, **kwargs)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mreduction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mpasskwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mufunc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreduce\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mpasskwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 87\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
159 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
160 | ]
161 | }
162 | ],
163 | "source": [
164 | "# Calculating allegiance matrices (mean over optimizations)\n",
165 | "n_sub = module_assignment.shape[0]\n",
166 | "n_ses = module_assignment.shape[1]\n",
167 | "n_opt = module_assignment.shape[2]\n",
168 | "n_nod = module_assignment.shape[3]\n",
169 | "\n",
170 | "P = np.zeros((n_sub, n_ses, n_nod, n_nod))\n",
171 | "\n",
172 | "for i in range(n_sub):\n",
173 | " print(f'Subject {i+1}')\n",
174 | " for j in range(n_ses):\n",
175 | " P[i,j,:,:] = networks.allegiance_matrix_opti(module_assignment[i,j,:,:,:])\n",
176 | "\n",
177 | "np.save(f'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/allegiance_matrix_power_opt_mean.npy', P)"
178 | ]
179 | },
180 | {
181 | "cell_type": "code",
182 | "execution_count": 14,
183 | "metadata": {},
184 | "outputs": [
185 | {
186 | "name": "stdout",
187 | "output_type": "stream",
188 | "text": [
189 | "Subject 1\n",
190 | "Subject 2\n",
191 | "Subject 3\n",
192 | "Subject 4\n",
193 | "Subject 5\n",
194 | "Subject 6\n",
195 | "Subject 7\n",
196 | "Subject 8\n",
197 | "Subject 9\n",
198 | "Subject 10\n",
199 | "Subject 11\n",
200 | "Subject 12\n",
201 | "Subject 13\n",
202 | "Subject 14\n",
203 | "Subject 15\n",
204 | "Subject 16\n",
205 | "Subject 17\n",
206 | "Subject 18\n",
207 | "Subject 19\n",
208 | "Subject 20\n",
209 | "Subject 21\n",
210 | "Subject 22\n",
211 | "Subject 23\n",
212 | "Subject 24\n",
213 | "Subject 25\n",
214 | "Subject 26\n",
215 | "Subject 27\n",
216 | "Subject 28\n",
217 | "Subject 29\n",
218 | "Subject 30\n",
219 | "Subject 31\n",
220 | "Subject 32\n",
221 | "Subject 33\n",
222 | "Subject 34\n",
223 | "Subject 35\n",
224 | "Subject 36\n",
225 | "Subject 37\n",
226 | "Subject 38\n",
227 | "Subject 39\n",
228 | "Subject 40\n",
229 | "Subject 41\n",
230 | "Subject 42\n",
231 | "Subject 43\n",
232 | "Subject 44\n",
233 | "Subject 45\n",
234 | "Subject 46\n"
235 | ]
236 | }
237 | ],
238 | "source": [
239 | "# Calculating allegiance matrices for each window (mean over optimizations)\n",
240 | "\n",
241 | "n_sub = len(module_assignment.shape[0])\n",
242 | "n_ses = len(module_assignment.shape[1])\n",
243 | "n_nod = len(module_assignment.shape[3])\n",
244 | "n_win = len(module_assignment.shape[4])\n",
245 | "\n",
246 | "W = np.zeros((n_sub, n_ses, n_win, n_nod, n_nod))\n",
247 | "\n",
248 | "for i in range(n_sub):\n",
249 | " print(f'Subject {i+1}')\n",
250 | " W[i,j,:,:,:] = networks.all_window_allegiance_mean(module_assignment[i, j, :, :, :])\n",
251 | "\n",
252 | "np.save(f'{top_dir}data/neuroimaging/03-modularity/dynamic/03-allegiance_matrices/window_allegiance_matrix_power_dualnback.npy', W)"
253 | ]
254 | }
255 | ],
256 | "metadata": {
257 | "kernelspec": {
258 | "display_name": "Python 3",
259 | "language": "python",
260 | "name": "python3"
261 | },
262 | "language_info": {
263 | "codemirror_mode": {
264 | "name": "ipython",
265 | "version": 3
266 | },
267 | "file_extension": ".py",
268 | "mimetype": "text/x-python",
269 | "name": "python",
270 | "nbconvert_exporter": "python",
271 | "pygments_lexer": "ipython3",
272 | "version": "3.7.3"
273 | }
274 | },
275 | "nbformat": 4,
276 | "nbformat_minor": 2
277 | }
278 |
--------------------------------------------------------------------------------
/04-dynamic_FC_analyses/08-multilayer_modularity_calculation_signed.m:
--------------------------------------------------------------------------------
1 | clc; clear;
2 |
3 | %% Loading data
4 | large = load('LB_dualnback_power_dynamic_correlation_matrices.mat');
5 | M = squeeze(large.correlation_matrices_dyn_wei);
6 |
7 | n_sub = size(M,1);
8 | n_ses = size(M,2);
9 | T = size(M,3);
10 | N = size(M,4);
11 |
12 | %% Parameters
13 | gplus = 1;
14 | gminus = 1;
15 | omega = 1;
16 | n_rep = 100;
17 |
18 | %% Empty matrices to store results
19 | modularity_mean = zeros(n_sub, n_rep, n_ses); % Mean modularity
20 | modules = zeros(n_sub, n_ses, n_rep, N, T); % Module assigment labels
21 |
22 | for sub = 1 : 1:n_sub
23 | for ses = 1 :1: n_ses
24 |
25 | %--- define objects ---------------------------------------------------
26 | A = cell(1, T);
27 | B=spalloc(N*T,N*T,N*N*T+2*N*T);
28 | twom=0;
29 |
30 | % Signed version by Xiaosong He, 5/23/2019
31 | for s=1:T
32 | A{s} = squeeze(M(sub, ses, s, :, :));
33 | Aplus=A{s}; Aplus(A{s}<0)=0;
34 | Aminus=-A{s}; Aminus(A{s}>0)=0;
35 | kplus=sum(Aplus)';
36 | kminus=sum(Aminus)';
37 | mm=sum(kplus)+sum(kminus);
38 | twom=twom+mm;
39 | indx=[1:N]+(s-1)*N;
40 | if sum(kminus) == 0 % necessary for case no negative edges in matrix
41 | Gm=0;
42 | else
43 | Gm=gminus*kminus*kminus'/sum(kminus);
44 | end
45 | B(indx,indx)=A{s}-(gplus*kplus*kplus'/sum(kplus)-Gm);
46 | end
47 |
48 |
49 | B = B + omega/2*spdiags(ones(N*T,2),[-N, N], N*T, N*T);
50 | B = B + omega*spdiags(ones(N*T,2),[-2*N, 2*N], N*T, N*T);
51 |
52 | twom=twom+(N*T*(T-1)*omega);
53 |
54 | for rep = 1 : n_rep
55 | clc;
56 | fprintf('Subject = %i\n',sub);
57 | [S,Q] = genlouvain(B);
58 | Q = Q / twom;
59 | S = reshape(S, N, T);
60 |
61 | modularity_mean(sub, rep, ses) = Q;
62 | modules(sub, ses, rep, :, :) = S;
63 | end
64 |
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/LICENCE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 Karolina Finc
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dynamic reconfiguration of functional brain networks during working memory training
2 |
3 | Repository containing a code for network analyses of longitudinal working memory training data with multi-session fMRI scanning.
4 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: LearningBrain_networks
2 | dependencies:
3 | - numpy = 1.13.3
4 | - pandas = 0.20.3
5 | - nilearn = 0.4.2
6 | - scipy = 0.19.1
7 | - matplotlib = 2.1.0
8 | - sklearn = 0.19.1
9 |
10 |
--------------------------------------------------------------------------------
/fctools/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = "0.1"
2 |
--------------------------------------------------------------------------------
/fctools/denoise.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | """
5 | Created on Wed Jul 19 2018
6 | Last edit: Sat Sep 01 2018
7 | @author: kfinc
8 |
9 | """
10 |
11 | import pandas as pd
12 | import numpy as np
13 | from sklearn import preprocessing
14 | from nistats.design_matrix import make_first_level_design_matrix
15 |
16 |
17 | def motion_24_friston(dataframe):
18 |
19 | """Simple function that calculates 24 motion parameters from pandas dataframe.
20 |
21 | Parameters
22 | ----------
23 | dataframe: pandas dataframe including 6 movement parameters with headers
24 |
25 | Returns
26 | -------
27 | motion_24_friston: pandas dataframe including 24 motion parameters
28 |
29 | - the first 6 are the motion parameters
30 | - the next 6 are the temporal difference of motion parameters ('_td' suffix)
31 | - the next 12 are the square of the motion parameters and the differenced values ('_sqrt' suffix)
32 |
33 | """
34 |
35 | motion_24_friston = dataframe
36 |
37 | for col in dataframe.columns:
38 | temp_diff = np.roll(dataframe[col], 1, axis = 0)
39 | temp_diff[0] = 0
40 | temp_diff = pd.DataFrame(temp_diff)
41 | motion_24_friston[col + '_td'] = temp_diff
42 |
43 | for col in motion_24_friston.columns:
44 | quad = motion_24_friston[col] ** 2
45 | motion_24_friston[col + '_quad'] = quad
46 |
47 | return motion_24_friston
48 |
49 |
50 | def scrubbing(fd, thr = 0.5, before = True, after = True):
51 |
52 | """Function that calculates motion outliers (frames with motion above threshold_.
53 |
54 | Parameters
55 | ----------
56 | fd: pandas dataframe including frame-wise displacement (FD)
57 | thr: threshold (default: 0.5)
58 | before: marks frames before outlier datapoint (default: True)
59 | after: marks frames after outlier datapoint (default: True)
60 |
61 | Returns
62 | -------
63 | scrubbing: pandas dataframe including all ourliers datapoints
64 |
65 | """
66 |
67 | scrubbing = pd.DataFrame()
68 | fd.loc[0] = 0
69 | fd = fd.astype(float)
70 |
71 | scrub1 = fd > thr
72 | scrub1 = scrub1.astype(int)
73 | scrubbing['scrubbing'] = scrub1
74 |
75 | if before == True:
76 | scrub2 = np.roll(scrubbing['scrubbing'], -1, axis = 0)
77 | scrub2[0] = 0
78 | scrubbing['scrubbing_bef'] = scrub2
79 |
80 | if after == True:
81 | scrub3 = np.roll(scrubbing['scrubbing'], 1, axis = 0)
82 | scrub3[0] = 0
83 | scrubbing['scrubbing_aft'] = scrub3
84 |
85 | return scrubbing
86 |
87 |
88 |
89 | def standardize(dataframe):
90 | """
91 | Normalizes each column and returns values set to unit variance.
92 |
93 | Parameters
94 | ----------
95 | dataframe: pandas dataframe including columns of interest
96 |
97 | Returns
98 | -------
99 | dataframe_stand: pandas dataframe with standarized values
100 |
101 |
102 | """
103 |
104 | dataframe_stand = pd.DataFrame()
105 | val = dataframe.values
106 | standardize = preprocessing.StandardScaler()
107 | val_scaled = standardize.fit_transform(val)
108 | dataframe_stand = pd.DataFrame(val_scaled, columns = dataframe.columns)
109 |
110 | return dataframe_stand
111 |
112 |
113 | def motion_temp_diff(dataframe):
114 |
115 | """Simple function that calculates 12 motion parameters from pandas dataframe.
116 |
117 | Parameters
118 | ----------
119 | dataframe: pandas dataframe including 6 movement parameters with headers
120 |
121 | Returns
122 | -------
123 | motion_temp_diff: pandas dataframe including 24 motion parameters
124 |
125 | - the first 6 are the motion parameters
126 | - the next 6 are the temporal difference of motion parameters ('_td' suffix)
127 |
128 | """
129 |
130 | motion_temp_diff = dataframe
131 |
132 | for col in dataframe.columns:
133 | temp_diff = np.roll(dataframe[col], 1, axis = 0)
134 | temp_diff[0] = 0
135 | temp_diff = pd.DataFrame(temp_diff)
136 | motion_temp_diff[col + '_td'] = temp_diff
137 |
138 | return motion_temp_diff
139 |
140 |
141 | def temp_deriv(dataframe, quadratic = False):
142 | """Simple function that calculates temporal derivatives for each column of pandas dataframe.
143 |
144 | Parameters
145 | ----------
146 | dataframe: pandas dataframe with variable to calculate temporal derivarives
147 |
148 | Returns
149 | -------
150 | temp_deriv: pandas dataframe including original columns and their temporal derivatives ('_td') and (optional)
151 | their quadratic terms
152 |
153 | """
154 |
155 | temp_deriv = dataframe.copy()
156 |
157 | for col in dataframe.columns:
158 | #--- backward difference algorithm
159 | temp = np.diff(dataframe[col], 1, axis = 0)
160 | temp = np.insert(temp, 0, 0)
161 | temp = pd.DataFrame(temp )
162 | temp_deriv[col + '_td'] = temp
163 |
164 | if quadratic == True:
165 | for col in temp_deriv.columns:
166 | quad = temp_deriv[col] ** 2
167 | temp_deriv[col + '_quad'] = quad
168 |
169 | return temp_deriv
170 |
171 | def scrubbing(fd, thr = 0.5, before = True, after = True):
172 |
173 | """Function that calculates motion outliers (frames with motion above threshold_.
174 |
175 | Parameters
176 | ----------
177 | fd: pandas dataframe including frame-wise displacement (FD)
178 | thr: threshold (default: 0.5)
179 | before: marks frames before outlier datapoint (default: True)
180 | after: marks frames after outlier datapoint (default: True)
181 |
182 | Returns
183 | -------
184 | scrubbing: pandas dataframe including all outliers datapoints
185 |
186 | """
187 |
188 | scrubbing = pd.DataFrame()
189 | fd.loc[0] = 0
190 | fd = fd.astype(float)
191 |
192 | scrub1 = fd > thr
193 | scrub1 = scrub1.astype(int)
194 | scrubbing['scrubbing'] = scrub1
195 |
196 | if before == True:
197 | scrub2 = np.roll(scrubbing['scrubbing'], -1, axis = 0)
198 | scrub2[0] = 0
199 | scrubbing['scrubbing_bef'] = scrub2
200 |
201 | if after == True:
202 | scrub3 = np.roll(scrubbing['scrubbing'], 1, axis = 0)
203 | scrub3[0] = 0
204 | scrubbing['scrubbing_aft'] = scrub3
205 |
206 | return scrubbing
207 |
208 | def outliers_fd_dvars(dataframe, fd=0.5, dvars=3):
209 | """Function that calculates motion outliers (frames with frame-wise displacement (FD)
210 | and DVARS above predefined threshold).
211 |
212 | Parameters
213 | ----------
214 | dataframe: pandas dataframe including columns with DVARS and FD
215 | fd: threshold for FD (default: 0.5)
216 | dvars: threshold for DVARS (+/-SD, default: 3)
217 |
218 | Returns
219 | -------
220 | outliers: pandas dataframe including all outliers datapoints
221 |
222 | """
223 |
224 | df = dataframe.copy()
225 | df.fillna(value=0, inplace=True)
226 |
227 | dvars_out = np.absolute(df[df.columns[0]].astype(float)) > dvars
228 | fd_out = df[df.columns[1]].astype(float) > fd
229 |
230 | outliers = (dvars_out == True) | (fd_out == True)
231 | outliers = pd.DataFrame(outliers.astype('int'))
232 | outliers.columns = ['scrubbing']
233 |
234 | return outliers
235 |
236 | def get_condition_column(events, tr = 2, n_scans = 340):
237 | """converts events file to pd dataframe with column representing each condition"""
238 | frame_times = np.arange(n_scans) * tr
239 | box = make_first_level_design_matrix(frame_times, events, hrf_model = None)
240 | box = box.reset_index()
241 |
242 | x = box.iloc[:,1:4] > 0.8
243 | y = x.astype('int')
244 | col = pd.DataFrame(y.idxmax(axis=1), columns = ['condition'])
245 | return col
246 |
247 |
--------------------------------------------------------------------------------
/fctools/figures.py:
--------------------------------------------------------------------------------
1 | import seaborn as sns
2 | import matplotlib.pyplot as plt
3 | import numpy as np
4 |
5 | def matrix_networks_plot(M, network_colors, dpi = 300, colorbar = False, group = None, ses = None, suffix = None, out_dir = None):
6 | """Creates and saves matrixplot with networks color labels. """
7 |
8 | small = 15
9 | medium = 15
10 | bigger = 15
11 |
12 | plt.rc('font', size=small) # controls default text sizes
13 | plt.rc('axes', titlesize=small) # fontsize of the axes title
14 | plt.rc('axes', linewidth=2.2)
15 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels
16 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels
17 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels
18 | plt.rc('legend', fontsize=small) # legend fontsize
19 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title
20 | plt.rc('lines', linewidth=2.2, color='gray')
21 |
22 | g = sns.clustermap(M,
23 | cmap="RdBu_r",
24 | row_cluster=False,
25 | col_cluster=False,
26 | row_colors=network_colors,
27 | col_colors=network_colors,
28 | linewidths=0,
29 | yticklabels=False,
30 | xticklabels=False,
31 | vmax = 0.8)
32 |
33 | # Adjust the postion of the main colorbar for the heatmap
34 | g.cax.set_position([.97, .2, .03, .45])
35 | g.fig.suptitle(f'{group}: {ses}', size = 20)
36 | #g.ax_heatmap.set_title(f'{group}: {ses}', size = 15)
37 | g.cax.set_visible(colorbar)
38 |
39 | if out_dir == None:
40 | "Figure not saved"
41 | else:
42 |
43 | if suffix != None:
44 | g.savefig(f'{out_dir}{group}_{ses}_{suffux}.pdf', dpi=dpi)
45 | else:
46 | g.savefig(f'{out_dir}{group}_{ses}.pdf', dpi=dpi)
47 |
48 |
49 | def swarm_box_plot(x, y, hue, data):
50 | plt.style.use('seaborn-white')
51 | plt.rcParams['font.family'] = 'Helvetica'
52 |
53 | plt.figure(figsize = (8, 6))
54 |
55 | ax = sns.swarmplot(x = x, y = y, hue = hue, data = data, dodge = True, alpha = 0.8, size = 8)
56 | ax = sns.boxplot(x = x, y = y, hue = hue, data = data, dodge = True,
57 | showcaps = False, boxprops = {'facecolor':'None'},
58 | showfliers = False)
59 | plt.xticks(np.arange(4), ('1', '2', '3', '4'))
60 | ax.set(xlabel='Scan')
61 | ax.tick_params(axis='both', color = 'black', length = 5, width = 2)
62 |
63 | return ax
64 |
65 |
66 | def swarm_box_plot_integ(x, hue, data, net1, net2):
67 |
68 | plt.style.use('seaborn-white')
69 | plt.rcParams['font.family'] = 'Helvetica'
70 |
71 | small = 25
72 | medium = 25
73 | bigger = 25
74 |
75 | plt.rc('font', size=small) # controls default text sizes
76 | plt.rc('axes', titlesize=small) # fontsize of the axes title
77 | plt.rc('axes', linewidth=2.2)
78 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels
79 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels
80 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels
81 | plt.rc('legend', fontsize=small) # legend fontsize
82 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title
83 | plt.rc('lines', linewidth=2.2, color='gray')
84 |
85 | plt.figure(figsize = (8, 6))
86 |
87 | ax = sns.swarmplot(x = x, y = f'{net1}_integration', hue = hue, data = data[data['Network'] == net2], dodge = True, alpha = 0.8, size = 8)
88 | ax = sns.boxplot(x = x, y = f'{net1}_integration', hue = hue, data = data[data['Network'] == net2], dodge = True,
89 | showcaps = False, boxprops = {'facecolor':'None'},
90 | showfliers = False)
91 | plt.xticks(np.arange(4), ('Naive', 'Early', 'Middle', 'Late'))
92 | ax.set(xlabel='Scan')
93 | plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
94 | ax.tick_params(axis='both', color = 'black', length = 5, width = 2)
95 |
96 |
97 | return ax
98 |
99 |
100 | def matrix_networks_slope_plot(M, network_colors, dpi=300, colorbar=False, group=None, suffix=None, out_dir=None, vmin = -0.08, vmax = 0.08):
101 | """Creates and saves matrixplot with networks color labels. """
102 |
103 | small = 15
104 | medium = 15
105 | bigger = 15
106 |
107 | plt.rc('font', size=small) # controls default text sizes
108 | plt.rc('axes', titlesize=small) # fontsize of the axes title
109 | plt.rc('axes', linewidth=2.2)
110 | plt.rc('axes', labelsize=medium) # fontsize of the x and y labels
111 | plt.rc('xtick', labelsize=small) # fontsize of the tick labels
112 | plt.rc('ytick', labelsize=small) # fontsize of the tick labels
113 | plt.rc('legend', fontsize=small) # legend fontsize
114 | plt.rc('figure', titlesize=bigger) # fontsize of the figure title
115 | plt.rc('lines', linewidth=2.2, color='gray')
116 | g = sns.clustermap(M,
117 | cmap="RdBu_r",
118 | row_cluster=False,
119 | col_cluster=False,
120 | row_colors=network_colors,
121 | col_colors=network_colors,
122 | linewidths=0,
123 | yticklabels=False,
124 | xticklabels=False, vmin = vmin, vmax = vmax)
125 |
126 | # Adjust the postion of the main colorbar for the heatmap
127 | g.cax.set_position([.97, .2, .03, .45])
128 | g.fig.suptitle(f'{group}', size=20)
129 | #g.ax_heatmap.set_title(f'{group}: {ses}', size = 15)
130 | g.cax.set_visible(colorbar)
131 |
132 | if out_dir == None:
133 | "Figure not saved"
134 | else:
135 |
136 | if suffix != None:
137 | g.savefig(f'{out_dir}{group}_{ses}_{suffux}.pdf', dpi=dpi)
138 | else:
139 | g.savefig(f'{out_dir}{group}_{ses}.pdf', dpi=dpi)
--------------------------------------------------------------------------------
/fctools/networks.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | """
5 | Created on Tue Jun 12 2018
6 | Last edit: Tue Jun 12 2018
7 | @author: kfinc
8 |
9 | """
10 |
11 | import numpy as np
12 | import pandas as pd
13 |
14 | def calculate_lsn_edges (A, labels):
15 | """Function calculates number of edges between and within predefined large-scale networks (LSNs).
16 | The function takes binary symetrical adjacency matrix, module assignment of each ROI and calculate number of edges between and within each
17 | large-scale network.
18 |
19 | Parameters
20 | ------------
21 | array: N x N binary ajdacency matrix
22 | array: N-length vector with module assignment for each node
23 |
24 | Returns
25 | ------------
26 | array: M x M matrix with number of edges between each module
27 |
28 | """
29 | columns = np.unique(labels)
30 | lsn_matrix = np.zeros((len(labels), len(columns)))
31 | lsn_edges = np.zeros((len(columns), len(columns)))
32 |
33 | for col in range(len(columns)):
34 | module = columns[col, ]
35 | for row in range(len(labels)):
36 | if (labels[row, ] == module):
37 | lsn_matrix[row, col] = 1
38 | else:
39 | lsn_matrix[row, col] = 0
40 |
41 | lsn_edges = lsn_matrix.T @ A @ lsn_matrix
42 | return lsn_edges
43 |
44 |
45 | def allegiance_matrix(M):
46 | """Calculates n x n allegiance matrix P from n x t matrix M, where n represents nodes, and t represents time windows.
47 | Each value on allegiance matrix P represents the probability that node i and node j have been assigned to the same
48 | community (Bassett et al., 2014; Mattar et al., 2015).
49 |
50 | Parameters
51 | ------------
52 | array: n x t module assignment matrix t
53 |
54 | Returns
55 | ------------
56 | array: n x n allegiance matrix P """
57 |
58 | n_nodes = M.shape[0]
59 | n_slices = M.shape[1]
60 | T = np.zeros((n_nodes, n_nodes))
61 |
62 | for i in range(n_nodes):
63 | for j in range(i):
64 | if i == j:
65 | continue
66 | else:
67 | t = np.sum(M[i, :] == M[j, :])
68 | T[i, j] = t
69 |
70 | P = (T + T.T)/n_slices
71 | np.fill_diagonal(P, 1)
72 |
73 | return P
74 |
75 |
76 | def allegiance_matrices_4d(M):
77 | """Calculates 4D array composed of allegiance matrices for each subject and each condition/session.
78 |
79 | Parameters
80 | ------------
81 | array: 4D array S(subjects) x C(condition/session) x N(node) x M(window)
82 |
83 | Returns
84 | ------------
85 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node), where N x N is allegiance matrix
86 |
87 | """
88 | n_roi = len(M[0,0,:,0])
89 | n_sub = len(M[:,0,0,0])
90 | n_ses = len(M[0,:,0,0])
91 | AM = np.zeros((n_sub, n_ses, n_roi, n_roi))
92 |
93 | for sub in range(n_sub):
94 | for ses in range(n_ses):
95 | AM[sub, ses, :, :] = allegiance_matrix(M[sub, ses, :, :])
96 | return AM
97 |
98 | def allegiance_matrix_opti(M):
99 | """Calculates n x n allegiance matrix P from o x n x t matrix M, where o represents module community detection
100 | optimizations, n represents nodes, and t represents time windows. Each value on allegiance matrix PO represents the
101 | probability that node i and node j have been assigned to the same
102 | community (Bassett et al., 2014; Mattar et al., 2015).
103 |
104 | Parameters
105 | ------------
106 | array: o x n x t module assignment matrix t
107 |
108 | Returns
109 | ------------
110 | array: n x n allegiance matrix P (mean across all optimizations)"""
111 |
112 | n_optimizations = M.shape[0]
113 | n_nodes = M.shape[1]
114 | P = np.zeros((n_optimizations, n_nodes, n_nodes))
115 | PO = np.zeros((n_nodes, n_nodes))
116 |
117 | for i in range(n_optimizations):
118 | P[i, :, :] = allegiance_matrix(M[i, :, :])
119 | PO = P.mean(axis = 0)
120 | return PO
121 |
122 | def allegiance_matrix_opti_5d(M):
123 |
124 | n_subs = M.shape[0]
125 | n_sess = M.shape[1]
126 | n_optimizations = M.shape[2]
127 | n_nodes = M.shape[3]
128 |
129 | P = np.zeros((n_subs, n_sess, n_optimizations, n_nodes, n_nodes))
130 |
131 | for i in range(n_subs):
132 | for j in range(n_sess):
133 | P[i, j, :, :, :] = allegiance_matrix_opti_3d(M[i, j, :, :, :])
134 | return P
135 |
136 | def sort_matrices_4d(M, idx):
137 | """Sorts matrices according to predefinded index.
138 |
139 | Parameters
140 | ------------
141 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node) (unsorted)
142 | array: N-length vector with index to sort matrix
143 |
144 | Returns
145 | ------------
146 | array: 4D array S(subjects) x C(condition/session) x N(node) x N(node) (sorted)"""
147 | M1 = M[:,:,:,idx]
148 | M2 = M1[:,:,idx,:]
149 | return M2
150 |
151 |
152 | def dumming(labels):
153 | """Gennerate vectors with dummy variables from single vector with categorical variable
154 |
155 | Parameters
156 | ------------
157 | array: np.array, N-length vector with categorical variable
158 |
159 | Returns
160 | ------------
161 | array: 3D array with M rows and N columns with binary variables"""
162 |
163 | columns = np.unique(labels)
164 | dummies = np.zeros((len(labels), len(columns)))
165 |
166 | for col in range(len(columns)):
167 | module = columns[col]
168 | for row in range(len(labels)):
169 | if (labels[row] == module):
170 | dummies[row, col] = 1
171 | else:
172 | dummies[row, col] = 0
173 | return dummies
174 |
175 |
176 | def dumming_pd(labels):
177 | """Gennerate vectors with dummy variables from single vector with categorical variable
178 |
179 | Parameters
180 | ------------
181 | array: np.array, N-length vector with categorical variable
182 |
183 | Returns
184 | ------------
185 | array: pd.DataFrame with M rows and N columns with binary variables
186 |
187 | """
188 | columns = np.unique(labels)
189 | return pd.DataFrame(dumming(labels), columns=columns)
190 |
191 | def upper_tri_masking(A):
192 | """Getting values of upper triangle of matrix without diagonal"""
193 | m = A.shape[0]
194 | r = np.arange(m)
195 | mask = r[:,None] < r
196 | return A[mask]
197 |
198 |
199 | def fc_cartography(M, modules):
200 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices"""
201 | dummy_networks = dumming(sorted(modules))
202 | roi_n = len(dummy_networks)
203 | net = np.size(dummy_networks,1)
204 | diagnostics = np.zeros((net, net))
205 |
206 | for i in range(net):
207 | for j in range(net):
208 | vec1 = dummy_networks[:,i].astype('bool')
209 | vec2 = dummy_networks[:,j].astype('bool')
210 |
211 | L = M[vec1,:]
212 | P = L[:,vec2]
213 |
214 | #if i == j:
215 | # m = upper_tri_masking(P).mean()
216 | #else:
217 | m = P.mean()
218 |
219 | diagnostics[i, j] = m
220 | return diagnostics
221 |
222 |
223 | '''def fc_cartography(M, modules):
224 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices"""
225 | dummy_networks = dumming(sorted(modules))
226 | n_nod = len(dummy_networks)
227 | n_net = np.size(dummy_networks,1)
228 | diagnostics = np.zeros((n_net, n_net))
229 |
230 | for i in range(n_net):
231 | for j in range(n_net):
232 | vec1 = dummy_networks[:,i].astype('bool')
233 | vec2 = dummy_networks[:,j].astype('bool')
234 |
235 | L = M[vec1,:]
236 | P = L[:,vec2]
237 |
238 | #if i == j:
239 | # m = upper_tri_masking(P).mean()
240 | #else:
241 | m = P.mean()
242 |
243 | diagnostics[i, j] = m
244 | return diagnostics
245 | '''
246 |
247 |
248 |
249 | def fc_cartography_4d(M, modules):
250 | """Function which calculates mean integration and recruitment values from sorted allegiance matrices. 4D version"""
251 | sub_n = len(M[:,0,0,0])
252 | ses_n = len(M[0,:,0,0])
253 | mod_n = len(np.unique(modules))
254 |
255 | fc_cart = np.zeros((sub_n, ses_n, mod_n, mod_n))
256 |
257 | for i in range(sub_n):
258 | for j in range(ses_n):
259 | X = M[i,j,:,:]
260 | fc_cart[i, j, :, :] = fc_cartography(X, modules)
261 | return fc_cart
262 |
263 |
264 | def net_filter(M, modules, net_list):
265 | modules = np.sort(np.asarray(modules))
266 | net_filt = [True if elem in net_list else False for elem in modules]
267 | M1 = M[net_filt, :]
268 | M2 = M1[:, net_filt]
269 | return M2
270 |
271 | def net_filter_4d(M, modules, net_list):
272 | modules = np.sort(np.asarray(modules))
273 | net_filt = [True if elem in net_list else False for elem in modules]
274 | M1 = M[:, :, net_filt, :]
275 | M2 = M1[:, :, :, net_filt]
276 | return M2
277 |
278 | def single_window_allegiance(t):
279 | n_nod = len(t)
280 | T = np.zeros((n_nod, n_nod))
281 |
282 | for i, row in enumerate(t):
283 | for j, col in enumerate(t):
284 | if row == col:
285 | T[i,j] = 1
286 | else:
287 | continue
288 | return T
289 |
290 | def single_window_allegiance_mean(M):
291 | n_opt = M.shape[0]
292 | n_nod = M.shape[1]
293 | T = np.zeros((n_opt, n_nod, n_nod))
294 |
295 | for i in range(n_opt):
296 | T[i, :, :] = single_window_allegiance(M[i, :])
297 |
298 | return T.mean(axis=0)
299 |
300 | def all_window_allegiance_mean(M):
301 |
302 | n_win = M.shape[2]
303 | n_nod = M.shape[1]
304 |
305 | T = np.zeros((n_win, n_nod, n_nod))
306 |
307 | for i in range(n_win):
308 | T[i, :, :] = single_window_allegiance_mean(M[:,:,i])
309 |
310 | return T
311 |
312 | def node_flexibility(node_vector):
313 | n_win = len(node_vector)
314 | count = 0
315 | for i in range(n_win-1):
316 | if node_vector[i] != node_vector[i+1]:
317 | count += 1
318 | return count/n_win
319 |
320 |
321 | def flexibility(matrix):
322 | n_nod = matrix.shape[0]
323 | n_win = matrix.shape[1]
324 |
325 | node_flex = [node_flexibility(elem) for elem in matrix]
326 | return node_flex
327 |
328 |
329 |
330 | def randmio_und(R, itr):
331 | '''
332 | Edited from aestrivex/bctpy with corrected matrix symetry check
333 |
334 | This function randomizes an undirected network, while preserving the
335 | degree distribution. The function does not preserve the strength
336 | distribution in weighted networks.
337 | Parameters
338 | ----------
339 | W : NxN np.ndarray
340 | undirected binary/weighted connection matrix
341 | itr : int
342 | rewiring parameter. Each edge is rewired approximately itr times.
343 | Returns
344 | -------
345 | R : NxN np.ndarray
346 | randomized network
347 | eff : int
348 | number of actual rewirings carried out
349 | '''
350 | if not np.allclose(R, R.T):
351 | raise BCTParamError("Input must be undirected")
352 | R = R.copy()
353 | n = len(R)
354 | i, j = np.where(np.tril(R))
355 | k = len(i)
356 | itr *= k
357 |
358 | # maximum number of rewiring attempts per iteration
359 | max_attempts = np.round(n * k / (n * (n - 1)))
360 | # actual number of successful rewirings
361 | eff = 0
362 |
363 | for it in range(int(itr)):
364 | att = 0
365 | while att <= max_attempts: # while not rewired
366 | while True:
367 | e1, e2 = np.random.randint(k, size=(2,))
368 | while e1 == e2:
369 | e2 = np.random.randint(k)
370 | a = i[e1]
371 | b = j[e1]
372 | c = i[e2]
373 | d = j[e2]
374 |
375 | if a != c and a != d and b != c and b != d:
376 | break # all 4 vertices must be different
377 |
378 | if np.random.random() > .5:
379 | i.setflags(write=True)
380 | j.setflags(write=True)
381 | i[e2] = d
382 | j[e2] = c # flip edge c-d with 50% probability
383 | c = i[e2]
384 | d = j[e2] # to explore all potential rewirings
385 |
386 | # rewiring condition
387 | if not (R[a, d] or R[c, b]):
388 | R[a, d] = R[a, b]
389 | R[a, b] = 0
390 | R[d, a] = R[b, a]
391 | R[b, a] = 0
392 | R[c, b] = R[c, d]
393 | R[c, d] = 0
394 | R[b, c] = R[d, c]
395 | R[d, c] = 0
396 |
397 | j.setflags(write=True)
398 | j[e1] = d
399 | j[e2] = b # reassign edge indices
400 | eff += 1
401 | break
402 | att += 1
403 |
404 | return R, eff
--------------------------------------------------------------------------------
/fctools/stats.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from scipy import stats
3 | import pandas as pd
4 |
5 | def m_wei(x, w):
6 | """Weighted Mean"""
7 | return np.sum(x * w) / np.sum(w)
8 |
9 | def cov_wei(x, y, w):
10 | """Weighted Covariance"""
11 | return np.sum(w * (x - m_wei(x, w)) * (y - m_wei(y, w))) / np.sum(w)
12 |
13 | def corr_wei(x, y, w):
14 | """Weighted Correlation"""
15 | return cov_wei(x, y, w) / np.sqrt(cov_wei(x, x, w) * cov_wei(y, y, w))
16 |
17 | def bootstrap_replicate_1d(data, func):
18 | """Calculate bootstrap replicate"""
19 | return func(np.random.choice(data, size=len(data)))
20 |
21 | def ttest_rel_cond(group, variable, data):
22 | """ Function which calculates paired t-test comparing variable between two task conditions"""
23 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4']
24 | conds = ['1-back', '2-back']
25 | table = np.zeros((4,2))
26 |
27 | for i, ses in enumerate(sess):
28 | group_1 = data[(data.Session == ses) & (data.Condition == '1-back') & (data.Group == group)]
29 | group_2 = data[(data.Session == ses) & (data.Condition == '2-back') & (data.Group == group)]
30 |
31 | t, pval = stats.ttest_rel(group_1[variable].values, group_2[variable].values,)
32 | table[i, 0] = t
33 | table[i, 1] = pval
34 |
35 | return pd.DataFrame(table.tolist(), columns = ['statistic', 'pval'])
36 |
37 |
38 | def ttest_rel_sess(group, variable, data):
39 | """ Function which calculates paired t-test comparing variable between each session"""
40 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4']
41 | table = np.zeros((4,4,2))
42 |
43 | for i, ses1 in enumerate(sess):
44 | for j, ses2 in enumerate(sess):
45 | ses_1 = data[(data.Session == ses1) & (data.Group == group)]
46 | ses_2 = data[(data.Session == ses2) & (data.Group == group)]
47 |
48 | t, pval = stats.ttest_rel(ses_1[variable].values, ses_2[variable].values,)
49 | table[i, j, 0] = t
50 | table[i, j, 1] = pval
51 |
52 | return table
53 |
54 | def ttest_ind_groups(variable, data):
55 | """ Function which calculates two sample t-test comparing variables between groups"""
56 | sess = ['ses-1', 'ses-2', 'ses-3', 'ses-4']
57 |
58 | table = np.zeros((4,2))
59 |
60 | for i, ses in enumerate(sess):
61 | group_1 = data[(data.Session == ses) & (data.Group == 'Experimental')]
62 | group_2 = data[(data.Session == ses) & (data.Group == 'Control')]
63 |
64 | t, pval = stats.ttest_ind(group_1[variable].values, group_2[variable].values,)
65 | table[i, 0] = t
66 | table[i, 1] = pval
67 |
68 | return pd.DataFrame(table.tolist(), columns = ['statistic', 'pval'])
69 |
70 |
--------------------------------------------------------------------------------
/support/modules.txt:
--------------------------------------------------------------------------------
1 | UNC
2 | UNC
3 | UNC
4 | UNC
5 | UNC
6 | UNC
7 | UNC
8 | UNC
9 | UNC
10 | UNC
11 | UNC
12 | UNC
13 | SOM
14 | SOM
15 | SOM
16 | SOM
17 | SOM
18 | SOM
19 | SOM
20 | SOM
21 | SOM
22 | SOM
23 | SOM
24 | SOM
25 | SOM
26 | SOM
27 | SOM
28 | SOM
29 | SOM
30 | SOM
31 | SOM
32 | SOM
33 | SOM
34 | SOM
35 | SOM
36 | SOM
37 | SOM
38 | SOM
39 | SOM
40 | SOM
41 | SOM
42 | SOM
43 | SOM
44 | SOM
45 | SOM
46 | SOM
47 | CO
48 | CO
49 | CO
50 | CO
51 | CO
52 | CO
53 | CO
54 | CO
55 | CO
56 | CO
57 | CO
58 | CO
59 | CO
60 | CO
61 | AU
62 | AU
63 | AU
64 | AU
65 | AU
66 | AU
67 | AU
68 | AU
69 | AU
70 | AU
71 | AU
72 | AU
73 | AU
74 | DM
75 | DM
76 | DM
77 | DM
78 | DM
79 | DM
80 | DM
81 | DM
82 | DM
83 | DM
84 | UNC
85 | UNC
86 | DM
87 | DM
88 | DM
89 | DM
90 | DM
91 | DM
92 | DM
93 | DM
94 | DM
95 | DM
96 | DM
97 | DM
98 | DM
99 | DM
100 | DM
101 | DM
102 | DM
103 | DM
104 | DM
105 | DM
106 | DM
107 | DM
108 | DM
109 | DM
110 | DM
111 | DM
112 | DM
113 | DM
114 | DM
115 | DM
116 | DM
117 | DM
118 | DM
119 | DM
120 | DM
121 | DM
122 | DM
123 | DM
124 | DM
125 | DM
126 | DM
127 | DM
128 | DM
129 | DM
130 | DM
131 | DM
132 | UNC
133 | MEM
134 | MEM
135 | MEM
136 | MEM
137 | DM
138 | VA
139 | DM
140 | UNC
141 | UNC
142 | UNC
143 | VIS
144 | VIS
145 | VIS
146 | VIS
147 | VIS
148 | VIS
149 | VIS
150 | VIS
151 | VIS
152 | VIS
153 | VIS
154 | VIS
155 | VIS
156 | VIS
157 | VIS
158 | VIS
159 | VIS
160 | VIS
161 | VIS
162 | VIS
163 | VIS
164 | VIS
165 | VIS
166 | VIS
167 | VIS
168 | VIS
169 | VIS
170 | VIS
171 | VIS
172 | VIS
173 | VIS
174 | FP
175 | FP
176 | FP
177 | FP
178 | FP
179 | FP
180 | FP
181 | FP
182 | UNC
183 | UNC
184 | UNC
185 | UNC
186 | FP
187 | FP
188 | FP
189 | FP
190 | FP
191 | FP
192 | FP
193 | FP
194 | FP
195 | FP
196 | FP
197 | FP
198 | FP
199 | FP
200 | FP
201 | FP
202 | FP
203 | SAL
204 | SAL
205 | SAL
206 | SAL
207 | SAL
208 | SAL
209 | SAL
210 | SAL
211 | SAL
212 | SAL
213 | SAL
214 | SAL
215 | SAL
216 | SAL
217 | SAL
218 | SAL
219 | SAL
220 | SAL
221 | MEM
222 | SUB
223 | SUB
224 | SUB
225 | SUB
226 | SUB
227 | SUB
228 | SUB
229 | SUB
230 | SUB
231 | SUB
232 | SUB
233 | SUB
234 | SUB
235 | VA
236 | VA
237 | VA
238 | VA
239 | VA
240 | VA
241 | VA
242 | VA
243 | CER
244 | CER
245 | CER
246 | CER
247 | UNC
248 | UNC
249 | UNC
250 | UNC
251 | DA
252 | DA
253 | UNC
254 | UNC
255 | SOM
256 | DA
257 | DA
258 | DA
259 | DA
260 | DA
261 | DA
262 | DA
263 | DA
264 | DA
265 |
--------------------------------------------------------------------------------
/support/onsets_dualnback.csv:
--------------------------------------------------------------------------------
1 | duration,onset,trial_type
2 | 4.00,0.00,intro
3 | 30.00,4.00,1-back
4 | 4.00,34.00,intro
5 | 30.00,38.00,2-back
6 | 4.00,68.00,intro
7 | 30.00,72.00,1-back
8 | 4.00,102.00,intro
9 | 30.00,106.00,2-back
10 | 4.00,136.00,intro
11 | 30.00,140.00,1-back
12 | 4.00,170.00,intro
13 | 30.00,174.00,2-back
14 | 4.00,204.00,intro
15 | 30.00,208.00,1-back
16 | 4.00,238.00,intro
17 | 30.00,242.00,2-back
18 | 4.00,272.00,intro
19 | 30.00,276.00,1-back
20 | 4.00,306.00,intro
21 | 30.00,310.00,2-back
22 | 4.00,340.00,intro
23 | 30.00,344.00,1-back
24 | 4.00,374.00,intro
25 | 30.00,378.00,2-back
26 | 4.00,408.00,intro
27 | 30.00,412.00,1-back
28 | 4.00,442.00,intro
29 | 30.00,446.00,2-back
30 | 4.00,476.00,intro
31 | 30.00,480.00,1-back
32 | 4.00,510.00,intro
33 | 30.00,514.00,2-back
34 | 4.00,544.00,intro
35 | 30.00,548.00,1-back
36 | 4.00,578.00,intro
37 | 30.00,582.00,2-back
38 | 4.00,612.00,intro
39 | 30.00,616.00,1-back
40 | 4.00,646.00,intro
41 | 30.00,650.00,2-back
--------------------------------------------------------------------------------