Skip to content

Commit

Permalink
update preload to support new single .set EEGLAB format
Browse files Browse the repository at this point in the history
  • Loading branch information
dungscout96 committed Jan 14, 2025
1 parent 5fec4e0 commit b6871cc
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
26 changes: 21 additions & 5 deletions mne/io/eeglab/_eeglab.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
except ImportError: # scipy < 1.8
from scipy.io.matlab.mio5 import MatlabFunction
from scipy.io.matlab.mio5_params import MatlabOpaque
from scipy.io import loadmat
from scipy.io import loadmat, whosmat

from ...utils import _import_pymatreader_funcs

Expand Down Expand Up @@ -71,13 +71,29 @@ def _check_for_scipy_mat_struct(data): # taken from pymatreader.utils
return data


def _readmat(fname, uint16_codec=None):
def _readmat(fname, uint16_codec=None, preload=False):
try:
read_mat = _import_pymatreader_funcs("EEGLAB I/O")
except RuntimeError: # pymatreader not installed
eeg = loadmat(
fname, squeeze_me=True, mat_dtype=False, uint16_codec=uint16_codec
)
if preload:
eeg = loadmat(
fname, squeeze_me=True, mat_dtype=False, uint16_codec=uint16_codec
)
else:
info_fields = ['setname', 'filename', 'filepath', 'subject', 'group', 'condition', 'session', 'comments', 'nbchan', 'trials', 'pnts', 'srate', 'xmin', 'xmax', 'times', 'icaact', 'icawinv', 'icasphere', 'icaweights', 'icachansind', 'chanlocs', 'urchanlocs', 'chaninfo', 'ref', 'event', 'urevent', 'eventdescription', 'epoch', 'epochdescription', 'reject', 'stats', 'specdata', 'specicaact', 'splinefile', 'icasplinefile', 'dipfit', 'history', 'saved', 'etc']
eeg = loadmat(
fname, variable_names=info_fields, squeeze_me=True, mat_dtype=False, uint16_codec=uint16_codec
)
variables = whosmat(str(fname))
for var in variables:
if var[0] == 'data':
numeric_types = ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'single', 'double']
if var[2] in numeric_types:
# in preload=False mode and data is in .set file
eeg['data'] = str(fname)
else:
eeg['data'] = loadmat(fname, variable_names=['data'], squeeze_me=True, mat_dtype=False, uint16_codec=uint16_codec)
break
return _check_for_scipy_mat_struct(eeg)
else:
return read_mat(fname, uint16_codec=uint16_codec)
29 changes: 10 additions & 19 deletions mne/io/eeglab/eeglab.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,20 @@
def _check_eeglab_fname(fname, dataname):
"""Check whether the filename is valid.
Check if the file extension is ``.fdt`` (older ``.dat`` being invalid) or
whether the ``EEG.data`` filename exists. If ``EEG.data`` file is absent
the set file name with .set changed to .fdt is checked.
Check if the file extension is ``.fdt`` (older ``.dat`` being invalid)
or ``.set`` (new EEGLAB format) or whether the ``EEG.data`` filename exists.
If ``EEG.data`` file is absent the set file name with .set changed to .fdt is checked.
"""
fmt = str(op.splitext(dataname)[-1])
if fmt == ".dat":
raise NotImplementedError(
"Old data format .dat detected. Please update your EEGLAB "
"version and resave the data in .fdt format"
)

if fmt != ".set" and fmt != ".fdt":
raise ValueError(
"The file extension must be .set or .fdt, not {}".format(fmt)
)
basedir = op.dirname(fname)
data_fname = op.join(basedir, dataname)
if not op.exists(data_fname):
Expand All @@ -68,10 +71,10 @@ def _check_eeglab_fname(fname, dataname):
return data_fname


def _check_load_mat(fname, uint16_codec):
def _check_load_mat(fname, uint16_codec, preload=False):
"""Check if the mat struct contains 'EEG'."""
fname = _check_fname(fname, "read", True)
eeg = _readmat(fname, uint16_codec=uint16_codec)
eeg = _readmat(fname, uint16_codec=uint16_codec, preload=preload)
if "ALLEEG" in eeg:
raise NotImplementedError(
"Loading an ALLEEG array is not supported. Please contact"
Expand Down Expand Up @@ -302,8 +305,6 @@ def read_raw_eeglab(
If 'auto', the channel names containing ``EOG`` or ``EYE`` are used.
Defaults to empty tuple.
%(preload)s
Note that ``preload=False`` will be effective only if the data is
stored in a separate binary file.
%(uint16_codec)s
%(montage_units)s
Expand Down Expand Up @@ -420,8 +421,6 @@ class RawEEGLAB(BaseRaw):
If 'auto', the channel names containing ``EOG`` or ``EYE`` are used.
Defaults to empty tuple.
%(preload)s
Note that preload=False will be effective only if the data is stored
in a separate binary file.
%(uint16_codec)s
%(montage_units)s
%(verbose)s
Expand All @@ -447,7 +446,7 @@ def __init__(
verbose=None,
):
input_fname = str(_check_fname(input_fname, "read", True, "input_fname"))
eeg = _check_load_mat(input_fname, uint16_codec)
eeg = _check_load_mat(input_fname, uint16_codec, preload)
if eeg.trials != 1:
raise TypeError(
f"The number of trials is {eeg.trials:d}. It must be 1 for raw"
Expand All @@ -472,14 +471,6 @@ def __init__(
verbose=verbose,
)
else:
if preload is False or isinstance(preload, str):
warn(
"Data will be preloaded. preload=False or a string "
"preload is not supported when the data is stored in "
"the .set file"
)
# can't be done in standard way with preload=True because of
# different reading path (.set file)
if eeg.nbchan == 1 and len(eeg.data.shape) == 1:
n_chan, n_times = [1, eeg.data.shape[0]]
else:
Expand Down

0 comments on commit b6871cc

Please sign in to comment.