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'.")
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'.")