def test_make_folders(): """Test that folders are created and named properly.""" # Make sure folders are created properly output_path = _TempDir() make_bids_folders(subject='hi', session='foo', kind='ba', root=output_path) assert os.path.isdir(os.path.join(output_path, 'sub-hi', 'ses-foo', 'ba')) # If we remove a kwarg the folder shouldn't be created output_path = _TempDir() make_bids_folders(subject='hi', kind='ba', root=output_path) assert os.path.isdir(os.path.join(output_path, 'sub-hi', 'ba'))
def get_matched_empty_room(bids_fname, bids_root): """Get matching empty room file. Parameters ---------- bids_fname : str The filename for which to find the matching empty room file. bids_root : str Path to the BIDS root folder. Returns ------- er_fname : str | None. The filename corresponding to the empty room. Returns None if no file found. """ bids_fname = op.basename(bids_fname) _, ext = _parse_ext(bids_fname) raw = read_raw_bids(bids_fname, bids_root) if raw.info['meas_date'] is None: raise ValueError('Measurement date not available. Cannot get matching' ' empty room file') ref_date = raw.info['meas_date'] if not isinstance(ref_date, datetime): # for MNE < v0.20 ref_date = datetime.fromtimestamp(raw.info['meas_date'][0]) search_path = make_bids_folders(bids_root=bids_root, subject='emptyroom', session='**', make_dir=False) search_path = op.join(search_path, '**', '**%s' % ext) er_fnames = glob.glob(search_path) best_er_fname = None min_seconds = np.inf for er_fname in er_fnames: params = _parse_bids_filename(er_fname, verbose=False) dt = datetime.strptime(params['ses'], '%Y%m%d') dt = dt.replace(tzinfo=ref_date.tzinfo) delta_t = dt - ref_date if abs(delta_t.total_seconds()) < min_seconds: min_seconds = abs(delta_t.total_seconds()) best_er_fname = er_fname return best_er_fname
def test_make_folders(): """Test that folders are created and named properly.""" # Make sure folders are created properly output_path = _TempDir() make_bids_folders(subject='hi', session='foo', kind='ba', output_path=output_path) assert op.isdir(op.join(output_path, 'sub-hi', 'ses-foo', 'ba')) # If we remove a kwarg the folder shouldn't be created output_path = _TempDir() make_bids_folders(subject='hi', kind='ba', output_path=output_path) assert op.isdir(op.join(output_path, 'sub-hi', 'ba')) # check overwriting of folders make_bids_folders(subject='hi', kind='ba', output_path=output_path, overwrite=True, verbose=True)
def get_matched_empty_room(bids_basename, bids_root): """Get matching empty-room file for an MEG recording. Parameters ---------- bids_basename : str | BIDSPath The base filename of the BIDS-compatible file. Typically, this can be generated using :func:`mne_bids.make_bids_basename`. bids_root : str | pathlib.Path Path to the BIDS root folder. Returns ------- er_basename : str | None. The basename corresponding to the best-matching empty-room measurement. Returns None if none was found. """ # convert to BIDS Path if isinstance(bids_basename, str): params = _parse_bids_filename(bids_basename, False) 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')) kind = 'meg' # We're only concerned about MEG data here bids_fname = bids_basename.get_bids_fname(kind=kind, bids_root=bids_root) _, ext = _parse_ext(bids_fname) if ext == '.fif': extra_params = dict(allow_maxshield=True) else: extra_params = None raw = read_raw_bids(bids_basename=bids_basename, bids_root=bids_root, kind=kind, extra_params=extra_params) if raw.info['meas_date'] is None: raise ValueError('The provided recording does not have a measurement ' 'date set. Cannot get matching empty-room file.') ref_date = raw.info['meas_date'] if not isinstance(ref_date, datetime): # for MNE < v0.20 ref_date = datetime.fromtimestamp(raw.info['meas_date'][0]) emptyroom_dir = pathlib.Path( make_bids_folders(bids_root=bids_root, subject='emptyroom', make_dir=False)) if not emptyroom_dir.exists(): return None # Find the empty-room recording sessions. emptyroom_session_dirs = [ x for x in emptyroom_dir.iterdir() if x.is_dir() and str(x.name).startswith('ses-') ] if not emptyroom_session_dirs: # No session sub-directories found emptyroom_session_dirs = [emptyroom_dir] # Now try to discover all recordings inside the session directories. allowed_extensions = list(reader.keys()) # `.pdf` is just a "virtual" extension for BTi data (which is stored inside # a dedicated directory that doesn't have an extension) del allowed_extensions[allowed_extensions.index('.pdf')] candidate_er_fnames = [] for session_dir in emptyroom_session_dirs: dir_contents = glob.glob( op.join(session_dir, kind, f'sub-emptyroom_*_{kind}*')) for item in dir_contents: item = pathlib.Path(item) if ((item.suffix in allowed_extensions) or (not item.suffix and item.is_dir())): # Hopefully BTi? candidate_er_fnames.append(item.name) # Walk through recordings, trying to extract the recording date: # First, from the filename; and if that fails, from `info['meas_date']`. best_er_basename = None min_delta_t = np.inf date_tie = False failed_to_get_er_date_count = 0 for er_fname in candidate_er_fnames: params = _parse_bids_filename(er_fname, verbose=False) er_meas_date = None er_bids_path = BIDSPath(subject='emptyroom', session=params.get('ses', None), task=params.get('task', None), acquisition=params.get('acq', None), run=params.get('run', None), processing=params.get('proc', None), recording=params.get('rec', None), space=params.get('space', None)) er_basename = str(er_bids_path) # Try to extract date from filename. if params['ses'] is not None: try: er_meas_date = datetime.strptime(params['ses'], '%Y%m%d') except (ValueError, TypeError): # There is a session in the filename, but it doesn't encode a # valid date. pass if er_meas_date is None: # No luck so far! Check info['meas_date'] _, ext = _parse_ext(er_fname) if ext == '.fif': extra_params = dict(allow_maxshield=True) else: extra_params = None er_raw = read_raw_bids(bids_basename=er_basename, bids_root=bids_root, kind=kind, extra_params=extra_params) er_meas_date = er_raw.info['meas_date'] if er_meas_date is None: # There's nothing we can do. failed_to_get_er_date_count += 1 continue er_meas_date = er_meas_date.replace(tzinfo=ref_date.tzinfo) delta_t = er_meas_date - ref_date if abs(delta_t.total_seconds()) == min_delta_t: date_tie = True elif abs(delta_t.total_seconds()) < min_delta_t: min_delta_t = abs(delta_t.total_seconds()) best_er_basename = er_basename date_tie = False if failed_to_get_er_date_count > 0: msg = (f'Could not retrieve the empty-room measurement date from ' f'a total of {failed_to_get_er_date_count} recording(s).') warn(msg) if date_tie: msg = ('Found more than one matching empty-room measurement with the ' 'same recording date. Selecting the first match.') warn(msg) return best_er_basename
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