Example #1
0
def read_raw_bids(bids_path, extra_params=None, verbose=True):
    """Read BIDS compatible data.

    Will attempt to read associated events.tsv and channels.tsv files to
    populate the returned raw object with raw.annotations and raw.info['bads'].

    Parameters
    ----------
    bids_path : mne_bids.BIDSPath
        The file to read. The :class:`mne_bids.BIDSPath` instance passed here
        **must** have the ``.root`` attribute set. The ``.datatype`` attribute
        **may** be set. If ``.datatype`` is not set and only one data type
        (e.g., only EEG or MEG data) is present in the dataset, it will be
        selected automatically.
    extra_params : None | dict
        Extra parameters to be passed to MNE read_raw_* functions.
        If a dict, for example: ``extra_params=dict(allow_maxshield=True)``.
        Note that the ``exclude`` parameter, which is supported by some
        MNE-Python readers, is not supported; instead, you need to subset
        your channels **after** reading.
    verbose : bool
        The verbosity level.

    Returns
    -------
    raw : mne.io.Raw
        The data as MNE-Python Raw object.

    Raises
    ------
    RuntimeError
        If multiple recording data types are present in the dataset, but
        ``datatype=None``.

    RuntimeError
        If more than one data files exist for the specified recording.

    RuntimeError
        If no data file in a supported format can be located.

    ValueError
        If the specified ``datatype`` cannot be found in the dataset.

    """
    if not isinstance(bids_path, BIDSPath):
        raise RuntimeError('"bids_path" must be a BIDSPath object. Please '
                           'instantiate using mne_bids.BIDSPath().')

    bids_path = bids_path.copy()
    sub = bids_path.subject
    ses = bids_path.session
    bids_root = bids_path.root
    datatype = bids_path.datatype
    suffix = bids_path.suffix

    # check root available
    if bids_root is None:
        raise ValueError('The root of the "bids_path" must be set. '
                         'Please use `bids_path.update(root="<root>")` '
                         'to set the root of the BIDS folder to read.')

    # infer the datatype and suffix if they are not present in the BIDSPath
    if datatype is None:
        datatype = _infer_datatype(root=bids_root, sub=sub, ses=ses)
        bids_path.update(datatype=datatype)
    if suffix is None:
        bids_path.update(suffix=datatype)

    data_dir = bids_path.directory
    bids_fname = bids_path.fpath.name

    if op.splitext(bids_fname)[1] == '.pdf':
        bids_raw_folder = op.join(data_dir, f'{bids_path.basename}')
        bids_fpath = glob.glob(op.join(bids_raw_folder, 'c,rf*'))[0]
        config = op.join(bids_raw_folder, 'config')
    else:
        bids_fpath = op.join(data_dir, bids_fname)
        config = None

    if extra_params is None:
        extra_params = dict()
    elif 'exclude' in extra_params:
        del extra_params['exclude']
        logger.info('"exclude" parameter is not supported by read_raw_bids')

    raw = _read_raw(bids_fpath,
                    electrode=None,
                    hsp=None,
                    hpi=None,
                    config=config,
                    verbose=None,
                    **extra_params)

    # Try to find an associated events.tsv to get information about the
    # events in the recorded data
    events_fname = _find_matching_sidecar(bids_path,
                                          suffix='events',
                                          extension='.tsv',
                                          on_error='warn')
    if events_fname is not None:
        raw = _handle_events_reading(events_fname, raw)

    # Try to find an associated channels.tsv to get information about the
    # status and type of present channels
    channels_fname = _find_matching_sidecar(bids_path,
                                            suffix='channels',
                                            extension='.tsv',
                                            on_error='warn')
    if channels_fname is not None:
        raw = _handle_channels_reading(channels_fname, raw)

    # Try to find an associated electrodes.tsv and coordsystem.json
    # to get information about the status and type of present channels
    on_error = 'warn' if suffix == 'ieeg' else 'ignore'
    electrodes_fname = _find_matching_sidecar(bids_path,
                                              suffix='electrodes',
                                              extension='.tsv',
                                              on_error=on_error)
    coordsystem_fname = _find_matching_sidecar(bids_path,
                                               suffix='coordsystem',
                                               extension='.json',
                                               on_error=on_error)
    if electrodes_fname is not None:
        if coordsystem_fname is None:
            raise RuntimeError(f"BIDS mandates that the coordsystem.json "
                               f"should exist if electrodes.tsv does. "
                               f"Please create coordsystem.json for"
                               f"{bids_path.basename}")
        if datatype in ['meg', 'eeg', 'ieeg']:
            raw = _read_dig_bids(electrodes_fname, coordsystem_fname, raw,
                                 datatype, verbose)

    # Try to find an associated sidecar .json to get information about the
    # recording snapshot
    sidecar_fname = _find_matching_sidecar(bids_path,
                                           suffix=datatype,
                                           extension='.json',
                                           on_error='warn')
    if sidecar_fname is not None:
        raw = _handle_info_reading(sidecar_fname, raw, verbose=verbose)

    # read in associated scans filename
    scans_fname = BIDSPath(subject=bids_path.subject,
                           session=bids_path.session,
                           suffix='scans',
                           extension='.tsv',
                           root=bids_path.root).fpath
    if scans_fname.exists():
        raw = _handle_scans_reading(scans_fname,
                                    raw,
                                    bids_path,
                                    verbose=verbose)

    # read in associated subject info from participants.tsv
    participants_tsv_fpath = op.join(bids_root, 'participants.tsv')
    subject = f"sub-{bids_path.subject}"
    if op.exists(participants_tsv_fpath):
        raw = _handle_participants_reading(participants_tsv_fpath,
                                           raw,
                                           subject,
                                           verbose=verbose)
    else:
        warn("Participants file not found for {}... Not reading "
             "in any particpants.tsv data.".format(bids_fname))

    return raw
Example #2
0
def read_raw_bids(bids_path, extra_params=None, verbose=None):
    """Read BIDS compatible data.

    Will attempt to read associated events.tsv and channels.tsv files to
    populate the returned raw object with raw.annotations and raw.info['bads'].

    Parameters
    ----------
    bids_path : BIDSPath
        The file to read. The :class:`mne_bids.BIDSPath` instance passed here
        **must** have the ``.root`` attribute set. The ``.datatype`` attribute
        **may** be set. If ``.datatype`` is not set and only one data type
        (e.g., only EEG or MEG data) is present in the dataset, it will be
        selected automatically.

        .. note::
           If ``bids_path`` points to a symbolic link of a ``.fif`` file
           without a ``split`` entity, the link will be resolved before
           reading.

    extra_params : None | dict
        Extra parameters to be passed to MNE read_raw_* functions.
        Note that the ``exclude`` parameter, which is supported by some
        MNE-Python readers, is not supported; instead, you need to subset
        your channels **after** reading.
    %(verbose)s

    Returns
    -------
    raw : mne.io.Raw
        The data as MNE-Python Raw object.

    Raises
    ------
    RuntimeError
        If multiple recording data types are present in the dataset, but
        ``datatype=None``.

    RuntimeError
        If more than one data files exist for the specified recording.

    RuntimeError
        If no data file in a supported format can be located.

    ValueError
        If the specified ``datatype`` cannot be found in the dataset.

    """
    if not isinstance(bids_path, BIDSPath):
        raise RuntimeError('"bids_path" must be a BIDSPath object. Please '
                           'instantiate using mne_bids.BIDSPath().')

    bids_path = bids_path.copy()
    sub = bids_path.subject
    ses = bids_path.session
    bids_root = bids_path.root
    datatype = bids_path.datatype
    suffix = bids_path.suffix

    # check root available
    if bids_root is None:
        raise ValueError('The root of the "bids_path" must be set. '
                         'Please use `bids_path.update(root="<root>")` '
                         'to set the root of the BIDS folder to read.')

    # infer the datatype and suffix if they are not present in the BIDSPath
    if datatype is None:
        datatype = _infer_datatype(root=bids_root, sub=sub, ses=ses)
        bids_path.update(datatype=datatype)
    if suffix is None:
        bids_path.update(suffix=datatype)

    if bids_path.fpath.suffix == '.pdf':
        bids_raw_folder = bids_path.directory / f'{bids_path.basename}'
        raw_path = list(bids_raw_folder.glob('c,rf*'))[0]
        config_path = bids_raw_folder / 'config'
    else:
        raw_path = bids_path.fpath
        # Resolve for FIFF files
        if (raw_path.suffix == '.fif' and bids_path.split is None
                and raw_path.is_symlink()):
            target_path = raw_path.resolve()
            logger.info(f'Resolving symbolic link: '
                        f'{raw_path} -> {target_path}')
            raw_path = target_path
        config_path = None

    # Special-handle EDF filenames: we accept upper- and lower-case extensions
    if raw_path.suffix.lower() == '.edf':
        for extension in ('.edf', '.EDF'):
            candidate_path = raw_path.with_suffix(extension)
            if candidate_path.exists():
                raw_path = candidate_path
                break

    if not raw_path.exists():
        raise FileNotFoundError(f'File does not exist: {raw_path}')
    if config_path is not None and not config_path.exists():
        raise FileNotFoundError(f'config directory not found: {config_path}')

    if extra_params is None:
        extra_params = dict()
    elif 'exclude' in extra_params:
        del extra_params['exclude']
        logger.info('"exclude" parameter is not supported by read_raw_bids')

    if raw_path.suffix == '.fif' and 'allow_maxshield' not in extra_params:
        extra_params['allow_maxshield'] = True
    raw = _read_raw(raw_path,
                    electrode=None,
                    hsp=None,
                    hpi=None,
                    config_path=config_path,
                    **extra_params)

    # Try to find an associated events.tsv to get information about the
    # events in the recorded data
    events_fname = _find_matching_sidecar(bids_path,
                                          suffix='events',
                                          extension='.tsv',
                                          on_error='warn')
    if events_fname is not None:
        raw = _handle_events_reading(events_fname, raw)

    # Try to find an associated channels.tsv to get information about the
    # status and type of present channels
    channels_fname = _find_matching_sidecar(bids_path,
                                            suffix='channels',
                                            extension='.tsv',
                                            on_error='warn')
    if channels_fname is not None:
        raw = _handle_channels_reading(channels_fname, raw)

    # Try to find an associated electrodes.tsv and coordsystem.json
    # to get information about the status and type of present channels
    on_error = 'warn' if suffix == 'ieeg' else 'ignore'
    electrodes_fname = _find_matching_sidecar(bids_path,
                                              suffix='electrodes',
                                              extension='.tsv',
                                              on_error=on_error)
    coordsystem_fname = _find_matching_sidecar(bids_path,
                                               suffix='coordsystem',
                                               extension='.json',
                                               on_error=on_error)
    if electrodes_fname is not None:
        if coordsystem_fname is None:
            raise RuntimeError(f"BIDS mandates that the coordsystem.json "
                               f"should exist if electrodes.tsv does. "
                               f"Please create coordsystem.json for"
                               f"{bids_path.basename}")
        if datatype in ['meg', 'eeg', 'ieeg']:
            _read_dig_bids(electrodes_fname,
                           coordsystem_fname,
                           raw=raw,
                           datatype=datatype)

    # Try to find an associated sidecar .json to get information about the
    # recording snapshot
    sidecar_fname = _find_matching_sidecar(bids_path,
                                           suffix=datatype,
                                           extension='.json',
                                           on_error='warn')
    if sidecar_fname is not None:
        raw = _handle_info_reading(sidecar_fname, raw)

    # read in associated scans filename
    scans_fname = BIDSPath(subject=bids_path.subject,
                           session=bids_path.session,
                           suffix='scans',
                           extension='.tsv',
                           root=bids_path.root).fpath

    if scans_fname.exists():
        raw = _handle_scans_reading(scans_fname, raw, bids_path)

    # read in associated subject info from participants.tsv
    participants_tsv_path = bids_root / 'participants.tsv'
    subject = f"sub-{bids_path.subject}"
    if op.exists(participants_tsv_path):
        raw = _handle_participants_reading(
            participants_fname=participants_tsv_path, raw=raw, subject=subject)
    else:
        warn(f"participants.tsv file not found for {raw_path}")

    assert raw.annotations.orig_time == raw.info['meas_date']
    return raw