Building a brain object
=======================
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.
Load in the required libraries
==============================
.. code:: ipython2
import supereeg as se
import numpy as np
import warnings
warnings.simplefilter("ignore")
%matplotlib inline
Simulate some data
==================
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!
.. code:: ipython2
# 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()
.. image:: brain_objects_files/brain_objects_4_0.png
We’ll also simulate some electrode locations
.. code:: ipython2
locs = se.simulate_locations()
print(locs)
.. parsed-literal::
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
Creating a brain object
=======================
To construct a new brain objects, simply pass the data and locations to
the ``Brain`` class like this:
.. code:: ipython2
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:
.. code:: ipython2
bo.info()
.. parsed-literal::
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:
.. code:: ipython2
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()
.. parsed-literal::
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:
.. code:: ipython2
meta = {
'subjectID' : '123',
'Investigator' : 'Andy',
'Hospital' : 'DHMC'
}
bo = se.Brain(data=data, locs=locs, sample_rate=1000, sessions=sessions, meta=meta)
bo.info()
.. parsed-literal::
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'}
Initialize brain objects
========================
``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:
.. code:: ipython2
nii_bo = se.Brain('example_nifti')
Or:
.. code:: ipython2
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:
.. code:: ipython2
bo_locs = se.load('example_data', field='locs')
The structure of a brain object
===============================
Inside the brain object, the ECoG data are stored in a Pandas DataFrame
that can be accessed with the ``get_data`` function:
.. code:: ipython2
bo.get_data().head()
.. raw:: html
|
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:
.. code:: ipython2
bo.get_locs().head()
.. raw:: html
|
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:
.. code:: ipython2
#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()
.. raw:: html
|
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.
.. code:: ipython2
bo_s = bo.get_slice(sample_inds=[0,1,2], loc_inds=[0,1,2])
bo_s.get_data()
.. raw:: html
|
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
.. code:: ipython2
bo.resample(64)
bo.info()
.. parsed-literal::
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:
.. code:: ipython2
bo.plot_data()
.. image:: brain_objects_files/brain_objects_32_0.png
.. code:: ipython2
bo.plot_locs()
.. image:: brain_objects_files/brain_objects_33_0.png
The other pieces of the brain object are listed below:
.. code:: ipython2
# 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
Brain object methods
====================
There are a few other useful methods on a brain object
``bo.info()``
-------------
This method will give you a summary of the brain object:
.. code:: ipython2
bo.info()
.. parsed-literal::
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.
.. code:: ipython2
bo_f = bo.apply_filter()
``bo.get_data()``
-----------------
.. code:: ipython2
data_array = bo.get_data()
``bo.get_zscore_data()``
------------------------
This method will return a numpy array of the zscored data:
.. code:: ipython2
zdata_array = bo.get_zscore_data()
``bo.get_locs()``
-----------------
This method will return a numpy array of the electrode locations:
.. code:: ipython2
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``.
.. code:: ipython2
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.
.. code:: ipython2
bo.resample(resample_rate=None)
.. parsed-literal::
``bo.plot_data()``
------------------
This method normalizes and plots data from brain object:
.. code:: ipython2
bo.plot_data()
.. image:: brain_objects_files/brain_objects_52_0.png
``bo.plot_locs()``
------------------
This method plots electrode locations from brain object:
.. code:: ipython2
bo_f = se.load('example_filter')
.. code:: ipython2
bo_f.plot_locs()
.. image:: brain_objects_files/brain_objects_55_0.png
``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.
.. code:: ipython2
# 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)
.. image:: brain_objects_files/brain_objects_57_0.png
``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``.
.. code:: ipython2
#bo.save(fname='brain_object')