#!/usr/bin/env python
# coding: utf-8
#
# ## 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?