Brain objects are supereeg’s fundamental data structure for a single subject’s ECoG data. To create one at minimum you’ll need a matrix of neural recordings (time samples by electrodes), electrode locations, and a sample rate. Additionally, you can include information about separate recording sessions and store custom meta data. In this tutorial, we’ll build a brain object from scratch and get familiar with some of the methods.
import supereeg as se
import numpy as np
import warnings
warnings.simplefilter("ignore")
%matplotlib inline
First, we’ll use supereeg’s built in simulation functions to simulate
some data and electrodes. By default, the simulate_data
function
will return a 1000 samples by 10 electrodes matrix, but you can specify
the number of time samples with n_samples
and the number of
electrodes with n_elecs
. If you want further information on
simulating data, check out the simulate tutorial!
# simulate some data
bo_data = se.simulate_bo(n_samples=1000, sessions=2, n_elecs=10)
# plot it
bo_data.plot_data()
# get just data
data = bo_data.get_data()
We’ll also simulate some electrode locations
locs = se.simulate_locations()
print(locs)
x y z
0 -31 1 -18
1 -26 34 -24
2 -11 9 -12
3 -9 -8 -28
4 6 38 -41
5 10 -42 -3
6 29 47 36
7 32 3 -42
8 41 -18 -16
9 47 -34 32
To construct a new brain objects, simply pass the data and locations to
the Brain
class like this:
bo = se.Brain(data=data, locs=locs, sample_rate=100)
To view a summary of the contents of the brain object, you can call the
info
function:
bo.info()
Number of electrodes: 10
Recording time in seconds: [10.]
Sample Rate in Hz: [100]
Number of sessions: 1
Date created: Fri Jul 27 16:19:15 2018
Meta data: {}
Optionally, you can pass a sessions
parameter, which is can be a
numpy array or list the length of your data with a unique identifier for
each session. For example:
sessions = np.array([1]*(data.shape[0]/2)+[2]*(data.shape[0]/2))
bo = se.Brain(data=data, locs=locs, sample_rate=1000, sessions=sessions)
bo.info()
Number of electrodes: 10
Recording time in seconds: [0.5 0.5]
Sample Rate in Hz: [1000, 1000]
Number of sessions: 2
Date created: Fri Jul 27 16:19:15 2018
Meta data: {}
You can also add custom meta data to the brain object to help keep track
of its contents. meta
is a dictionary comprised of whatever you
want:
meta = {
'subjectID' : '123',
'Investigator' : 'Andy',
'Hospital' : 'DHMC'
}
bo = se.Brain(data=data, locs=locs, sample_rate=1000, sessions=sessions, meta=meta)
bo.info()
Number of electrodes: 10
Recording time in seconds: [0.5 0.5]
Sample Rate in Hz: [1000, 1000]
Number of sessions: 2
Date created: Fri Jul 27 16:19:15 2018
Meta data: {'Hospital': 'DHMC', 'subjectID': '123', 'Investigator': 'Andy'}
Brain
objects can be initialized by passing a any of the following
to the Brain
class instance initialization function: - A path to a
saved Brain
object (ending in .bo
) - An existing Brain
object (this creates a copy of the object) - A path to or instance of
any other supported toolbox type (Model
objects or .mo files, or
Nifti
objects or .nii files)
In addition, Brain
objects may be created via load
by specifying
return_type='bo'
.
For example:
nii_bo = se.Brain('example_nifti')
Or:
nii_bo = se.load('example_nifti', return_type='bo')
Another feature, which can be particularly useful when working with
large files, is loading only a subfield by specifiying field
. For
example, if you only want to load locations:
bo_locs = se.load('example_data', field='locs')
Inside the brain object, the ECoG data are stored in a Pandas DataFrame
that can be accessed with the get_data
function:
bo.get_data().head()
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0.209741 | -0.512392 | -0.720984 | -0.754342 | -1.726174 | -0.443516 | -1.782753 | -0.713155 | -0.284680 | -0.068902 |
1 | -1.055684 | -0.810194 | -0.673013 | 0.483223 | 0.008181 | -0.190715 | 2.239795 | -0.028814 | -0.301845 | -1.022902 |
2 | -0.346641 | -0.239482 | -0.370357 | 0.246060 | -0.578913 | -0.565974 | -0.946681 | -0.358038 | -0.616623 | -0.124095 |
3 | -0.610393 | 0.130029 | -0.152837 | -1.142612 | -1.017601 | -0.409920 | -1.533653 | -0.806856 | -0.701596 | -0.249572 |
4 | 0.290803 | 0.699244 | 0.240235 | 1.122073 | 0.716814 | 0.532778 | 0.992918 | 1.079572 | 0.397130 | -0.019875 |
Similarly, the electrode locations are stored as a Pandas DataFrame, and
can be retrieved using the get_locs
method:
bo.get_locs().head()
x | y | z | |
---|---|---|---|
0 | -31 | 1 | -18 |
1 | -26 | 34 | -24 |
2 | -11 | 9 | -12 |
3 | -9 | -8 | -28 |
4 | 6 | 38 | -41 |
Brain objects are iterable, so you index a brain object like this:
#return first time sample
bo[0]
#return first 3 time samples
bo[:3]
#return first electrode
bo[:, 0]
#returns first 3 timesamples/elecs
bo_i = bo[:3, :3]
bo_i.get_data()
0 | 1 | 2 | |
---|---|---|---|
0 | 0.209741 | -0.512392 | -0.720984 |
1 | -1.055684 | -0.810194 | -0.673013 |
2 | -0.346641 | -0.239482 | -0.370357 |
You can also pass a list of indices for either times
(sample
numbers) or locs
to the get_slice
method and return a subset of
the brain object.
bo_s = bo.get_slice(sample_inds=[0,1,2], loc_inds=[0,1,2])
bo_s.get_data()
0 | 1 | 2 | |
---|---|---|---|
0 | 0.209741 | -0.512392 | -0.720984 |
1 | -1.055684 | -0.810194 | -0.673013 |
2 | -0.346641 | -0.239482 | -0.370357 |
You can resample your data by specifying a new sample rate
bo.resample(64)
bo.info()
Number of electrodes: 10
Recording time in seconds: [0.5 0.5]
Sample Rate in Hz: [64, 64]
Number of sessions: 2
Date created: Fri Jul 27 16:19:15 2018
Meta data: {'Hospital': 'DHMC', 'subjectID': '123', 'Investigator': 'Andy'}
You can also plot both the data and the electrode locations:
bo.plot_data()
bo.plot_locs()
The other pieces of the brain object are listed below:
# array of session identifiers for each timepoint
sessions = bo.sessions
# number of sessions
n_sessions = bo.n_sessions
# sample rate
sample_rate = bo.sample_rate
# number of electrodes
n_elecs = bo.n_elecs
# length of each recording session in seconds
n_seconds = bo.dur
# the date and time that the bo was created
date_created = bo.date_created
# kurtosis of each electrode
kurtosis = bo.kurtosis
# meta data
meta = bo.meta
# label delinieating observed and reconstructed locations
label = bo.label
There are a few other useful methods on a brain object
bo.info()
¶This method will give you a summary of the brain object:
bo.info()
Number of electrodes: 10
Recording time in seconds: [0.5 0.5]
Sample Rate in Hz: [64, 64]
Number of sessions: 2
Date created: Fri Jul 27 16:19:15 2018
Meta data: {'Hospital': 'DHMC', 'subjectID': '123', 'Investigator': 'Andy'}
bo.apply_filter()
¶This method will return a filtered copy of the brain object.
bo_f = bo.apply_filter()
bo.get_data()
¶data_array = bo.get_data()
bo.get_zscore_data()
¶This method will return a numpy array of the zscored data:
zdata_array = bo.get_zscore_data()
bo.get_locs()
¶This method will return a numpy array of the electrode locations:
locs = bo.get_locs()
bo.get_slice()
¶This method allows you to slice out time and locations from the brain
object, and returns a brain object. This can occur in place if you set
the flag inplace=True
.
bo_slice = bo.get_slice(sample_inds=None, loc_inds=None, inplace=False)
bo.resample()
¶This method allows you resample a brain object in place.
bo.resample(resample_rate=None)
<supereeg.brain.Brain at 0x116c298d0>
bo.plot_locs()
¶This method plots electrode locations from brain object:
bo_f = se.load('example_filter')
bo_f.plot_locs()
bo.to_nii()
¶This method converts the brain object into supereeg’s nifti
class (a
subclass of the nibabel
nifti class). If filepath
is specified,
the nifti file will be saved. You can also specify a nifti template with
the template
argument. If no template is specified, it will use the
gray matter masked MNI 152 brain downsampled to 6mm.
# convert to nifti
nii = bo.to_nii(template='gray', vox_size=6)
# plot first timepoint
nii.plot_glass_brain()
# save the file
# nii = bo.to_nii(filepath='/path/to/file/brain')
# specify a template and resolution
# nii = bo.to_nii(template='/path/to/nifti/file.nii', vox_size=20)
bo.save(fname='something')
¶This method will save the brain object to the specified file location.
The data will be saved as a ‘bo’ file, which is a dictionary containing
the elements of a brain object saved in the hd5 format using
deepdish
.
#bo.save(fname='brain_object')