Exemple #1
0
def _write_dig_bids(bids_path, raw, overwrite=False, verbose=True):
    """Write BIDS formatted DigMontage from Raw instance.

    Handles coordinatesystem.json and electrodes.tsv writing
    from DigMontage.

    Parameters
    ----------
    bids_path : BIDSPath
        Path in the BIDS dataset to save the ``electrodes.tsv``
        and ``coordsystem.json`` file for. ``datatype``
        attribute must be ``eeg``, or ``ieeg``. For ``meg``
        data, ``electrodes.tsv`` are not saved.
    raw : instance of Raw
        The data as MNE-Python Raw object.
    overwrite : bool
        Whether to overwrite the existing file.
        Defaults to False.
    verbose : bool
        Set verbose output to true or false.
    """
    # write electrodes data for iEEG and EEG
    unit = "m"  # defaults to meters

    # get coordinate frame from digMontage
    digpoint = raw.info['dig'][0]
    if any(digpoint['coord_frame'] != _digpoint['coord_frame']
           for _digpoint in raw.info['dig']):
        warn("Not all digpoints have the same coordinate frame. "
             "Skipping electrodes.tsv writing...")
        return

    # get the accepted mne-python coordinate frames
    coord_frame_int = int(digpoint['coord_frame'])
    mne_coord_frame = MNE_FRAME_TO_STR.get(coord_frame_int, None)
    coord_frame = MNE_TO_BIDS_FRAMES.get(mne_coord_frame, None)

    # create electrodes/coordsystem files using a subset of entities
    # that are specified for these files in the specification
    coord_file_entities = {
        'root': bids_path.root,
        'datatype': bids_path.datatype,
        'subject': bids_path.subject,
        'session': bids_path.session,
        'acquisition': bids_path.acquisition,
        'space': bids_path.space
    }
    datatype = bids_path.datatype
    electrodes_path = BIDSPath(**coord_file_entities, suffix='electrodes',
                               extension='.tsv')
    coordsystem_path = BIDSPath(**coord_file_entities, suffix='coordsystem',
                                extension='.json')

    if verbose:
        print("Writing electrodes file to... ", electrodes_path)
        print("Writing coordsytem file to... ", coordsystem_path)

    if datatype == "ieeg":
        if coord_frame is not None:
            # XXX: To improve when mne-python allows coord_frame='unknown'
            if coord_frame not in BIDS_IEEG_COORDINATE_FRAMES:
                coordsystem_path.update(space=coord_frame)
                electrodes_path.update(space=coord_frame)
                coord_frame = 'Other'

            # Now write the data to the elec coords and the coordsystem
            _electrodes_tsv(raw, electrodes_path,
                            datatype, overwrite, verbose)
            _coordsystem_json(raw=raw, unit=unit, hpi_coord_system='n/a',
                              sensor_coord_system=coord_frame,
                              fname=coordsystem_path, datatype=datatype,
                              overwrite=overwrite, verbose=verbose)
        else:
            # default coordinate frame to mri if not available
            warn("Coordinate frame of iEEG coords missing/unknown "
                 "for {}. Skipping reading "
                 "in of montage...".format(electrodes_path))
    elif datatype == 'eeg':
        # We only write EEG electrodes.tsv and coordsystem.json
        # if we have LPA, RPA, and NAS available to rescale to a known
        # coordinate system frame
        coords = _extract_landmarks(raw.info['dig'])
        landmarks = set(['RPA', 'NAS', 'LPA']) == set(list(coords.keys()))

        # XXX: to be improved to allow rescaling if landmarks are present
        # mne-python automatically converts unknown coord frame to head
        if coord_frame_int == FIFF.FIFFV_COORD_HEAD and landmarks:
            # Now write the data
            _electrodes_tsv(raw, electrodes_path, datatype,
                            overwrite, verbose)
            _coordsystem_json(raw=raw, unit='m', hpi_coord_system='n/a',
                              sensor_coord_system='CapTrak',
                              fname=coordsystem_path, datatype=datatype,
                              overwrite=overwrite, verbose=verbose)
        else:
            warn("Skipping EEG electrodes.tsv... "
                 "Setting montage not possible if anatomical "
                 "landmarks (NAS, LPA, RPA) are missing, "
                 "and coord_frame is not 'head'.")
Exemple #2
0
def _write_dig_bids(bids_path,
                    raw,
                    montage=None,
                    acpc_aligned=False,
                    overwrite=False):
    """Write BIDS formatted DigMontage from Raw instance.

    Handles coordinatesystem.json and electrodes.tsv writing
    from DigMontage.

    Parameters
    ----------
    bids_path : mne_bids.BIDSPath
        Path in the BIDS dataset to save the ``electrodes.tsv``
        and ``coordsystem.json`` file for. ``datatype``
        attribute must be ``eeg``, or ``ieeg``. For ``meg``
        data, ``electrodes.tsv`` are not saved.
    raw : mne.io.Raw
        The data as MNE-Python Raw object.
    montage : mne.channels.DigMontage | None
        The montage to use rather than the one in ``raw`` if it
        must be transformed from the "head" coordinate frame.
    acpc_aligned : bool
        Whether "mri" space is aligned to ACPC.
    overwrite : bool
        Whether to overwrite the existing file.
        Defaults to False.

    """
    # write electrodes data for iEEG and EEG
    unit = "m"  # defaults to meters

    if montage is None:
        montage = raw.get_montage()
    else:
        # prevent transformation back to "head", only should be used
        # in this specific circumstance
        if bids_path.datatype == 'ieeg':
            montage.remove_fiducials()
        raw.set_montage(montage)

    # get coordinate frame from digMontage
    digpoint = montage.dig[0]
    if any(digpoint['coord_frame'] != _digpoint['coord_frame']
           for _digpoint in montage.dig):
        warn("Not all digpoints have the same coordinate frame. "
             "Skipping electrodes.tsv writing...")
        return

    # get the accepted mne-python coordinate frames
    coord_frame_int = int(digpoint['coord_frame'])
    mne_coord_frame = MNE_FRAME_TO_STR.get(coord_frame_int, None)
    coord_frame = MNE_TO_BIDS_FRAMES.get(mne_coord_frame, None)

    if bids_path.datatype == 'ieeg' and mne_coord_frame == 'mri':
        if acpc_aligned:
            coord_frame = 'ACPC'
        else:
            raise RuntimeError(
                '`acpc_aligned` is False, if your T1 is not aligned '
                'to ACPC and the coordinates are in fact in ACPC '
                'space there will be no way to relate the coordinates '
                'to the T1. If the T1 is ACPC-aligned, use '
                '`acpc_aligned=True`')

    # create electrodes/coordsystem files using a subset of entities
    # that are specified for these files in the specification
    coord_file_entities = {
        'root': bids_path.root,
        'datatype': bids_path.datatype,
        'subject': bids_path.subject,
        'session': bids_path.session,
        'acquisition': bids_path.acquisition,
        'space': bids_path.space
    }
    datatype = bids_path.datatype
    electrodes_path = BIDSPath(**coord_file_entities,
                               suffix='electrodes',
                               extension='.tsv')
    coordsystem_path = BIDSPath(**coord_file_entities,
                                suffix='coordsystem',
                                extension='.json')

    logger.info(f'Writing electrodes file to... {electrodes_path}')
    logger.info(f'Writing coordsytem file to... {coordsystem_path}')

    if datatype == 'ieeg':
        if coord_frame is not None:
            # XXX: To improve when mne-python allows coord_frame='unknown'
            # coordinate frame is either
            coordsystem_path.update(space=coord_frame)
            electrodes_path.update(space=coord_frame)

            # Now write the data to the elec coords and the coordsystem
            _write_electrodes_tsv(raw, electrodes_path, datatype, overwrite)
            _write_coordsystem_json(raw=raw,
                                    unit=unit,
                                    hpi_coord_system='n/a',
                                    sensor_coord_system=(coord_frame,
                                                         mne_coord_frame),
                                    fname=coordsystem_path,
                                    datatype=datatype,
                                    overwrite=overwrite)
        else:
            # default coordinate frame to mri if not available
            warn("Coordinate frame of iEEG coords missing/unknown "
                 "for {}. Skipping reading "
                 "in of montage...".format(electrodes_path))
    elif datatype == 'eeg':
        # We only write EEG electrodes.tsv and coordsystem.json
        # if we have LPA, RPA, and NAS available to rescale to a known
        # coordinate system frame
        coords = _extract_landmarks(raw.info['dig'])
        landmarks = set(['RPA', 'NAS', 'LPA']) == set(list(coords.keys()))

        # XXX: to be improved to allow rescaling if landmarks are present
        # mne-python automatically converts unknown coord frame to head
        if coord_frame_int == FIFF.FIFFV_COORD_HEAD and landmarks:
            # Now write the data
            _write_electrodes_tsv(raw, electrodes_path, datatype, overwrite)
            _write_coordsystem_json(raw=raw,
                                    unit='m',
                                    hpi_coord_system='n/a',
                                    sensor_coord_system='CapTrak',
                                    fname=coordsystem_path,
                                    datatype=datatype,
                                    overwrite=overwrite)
        else:
            warn("Skipping EEG electrodes.tsv... "
                 "Setting montage not possible if anatomical "
                 "landmarks (NAS, LPA, RPA) are missing, "
                 "and coord_frame is not 'head'.")
Exemple #3
0
def _write_dig_bids(bids_path,
                    raw,
                    montage=None,
                    acpc_aligned=False,
                    overwrite=False):
    """Write BIDS formatted DigMontage from Raw instance.

    Handles coordsystem.json and electrodes.tsv writing
    from DigMontage.

    Parameters
    ----------
    bids_path : BIDSPath
        Path in the BIDS dataset to save the ``electrodes.tsv``
        and ``coordsystem.json`` file for. ``datatype``
        attribute must be ``eeg``, or ``ieeg``. For ``meg``
        data, ``electrodes.tsv`` are not saved.
    raw : mne.io.Raw
        The data as MNE-Python Raw object.
    montage : mne.channels.DigMontage | None
        The montage to use rather than the one in ``raw`` if it
        must be transformed from the "head" coordinate frame.
    acpc_aligned : bool
        Whether "mri" space is aligned to ACPC.
    overwrite : bool
        Whether to overwrite the existing file.
        Defaults to False.

    """
    # write electrodes data for iEEG and EEG
    unit = "m"  # defaults to meters

    if montage is None:
        montage = raw.get_montage()
    else:  # assign montage to raw but supress any coordinate transforms
        montage = montage.copy()  # don't modify original
        montage_coord_frame = montage.get_positions()['coord_frame']
        fids = [
            d for d in montage.dig  # save to add back
            if d['kind'] == FIFF.FIFFV_POINT_CARDINAL
        ]
        montage.remove_fiducials()  # prevent coordinate transform
        with warnings.catch_warnings():
            warnings.filterwarnings(action='ignore',
                                    category=RuntimeWarning,
                                    message='.*nasion not found',
                                    module='mne')
            raw.set_montage(montage)
        for ch in raw.info['chs']:
            ch['coord_frame'] = MNE_STR_TO_FRAME[montage_coord_frame]
        for d in raw.info['dig']:
            d['coord_frame'] = MNE_STR_TO_FRAME[montage_coord_frame]
        with raw.info._unlock():  # add back fiducials
            raw.info['dig'] = fids + raw.info['dig']

    # get the accepted mne-python coordinate frames
    coord_frame_int = int(montage.dig[0]['coord_frame'])
    mne_coord_frame = MNE_FRAME_TO_STR.get(coord_frame_int, None)
    coord_frame = MNE_TO_BIDS_FRAMES.get(mne_coord_frame, None)

    if coord_frame == 'CapTrak' and bids_path.datatype in ('eeg', 'nirs'):
        pos = raw.get_montage().get_positions()
        if any([pos[fid_key] is None for fid_key in ('nasion', 'lpa', 'rpa')]):
            raise RuntimeError("'head' coordinate frame must contain nasion "
                               "and left and right pre-auricular point "
                               "landmarks")

    if bids_path.datatype == 'ieeg' and bids_path.space in (None, 'ACPC') and \
            mne_coord_frame == 'ras':
        if not acpc_aligned:
            raise RuntimeError(
                '`acpc_aligned` is False, if your T1 is not aligned '
                'to ACPC and the coordinates are in fact in ACPC '
                'space there will be no way to relate the coordinates '
                'to the T1. If the T1 is ACPC-aligned, use '
                '`acpc_aligned=True`')
        coord_frame = 'ACPC'

    if bids_path.space is None:  # no space, use MNE coord frame
        if coord_frame is None:  # if no MNE coord frame, skip
            warn("Coordinate frame could not be inferred from the raw object "
                 "and the BIDSPath.space was none, skipping the writing of "
                 "channel positions")
            return
    else:  # either a space and an MNE coord frame or just a space
        if coord_frame is None:  # just a space, use that
            coord_frame = bids_path.space
        else:  # space and raw have coordinate frame, check match
            if bids_path.space != coord_frame and not (
                    coord_frame == 'fsaverage'
                    and bids_path.space == 'MNI305'):  # fsaverage == MNI305
                raise ValueError('Coordinates in the raw object or montage '
                                 f'are in the {coord_frame} coordinate '
                                 'frame but BIDSPath.space is '
                                 f'{bids_path.space}')

    # create electrodes/coordsystem files using a subset of entities
    # that are specified for these files in the specification
    coord_file_entities = {
        'root': bids_path.root,
        'datatype': bids_path.datatype,
        'subject': bids_path.subject,
        'session': bids_path.session,
        'acquisition': bids_path.acquisition,
        'space': None if bids_path.datatype == 'nirs' else coord_frame
    }
    channels_suffix = \
        'optodes' if bids_path.datatype == 'nirs' else 'electrodes'
    _channels_fun = _write_optodes_tsv if bids_path.datatype == 'nirs' else \
        _write_electrodes_tsv
    channels_path = BIDSPath(**coord_file_entities,
                             suffix=channels_suffix,
                             extension='.tsv')
    coordsystem_path = BIDSPath(**coord_file_entities,
                                suffix='coordsystem',
                                extension='.json')

    # Now write the data to the elec coords and the coordsystem
    _channels_fun(raw, channels_path, bids_path.datatype, overwrite)
    _write_coordsystem_json(raw=raw,
                            unit=unit,
                            hpi_coord_system='n/a',
                            sensor_coord_system=coord_frame,
                            fname=coordsystem_path,
                            datatype=bids_path.datatype,
                            overwrite=overwrite)
Exemple #4
0
def _write_dig_bids(electrodes_fname,
                    coordsystem_fname,
                    data_path,
                    raw,
                    kind,
                    overwrite=False,
                    verbose=True):
    """Write BIDS formatted DigMontage from Raw instance.

    Handles coordinatesystem.json and electrodes.tsv writing
    from DigMontage.

    Parameters
    ----------
    electrodes_fname : str
        Filename to save the electrodes.tsv to.
    coordsystem_fname : str
        Filename to save the coordsystem.json to.
    data_path : str | pathlib.Path
        Path to the data directory
    raw : instance of Raw
        The data as MNE-Python Raw object.
    kind : str
        Type of the data as in ALLOWED_KINDS.
    overwrite : bool
        Whether to overwrite the existing file.
        Defaults to False.
    verbose : bool
        Set verbose output to true or false.
    """
    # write electrodes data for iEEG and EEG
    unit = "m"  # defaults to meters

    params = _parse_bids_filename(electrodes_fname, verbose)
    subject_id = params['sub']
    session_id = params['ses']
    acquisition = params['acq']

    # get coordinate frame from digMontage
    digpoint = raw.info['dig'][0]
    if any(digpoint['coord_frame'] != _digpoint['coord_frame']
           for _digpoint in raw.info['dig']):
        warn("Not all digpoints have the same coordinate frame. "
             "Skipping electrodes.tsv writing...")
        return

    # get the accepted mne-python coordinate frames
    coord_frame_int = int(digpoint['coord_frame'])
    mne_coord_frame = MNE_FRAME_TO_STR.get(coord_frame_int, None)
    coord_frame = MNE_TO_BIDS_FRAMES.get(mne_coord_frame, None)

    if verbose:
        print("Writing electrodes file to... ", electrodes_fname)
        print("Writing coordsytem file to... ", coordsystem_fname)

    if kind == "ieeg":
        if coord_frame is not None:
            # XXX: To improve when mne-python allows coord_frame='unknown'
            if coord_frame not in BIDS_IEEG_COORDINATE_FRAMES:
                coordsystem_fname = make_bids_basename(
                    subject=subject_id,
                    session=session_id,
                    acquisition=acquisition,
                    space=coord_frame,
                    suffix='coordsystem.json',
                    prefix=data_path)
                electrodes_fname = make_bids_basename(subject=subject_id,
                                                      session=session_id,
                                                      acquisition=acquisition,
                                                      space=coord_frame,
                                                      suffix='electrodes.tsv',
                                                      prefix=data_path)
                coord_frame = 'Other'

            # Now write the data to the elec coords and the coordsystem
            _electrodes_tsv(raw, electrodes_fname, kind, overwrite, verbose)
            _coordsystem_json(raw, unit, 'n/a', coord_frame, coordsystem_fname,
                              kind, overwrite, verbose)
        else:
            # default coordinate frame to mri if not available
            warn("Coordinate frame of iEEG coords missing/unknown "
                 "for {}. Skipping reading "
                 "in of montage...".format(electrodes_fname))
    elif kind == 'eeg':
        # We only write EEG electrodes.tsv and coordsystem.json
        # if we have LPA, RPA, and NAS available to rescale to a known
        # coordinate system frame
        coords = _extract_landmarks(raw.info['dig'])
        landmarks = set(['RPA', 'NAS', 'LPA']) == set(list(coords.keys()))

        # XXX: to be improved to allow rescaling if landmarks are present
        # mne-python automatically converts unknown coord frame to head
        if coord_frame_int == FIFF.FIFFV_COORD_HEAD and landmarks:
            # Now write the data
            _electrodes_tsv(raw, electrodes_fname, kind, overwrite, verbose)
            _coordsystem_json(raw, 'm', 'RAS', 'CapTrak', coordsystem_fname,
                              kind, overwrite, verbose)
        else:
            warn("Skipping EEG electrodes.tsv... "
                 "Setting montage not possible if anatomical "
                 "landmarks (NAS, LPA, RPA) are missing, "
                 "and coord_frame is not 'head'.")