#!/usr/bin/env python # coding: utf-8 # Open In Colab   Open in Kaggle # ## Loading of Miller ECoG data of the memory nback task # # includes some visualizations # In[ ]: # @title Data retrieval import os, requests fname = 'memory_nback.npz' url = "https://osf.io/xfc7e/download" if not os.path.isfile(fname): try: r = requests.get(url) except requests.ConnectionError: print("!!! Failed to download data !!!") else: if r.status_code != requests.codes.ok: print("!!! Failed to download data !!!") else: with open(fname, "wb") as fid: fid.write(r.content) # In[ ]: # @title Install packages (`nilearn`, `nimare`, `duecredit`), import `matplotlib` and set defaults # install packages to visualize brains and electrode locations get_ipython().system('pip install nilearn --quiet') get_ipython().system('pip install nimare --quiet') get_ipython().system('pip install duecredit --quiet') from matplotlib import rcParams from matplotlib import pyplot as plt rcParams['figure.figsize'] = [20, 4] rcParams['font.size'] = 15 rcParams['axes.spines.top'] = False rcParams['axes.spines.right'] = False rcParams['figure.autolayout'] = True # In[ ]: # @title Data loading import numpy as np alldat = np.load(fname, allow_pickle=True)['dat'] # Select just one of the recordings here. This is subject 1, block 1. dat = alldat[1][1] print(dat.keys()) # --- # # Dataset info # # This is one of multiple ECoG datasets from Miller 2019, recorded in clinical settings with a variety of tasks. Raw data here: # # https://exhibits.stanford.edu/data/catalog/zk881ps0522 # # `dat` contain 3 sessions from 3 subjects, and was not yet used in a publication, so it's fresh data for you to analyze! The following references using other datasets may be useful for the memory n-back task: # # - Brouwer, Anne-Marie, et al. "Estimating workload using EEG spectral power and ERPs in the n-back task." Journal of Neural Engineering 9.4 (2012): 045008. doi: [10.1088/1741-2560/9/4/045008](https://doi.org/10.1088/1741-2560/9/4/045008) # # - Grissmann, Sebastian, et al. "Electroencephalography based analysis of working memory load and affective valence in an n-back task with emotional stimuli." Frontiers in Human Neuroscience 11 (2017): 616. doi: [10.3389/fnhum.2017.00616](https://doi.org/10.3389/fnhum.2017.00616) # # Each subject's data is divided into 5 sessions: fixation, exp1, exp2, exp3, fixation, which are consecutive blocks in the data structure (i.e. `alldat[0][0]`, `alldat[0][1]`, ..., `alldat[0][4]` for subject 0). Exp1 is a "0-back" memory experiment, where the subjects have to identify the picture of one of the houses (stimid = 10), which they have memorized at the beginning of the stimulus block. Exp2 is a 1-back memory experiment, where the participants have to respond to images of repeated houses. Finally, exp3 is 2-back where participants respond to pictures of houses that are repeated after another intervening random picture. This task was hard for these participants and most of them did not really respond at all, but the data can still be used to ask questions about overall shifts of neural activity in a hard task when the subjects feel overwhelmed by the memory requirements. # # Note that for the third/last subject, no response data was collected, so only the first two subjects can be analyzed for their correct / incorrect trials. # # Sample rate is always 1000Hz, and the ECoG data has been notch-filtered at 60, 120, 180, 240 and 250Hz, followed by z-scoring across the entire recording and conversion to float16 to minimize size. # # Variables for each block within each subject: # * `dat['V']`: continuous voltage data (time by channels) # * `dat['expinfo']`: experiment type for this block # * `dat['srate']`: sampling rate for voltage data, always 1000Hz # * `dat['t_on']`: time of stimulus onset in data samples # * `dat['t_off']`: time of stimulus offset, usually 600 samples after `t_on` # * `dat['stim_id`]: identity of house stimulus from 1 to 40. Stimulus 10 was the target in the 0-back task. # * `dat['target']`: 0 or 1, indicates if this stimulus requires a response # * `dat['response']`: 0 or 1, indicates if the subject actually made a response # * `dat['rt']`: reaction time for trials with a response in voltage data samples (1000Hz). # * `dat['locs']`: 3D locations of the electrodes on the cortical surface # In[ ]: from nilearn import plotting from nimare import utils plt.figure(figsize=(8, 8)) locs = dat['locs'] view = plotting.view_markers(utils.tal2mni(locs), marker_labels=['%d'%k for k in np.arange(locs.shape[0])], marker_color='purple', marker_size=5) view # In[ ]: # compute spectral power above 50Hz and low-pass below 10Hz # power is always positive, so we normalize it by its average from scipy import signal # pick subject 1 and experiment 1 dat = alldat[1][1] V = dat['V'].astype('float32') # always convert the voltage data to float32! # high-pass filter above 50 Hz b, a = signal.butter(3, [50], btype='high', fs=1000) V = signal.filtfilt(b, a, V, 0) # compute smooth envelope of this signal = approx power V = np.abs(V)**2 b, a = signal.butter(3, [10], btype='low', fs=1000) V = signal.filtfilt(b, a, V, 0) # normalize each channel so its mean power is 1 V = V/V.mean(0) # In[ ]: # divide into trials and average nt, nchan = V.shape nstim = len(dat['t_on']) # use a timerange from 400ms before to 1600ms after the stimulus onset trange = np.arange(-400, 1600) ts = dat['t_on'][:, np.newaxis] + trange V_epochs = np.reshape(V[ts, :], (nstim, 2000, nchan)) V_resp = (V_epochs[dat['response'] == 1]).mean(0) V_base = (V_epochs[dat['response'] == 0]).mean(0) # In[ ]: # let's find the electrodes that distinguish responses from non-responses # note these are event-related potentials plt.figure(figsize=(15, 12)) for j in range(60): ax = plt.subplot(6, 10, j+1) plt.plot(trange, V_resp[:, j], lw=2) plt.plot(trange, V_base[:, j], lw=2) plt.title('ch%d'%j) plt.yticks([]) plt.ylim([0, 3]) plt.show() # In[ ]: # let's look at all the response trials for the electrode that has a significant response plt.subplot(1, 3, 1) plt.imshow(V_epochs[dat['response']==1, :, 21].astype('float32'), aspect='auto') plt.colorbar() plt.show() # In[ ]: # this electrode has a more transient response plt.subplot(1, 3, 1) plt.imshow(V_epochs[dat['response']==1, :, 27].astype('float32'), aspect='auto') plt.colorbar() plt.show() # In[ ]: # to do: do these responses covary with the reaction times? are they present on trials where there is no motor response?