Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH : add units parameter to read_raw_edf in case units is missing from the file #11099

Merged
merged 5 commits into from
Aug 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Enhancements
- The ``trans`` parameter in :func:`mne.make_field_map` now accepts a :class:`~pathlib.Path` object, and uses standardised loading logic (:gh:`10784` by :newcontrib:`Andrew Quinn`)
- Add HTML representation for `~mne.Evoked` in Jupyter Notebooks (:gh:`11075` by `Valerii Chirkov`_ and `Andrew Quinn`_)
- Allow :func:`mne.beamformer.make_dics` to take ``pick_ori='vector'`` to compute vector source estimates (:gh:`19080` by `Alex Rockhill`_)
- Add ``units`` parameter to :func:`mne.io.read_raw_edf` in case units are missing from the file (:gh:`11099` by `Alex Gramfort`_)
- Add ``on_missing`` functionality to all of our classes that have a ``drop_channels`` method, to control what happens when channel names are not in the object (:gh:`11077` by `Andrew Quinn`_)

Bugs
Expand Down
31 changes: 25 additions & 6 deletions mne/io/edf/edf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from ...utils import verbose, logger, warn
from ..utils import _blk_read_lims, _mult_cal_one
from ..base import BaseRaw
from ..base import BaseRaw, _get_scaling
from ..meas_info import _empty_info, _unique_channel_names
from ..constants import FIFF
from ...filter import resample
Expand Down Expand Up @@ -83,6 +83,7 @@ class RawEDF(BaseRaw):

.. versionadded:: 1.1
%(preload)s
%(units_edf_bdf_io)s
%(verbose)s

See Also
Expand Down Expand Up @@ -132,14 +133,30 @@ class RawEDF(BaseRaw):
@verbose
def __init__(self, input_fname, eog=None, misc=None, stim_channel='auto',
exclude=(), infer_types=False, preload=False, include=None,
verbose=None):
units=None, *, verbose=None):
logger.info('Extracting EDF parameters from {}...'.format(input_fname))
input_fname = os.path.abspath(input_fname)
info, edf_info, orig_units = _get_info(input_fname, stim_channel, eog,
misc, exclude, infer_types,
preload, include)
logger.info('Creating raw.info structure...')

if units is not None and isinstance(units, str):
units = {ch_name: units for ch_name in info['ch_names']}
elif units is None:
units = dict()

for k, (this_ch, this_unit) in enumerate(orig_units.items()):
if this_unit != "" and this_unit in units:
raise ValueError(f'Unit for channel {this_ch} is present in '
'the file. Cannot overwrite it with the '
'units argument.')
if this_unit == "" and this_ch in units:
orig_units[this_ch] = units[this_ch]
ch_type = edf_info["ch_types"][k]
scaling = _get_scaling(ch_type.lower(), orig_units[this_ch])
edf_info["units"][k] /= scaling

# Raw attributes
last_samps = [edf_info['nsamples'] - 1]
super().__init__(info, preload, filenames=[input_fname],
Expand Down Expand Up @@ -1282,7 +1299,7 @@ def _find_tal_idx(ch_names):
@fill_doc
def read_raw_edf(input_fname, eog=None, misc=None, stim_channel='auto',
exclude=(), infer_types=False, include=None, preload=False,
verbose=None):
units=None, *, verbose=None):
"""Reader function for EDF or EDF+ files.

Parameters
Expand Down Expand Up @@ -1322,6 +1339,7 @@ def read_raw_edf(input_fname, eog=None, misc=None, stim_channel='auto',

.. versionadded:: 1.1
%(preload)s
%(units_edf_bdf_io)s
%(verbose)s

Returns
Expand Down Expand Up @@ -1384,13 +1402,13 @@ def read_raw_edf(input_fname, eog=None, misc=None, stim_channel='auto',
return RawEDF(input_fname=input_fname, eog=eog, misc=misc,
stim_channel=stim_channel, exclude=exclude,
infer_types=infer_types, preload=preload, include=include,
verbose=verbose)
units=units, verbose=verbose)


@fill_doc
def read_raw_bdf(input_fname, eog=None, misc=None, stim_channel='auto',
exclude=(), infer_types=False, include=None, preload=False,
verbose=None):
units=None, *, verbose=None):
"""Reader function for BDF files.

Parameters
Expand Down Expand Up @@ -1430,6 +1448,7 @@ def read_raw_bdf(input_fname, eog=None, misc=None, stim_channel='auto',

.. versionadded:: 1.1
%(preload)s
%(units_edf_bdf_io)s
%(verbose)s

Returns
Expand Down Expand Up @@ -1485,7 +1504,7 @@ def read_raw_bdf(input_fname, eog=None, misc=None, stim_channel='auto',
return RawEDF(input_fname=input_fname, eog=eog, misc=misc,
stim_channel=stim_channel, exclude=exclude,
infer_types=infer_types, preload=preload, include=include,
verbose=verbose)
units=units, verbose=verbose)


@fill_doc
Expand Down
8 changes: 8 additions & 0 deletions mne/utils/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3504,6 +3504,14 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
channel-type-specific default unit.
"""

docdict['units_edf_bdf_io'] = """
units : dict | str
The units of the channels as stored in the file. This argument
is useful only if the units are missing from the original file.
If a dict, it must map a channel name to its unit, and if str
it is assumed that all channels have the same units.
"""

docdict['units_topomap'] = """
units : dict | str | None
The unit of the channel type used for colorbar label. If
Expand Down