コード例 #1
0
ファイル: test_dig.py プロジェクト: aces/EEG2BIDS
def test_dig_pixels(tmp_path):
    """Test dig stored correctly for the Pixels coordinate frame."""
    bids_root = tmp_path / 'bids1'

    # test coordinates in pixels
    bids_path = _bids_path.copy().update(root=bids_root,
                                         datatype='ieeg',
                                         space='Pixels')
    os.makedirs(op.join(bids_root, 'sub-01', 'ses-01', bids_path.datatype),
                exist_ok=True)
    raw_test = raw.copy()
    raw_test.pick_types(eeg=True)
    raw_test.del_proj()
    raw_test.set_channel_types({ch: 'ecog' for ch in raw_test.ch_names})

    mnt = raw_test.get_montage()
    # fake transform to pixel coordinates
    mnt.apply_trans(mne.transforms.Transform('head', 'unknown'))
    _write_dig_bids(bids_path, raw_test, mnt)
    electrodes_path = bids_path.copy().update(task=None,
                                              run=None,
                                              suffix='electrodes',
                                              extension='.tsv')
    coordsystem_path = bids_path.copy().update(task=None,
                                               run=None,
                                               suffix='coordsystem',
                                               extension='.json')
    with pytest.warns(RuntimeWarning,
                      match='not an MNE-Python coordinate frame'):
        _read_dig_bids(electrodes_path, coordsystem_path, bids_path.datatype,
                       raw_test)
    mnt2 = raw_test.get_montage()
    assert mnt2.get_positions()['coord_frame'] == 'unknown'
    assert_almost_equal(
        np.array(list(mnt.get_positions()['ch_pos'].values())),
        np.array(list(mnt2.get_positions()['ch_pos'].values())))
コード例 #2
0
ファイル: read.py プロジェクト: eort/mne-bids
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
コード例 #3
0
ファイル: read.py プロジェクト: kalenkovich/mne-bids
def read_raw_bids(bids_basename,
                  bids_root,
                  kind=None,
                  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_basename : str | BIDSPath
        The base filename of the BIDS compatible files. Typically, this can be
        generated using :func:`mne_bids.make_bids_basename`.
    bids_root : str | pathlib.Path
        Path to root of the BIDS folder
    kind : str | None
        The kind of recording to read. If ``None`` and only one kind (e.g.,
        only EEG or only 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)``.
    verbose : bool
        The verbosity level.

    Returns
    -------
    raw : instance of Raw
        The data as MNE-Python Raw object.

    Raises
    ------
    RuntimeError
        If multiple recording kinds are present in the dataset, but
        ``kind=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 ``kind`` cannot be found in the dataset.

    """
    # convert to BIDS Path
    if isinstance(bids_basename, str):
        params = _parse_bids_filename(bids_basename, verbose)
        bids_basename = BIDSPath(subject=params.get('sub'),
                                 session=params.get('ses'),
                                 recording=params.get('rec'),
                                 acquisition=params.get('acq'),
                                 processing=params.get('proc'),
                                 space=params.get('space'),
                                 run=params.get('run'),
                                 task=params.get('task'))
    sub = bids_basename.subject
    ses = bids_basename.session
    acq = bids_basename.acquisition

    if kind is None:
        kind = _infer_kind(bids_basename=bids_basename,
                           bids_root=bids_root,
                           sub=sub,
                           ses=ses)

    data_dir = make_bids_folders(subject=sub,
                                 session=ses,
                                 kind=kind,
                                 make_dir=False)
    bids_fname = bids_basename.get_bids_fname(kind=kind, bids_root=bids_root)

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

    if extra_params is None:
        extra_params = dict()
    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_fname,
                                          bids_root,
                                          'events.tsv',
                                          allow_fail=True)
    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_fname,
                                            bids_root,
                                            'channels.tsv',
                                            allow_fail=True)
    if channels_fname is not None:
        raw = _handle_channels_reading(channels_fname, bids_fname, raw)

    # Try to find an associated electrodes.tsv and coordsystem.json
    # to get information about the status and type of present channels
    search_modifier = f'acq-{acq}' if acq else ''
    elec_suffix = f'{search_modifier}*_electrodes.tsv'
    coord_suffix = f'{search_modifier}*_coordsystem.json'
    electrodes_fname = _find_matching_sidecar(bids_fname,
                                              bids_root,
                                              suffix=elec_suffix,
                                              allow_fail=True)
    coordsystem_fname = _find_matching_sidecar(bids_fname,
                                               bids_root,
                                               suffix=coord_suffix,
                                               allow_fail=True)
    if electrodes_fname is not None:
        if coordsystem_fname is None:
            raise RuntimeError("BIDS mandates that the coordsystem.json "
                               "should exist if electrodes.tsv does. "
                               "Please create coordsystem.json for"
                               "{}".format(bids_basename))
        if kind in ['meg', 'eeg', 'ieeg']:
            raw = _read_dig_bids(electrodes_fname, coordsystem_fname, raw,
                                 kind, verbose)

    # Try to find an associated sidecar.json to get information about the
    # recording snapshot
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           bids_root,
                                           '{}.json'.format(kind),
                                           allow_fail=True)
    if sidecar_fname is not None:
        raw = _handle_info_reading(sidecar_fname, raw, verbose=verbose)

    # read in associated subject info from participants.tsv
    participants_tsv_fpath = op.join(bids_root, 'participants.tsv')
    subject = f"sub-{bids_basename.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
コード例 #4
0
ファイル: test_dig.py プロジェクト: aces/EEG2BIDS
def test_dig_template(tmp_path):
    """Test that eeg and ieeg dig are stored properly."""
    bids_root = tmp_path / 'bids1'
    for datatype in ('eeg', 'ieeg'):
        (bids_root / 'sub-01' / 'ses-01' / datatype).mkdir(parents=True)

    raw_test = raw.copy().pick_types(eeg=True)

    for datatype in ('eeg', 'ieeg'):
        bids_path = _bids_path.copy().update(root=bids_root, datatype=datatype)
        for coord_frame in BIDS_STANDARD_TEMPLATE_COORDINATE_SYSTEMS:
            bids_path.update(space=coord_frame)
            mnt = montage.copy()
            pos = mnt.get_positions()
            mne_coord_frame = BIDS_TO_MNE_FRAMES.get(coord_frame, None)
            if mne_coord_frame is None:
                mnt.apply_trans(mne.transforms.Transform('head', 'unknown'))
            else:
                mnt.apply_trans(
                    mne.transforms.Transform('head', mne_coord_frame))
            _write_dig_bids(bids_path, raw_test, mnt, acpc_aligned=True)
            electrodes_path = bids_path.copy().update(task=None,
                                                      run=None,
                                                      suffix='electrodes',
                                                      extension='.tsv')
            coordsystem_path = bids_path.copy().update(task=None,
                                                       run=None,
                                                       suffix='coordsystem',
                                                       extension='.json')
            if mne_coord_frame is None:
                with pytest.warns(RuntimeWarning,
                                  match='not an MNE-Python coordinate frame'):
                    _read_dig_bids(electrodes_path, coordsystem_path, datatype,
                                   raw_test)
            else:
                if coord_frame == 'MNI305':  # saved to fsaverage, same
                    electrodes_path.update(space='fsaverage')
                    coordsystem_path.update(space='fsaverage')
                _read_dig_bids(electrodes_path, coordsystem_path, datatype,
                               raw_test)
            mnt2 = raw_test.get_montage()
            pos2 = mnt2.get_positions()
            np.testing.assert_array_almost_equal(
                np.array(list(pos['ch_pos'].values())),
                np.array(list(pos2['ch_pos'].values())))
            if mne_coord_frame is None:
                assert pos2['coord_frame'] == 'unknown'
            else:
                assert pos2['coord_frame'] == mne_coord_frame

    # test MEG
    raw_test = raw.copy()
    for coord_frame in BIDS_STANDARD_TEMPLATE_COORDINATE_SYSTEMS:
        bids_path = _bids_path.copy().update(root=bids_root,
                                             datatype='meg',
                                             space=coord_frame)
        write_raw_bids(raw_test, bids_path)
        raw_test2 = read_raw_bids(bids_path)
        for ch, ch2 in zip(raw.info['chs'], raw_test2.info['chs']):
            np.testing.assert_array_equal(ch['loc'], ch2['loc'])
            assert ch['coord_frame'] == ch2['coord_frame']
コード例 #5
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