Skip to content

Commit

Permalink
WIP add load.cnd()
Browse files Browse the repository at this point in the history
  • Loading branch information
christianbrodbeck committed Jul 9, 2021
1 parent 085698b commit ba860c6
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Functions and modules for loading specific file formats as Eelbrain object:
load.eyelink
load.fiff
load.txt
load.cnd
load.besa


Expand Down
88 changes: 88 additions & 0 deletions eelbrain/_io/cnd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Author: Christian Brodbeck <christianbrodbeck@nyu.edu>
"""Continuous neural data (CND) format used for mTRF-Toolbox"""
from pathlib import Path
from typing import Optional

from mne.externals.pymatreader import read_mat
import numpy

from .._data_obj import Dataset, Factor, NDVar, Sensor, UTS, Var
from .._types import PathArg
from .._utils import ui


FILETYPES = [("CND files", "*.mat")]


def read_cnd(
filename: PathArg = None,
) -> Optional[Dataset]:
"""Load continuous neural data (CND) file used in the mTRF-Toolbox
Parameters
----------
filename
Path to the data file (``*.mat``). If unspecified, open a file dialog.
Notes
-----
There are two types of CND files: EEG and stimulus files.
EEG files will return the following contents:
``eeg``
The EEG data.
``stimIdxs``
Index of the stimulus on the given trial.
Indexes are adjusted for Pyton 0-based indexing.
``condIdxs``
Index of the condition on the given trial (when present).
Indexes are adjusted for Pyton 0-based indexing.
``condition``
Condition label on the given trial (when present).
"""
if filename is None:
path = ui.ask_file("Load CND File", "Select CND file to load as NDVar", FILETYPES)
if not path:
return
else:
path = Path(filename)
if not path.suffix and not path.exists():
path = path.with_suffix('.mat')
data = read_mat(path)
if 'eeg' in data:
# EEG data
locs = numpy.vstack([data['eeg']['chanlocs'][coord] for coord in 'XYZ']).T
sensor = Sensor(locs, data['eeg']['chanlocs']['labels'])
eeg = []
for trial_data in data['eeg']['data']:
uts = UTS(0, 1 / data['eeg']['fs'], trial_data.shape[0])
eeg.append(NDVar(trial_data, (uts, sensor), 'eeg'))
# Extra channels
ds = Dataset({
'eeg': eeg,
'stimIdxs': Var(data['eeg']['stimIdxs'] - 1),
})
if 'reRef' in data['eeg']:
ds.info['reRef'] = data['eeg']['reRef']
if 'condIdxs' in data['eeg']:
ds['condIdxs'] = Var(data['eeg']['condIdxs'] - 1)
labels = dict(enumerate(data['eeg']['condNames'], 1))
ds['condition'] = Factor(data['eeg']['condIdxs'], labels=labels)
return ds
if 'stim' in data:
ds = Dataset()
for stim_data in data['stim']:
if 'fs' in stim_data:
key = Dataset.as_key(stim_data['name'])
trials = []
for trial_data in stim_data['data']:
uts = UTS(0, 1 / stim_data['fs'], trial_data.shape[0])
trials.append(NDVar(trial_data, uts))
ds[key] = trials
else:
ds.info[stim_data['name']] = stim_data['data']
return ds
raise IOError("File contains neither 'eeg' or 'stim' entry")



1 change: 1 addition & 0 deletions eelbrain/load/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from . import txt

from .txt import tsv
from .._io.cnd import read_cnd as cnd
from .._io.feather import load_feather as feather
from .._io.pickle import unpickle, update_subjects_dir, convert_pickle_protocol
from .._io.pyarrow_context import load_arrow as arrow
Expand Down

0 comments on commit ba860c6

Please sign in to comment.