def _electrodes_tsv(raw, fname, datatype, overwrite=False, verbose=True): """Create an electrodes.tsv file and save it. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. fname : str Filename to save the electrodes.tsv to. datatype : str Type of the data recording. Can be ``meg``, ``eeg``, or ``ieeg``. overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ # create list of channel coordinates and names x, y, z, names = list(), list(), list(), list() for ch in raw.info['chs']: if _check_ch_locs([ch]): x.append(ch['loc'][0]) y.append(ch['loc'][1]) z.append(ch['loc'][2]) else: x.append('n/a') y.append('n/a') z.append('n/a') names.append(ch['ch_name']) # create OrderedDict to write to tsv file if datatype == "ieeg": # XXX: size should be included in the future sizes = ['n/a'] * len(names) data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ('size', sizes), ]) elif datatype == 'eeg': data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ]) else: # pragma: no cover raise RuntimeError("datatype {} not supported.".format(datatype)) # Add impedance values if available, currently only BrainVision: # https://github.com/mne-tools/mne-python/pull/7974 if hasattr(raw, 'impedances'): data['impedance'] = _get_impedances(raw, names) _write_tsv(fname, data, overwrite=overwrite, verbose=verbose)
def _write_electrodes_tsv( fname: str, ch_names: Union[List, np.ndarray], coords: Union[List, np.ndarray], sizes: Union[List, np.ndarray] = None, overwrite: bool = False, verbose: bool = True, ): """ Create an electrodes.tsv file and save it. Parameters ---------- fname : str Filename to save the electrodes.tsv to. names : coords : sizes : overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ if len(ch_names) != len(coords): raise RuntimeError( "Number of channel names should match " "number of coordinates passed in. " f"{len(ch_names)} names and {len(coords)} coords passed in." ) x, y, z, names = list(), list(), list(), list() for name, coord in zip(ch_names, coords): x.append(coord[0]) y.append(coord[1]) z.append(coord[2]) names.append(name) if sizes is None: sizes = ["n/a"] * len(ch_names) data = OrderedDict( [ ("name", names), ("x", x), ("y", y), ("z", z), ("size", sizes), ] ) print(f"Writin data to {fname}: ") print(data) _write_tsv(fname, data, overwrite=overwrite, verbose=verbose) return fname
def _events_tsv(events, raw, fname, trial_type, overwrite=False, verbose=True): """Create an events.tsv file and save it. This function will write the mandatory 'onset', and 'duration' columns as well as the optional 'value' and 'sample'. The 'value' corresponds to the marker value as found in the TRIG channel of the recording. In addition, the 'trial_type' field can be written. Parameters ---------- events : array, shape = (n_events, 3) The first column contains the event time in samples and the third column contains the event id. The second column is ignored for now but typically contains the value of the trigger channel either immediately before the event or immediately after. raw : instance of Raw The data as MNE-Python Raw object. fname : str Filename to save the events.tsv to. trial_type : dict | None Dictionary mapping a brief description key to an event id (value). For example {'Go': 1, 'No Go': 2}. overwrite : bool Whether to overwrite the existing file. Defaults to False. verbose : bool Set verbose output to true or false. Notes ----- The function writes durations of zero for each event. """ # Start by filling all data that we know into an ordered dictionary first_samp = raw.first_samp sfreq = raw.info['sfreq'] events[:, 0] -= first_samp # Onset column needs to be specified in seconds data = OrderedDict([('onset', events[:, 0] / sfreq), ('duration', np.zeros(events.shape[0])), ('trial_type', None), ('value', events[:, 2]), ('sample', events[:, 0])]) # Now check if trial_type is specified or should be removed if trial_type: trial_type_map = {v: k for k, v in trial_type.items()} data['trial_type'] = [trial_type_map.get(i, 'n/a') for i in events[:, 2]] else: del data['trial_type'] _write_tsv(fname, data, overwrite, verbose) return fname
def _electrodes_tsv(raw, fname, kind, overwrite=False, verbose=True): """Create an electrodes.tsv file and save it. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. fname : str Filename to save the electrodes.tsv to. kind : str Type of the data as in ALLOWED_KINDS. For iEEG, requires size. overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ # create list of channel coordinates and names x, y, z, names = list(), list(), list(), list() for ch in raw.info['chs']: if _check_ch_locs([ch]): x.append(ch['loc'][0]) y.append(ch['loc'][1]) z.append(ch['loc'][2]) else: x.append('n/a') y.append('n/a') z.append('n/a') names.append(ch['ch_name']) # create OrderedDict to write to tsv file if kind == "ieeg": # XXX: size should be included in the future sizes = ['n/a'] * len(names) data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ('size', sizes), ]) elif kind == 'eeg': data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ]) else: # pragma: no cover raise RuntimeError("kind {} not supported.".format(kind)) _write_tsv(fname, data, overwrite=overwrite, verbose=verbose)
def _scans_tsv(raw, raw_fname, fname, overwrite=False, verbose=True): """Create a scans.tsv file and save it. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. raw_fname : str Relative path to the raw data file. fname : str Filename to save the scans.tsv to. overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ # get measurement date from the data info meas_date = raw.info['meas_date'] if isinstance(meas_date, (tuple, list, np.ndarray)): meas_date = meas_date[0] acq_time = datetime.fromtimestamp(meas_date).strftime( '%Y-%m-%dT%H:%M:%S') else: acq_time = 'n/a' data = OrderedDict([('filename', ['%s' % raw_fname.replace(os.sep, '/')]), ('acq_time', [acq_time])]) if os.path.exists(fname): orig_data = _from_tsv(fname) # if the file name is already in the file raise an error if raw_fname in orig_data['filename'] and not overwrite: raise FileExistsError( '"%s" already exists in the scans list. ' # noqa: E501 F821 'Please set overwrite to True.' % raw_fname) # otherwise add the new data data = _combine(orig_data, data, 'filename') # overwrite is forced to True as all issues with overwrite == False have # been handled by this point _write_tsv(fname, data, True, verbose) return fname
def _write_electrodes_tsv(raw, fname, datatype, overwrite=False, verbose=True): """Create an electrodes.tsv file and save it. Parameters ---------- raw : mne.io.Raw The data as MNE-Python Raw object. fname : str Filename to save the electrodes.tsv to. datatype : str Type of the data recording. Can be ``meg``, ``eeg``, or ``ieeg``. overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ # create list of channel coordinates and names x, y, z, names = list(), list(), list(), list() for ch in raw.info['chs']: if _check_ch_locs([ch]): x.append(ch['loc'][0]) y.append(ch['loc'][1]) z.append(ch['loc'][2]) else: x.append('n/a') y.append('n/a') z.append('n/a') names.append(ch['ch_name']) # create OrderedDict to write to tsv file if datatype == "ieeg": # XXX: size should be included in the future sizes = ['n/a'] * len(names) data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ('size', sizes), ]) elif datatype == 'eeg': data = OrderedDict([ ('name', names), ('x', x), ('y', y), ('z', z), ]) else: # pragma: no cover raise RuntimeError("datatype {} not supported.".format(datatype)) # Add impedance values if available, currently only BrainVision: # https://github.com/mne-tools/mne-python/pull/7974 if hasattr(raw, 'impedances'): data['impedance'] = _get_impedances(raw, names) # note that any coordsystem.json file shared within sessions # will be the same across all runs (currently). So # overwrite is set to True always # XXX: improve later when BIDS is updated # check that there already exists a coordsystem.json if Path(fname).exists() and not overwrite: electrodes_tsv = _from_tsv(fname) # cast values to str to make equality check work if any([ list(map(str, vals1)) != list(vals2) for vals1, vals2 in zip(data.values(), electrodes_tsv.values()) ]): raise RuntimeError( f'Trying to write electrodes.tsv, but it already ' f'exists at {fname} and the contents do not match. ' f'You must differentiate this electrodes.tsv file ' f'from the existing one, or set "overwrite" to True.') _write_tsv(fname, data, overwrite=True, verbose=verbose)
def _channels_tsv(raw, fname, overwrite=False, verbose=True): """Create a channels.tsv file and save it. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. fname : str Filename to save the channels.tsv to. overwrite : bool Whether to overwrite the existing file. Defaults to False. verbose : bool Set verbose output to true or false. """ # Get channel type mappings between BIDS and MNE nomenclatures map_chs = _get_ch_type_mapping(fro='mne', to='bids') # Prepare the descriptions for each channel type map_desc = defaultdict(lambda: 'Other type of channel') map_desc.update(meggradaxial='Axial Gradiometer', megrefgradaxial='Axial Gradiometer Reference', meggradplanar='Planar Gradiometer', megmag='Magnetometer', megrefmag='Magnetometer Reference', stim='Trigger', eeg='ElectroEncephaloGram', ecog='Electrocorticography', seeg='StereoEEG', ecg='ElectroCardioGram', eog='ElectroOculoGram', emg='ElectroMyoGram', misc='Miscellaneous') get_specific = ('mag', 'ref_meg', 'grad') # get the manufacturer from the file in the Raw object manufacturer = None _, ext = _parse_ext(raw.filenames[0], verbose=verbose) manufacturer = MANUFACTURERS[ext] ignored_channels = IGNORED_CHANNELS.get(manufacturer, list()) status, ch_type, description = list(), list(), list() for idx, ch in enumerate(raw.info['ch_names']): status.append('bad' if ch in raw.info['bads'] else 'good') _channel_type = channel_type(raw.info, idx) if _channel_type in get_specific: _channel_type = coil_type(raw.info, idx, _channel_type) ch_type.append(map_chs[_channel_type]) description.append(map_desc[_channel_type]) low_cutoff, high_cutoff = (raw.info['highpass'], raw.info['lowpass']) if raw._orig_units: units = [raw._orig_units.get(ch, 'n/a') for ch in raw.ch_names] else: units = [_unit2human.get(ch_i['unit'], 'n/a') for ch_i in raw.info['chs']] units = [u if u not in ['NA'] else 'n/a' for u in units] n_channels = raw.info['nchan'] sfreq = raw.info['sfreq'] ch_data = OrderedDict([ ('name', raw.info['ch_names']), ('type', ch_type), ('units', units), ('low_cutoff', np.full((n_channels), low_cutoff)), ('high_cutoff', np.full((n_channels), high_cutoff)), ('description', description), ('sampling_frequency', np.full((n_channels), sfreq)), ('status', status)]) ch_data = _drop(ch_data, ignored_channels, 'name') _write_tsv(fname, ch_data, overwrite, verbose) return fname
def _participants_tsv(raw, subject_id, fname, overwrite=False, verbose=True): """Create a participants.tsv file and save it. This will append any new participant data to the current list if it exists. Otherwise a new file will be created with the provided information. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. subject_id : str The subject name in BIDS compatible format ('01', '02', etc.) fname : str Filename to save the participants.tsv to. overwrite : bool Whether to overwrite the existing file. Defaults to False. If there is already data for the given `subject_id` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ subject_id = 'sub-' + subject_id data = OrderedDict(participant_id=[subject_id]) subject_age = "n/a" sex = "n/a" subject_info = raw.info['subject_info'] if subject_info is not None: sexes = {0: 'n/a', 1: 'M', 2: 'F'} sex = sexes[subject_info.get('sex', 0)] # determine the age of the participant age = subject_info.get('birthday', None) meas_date = raw.info.get('meas_date', None) if isinstance(meas_date, (tuple, list, np.ndarray)): meas_date = meas_date[0] if meas_date is not None and age is not None: bday = datetime(age[0], age[1], age[2]) meas_datetime = datetime.fromtimestamp(meas_date) subject_age = _age_on_date(bday, meas_datetime) else: subject_age = "n/a" data.update({'age': [subject_age], 'sex': [sex]}) if os.path.exists(fname): orig_data = _from_tsv(fname) # whether the new data exists identically in the previous data exact_included = _contains_row(orig_data, {'participant_id': subject_id, 'age': subject_age, 'sex': sex}) # whether the subject id is in the previous data sid_included = subject_id in orig_data['participant_id'] # if the subject data provided is different to the currently existing # data and overwrite is not True raise an error if (sid_included and not exact_included) and not overwrite: raise FileExistsError('"%s" already exists in the participant ' # noqa: E501 F821 'list. Please set overwrite to ' 'True.' % subject_id) # otherwise add the new data data = _combine(orig_data, data, 'participant_id') # overwrite is forced to True as all issues with overwrite == False have # been handled by this point _write_tsv(fname, data, True, verbose) return fname
def _write_optodes_tsv(raw, fname, overwrite=False, verbose=True): """Create a optodes.tsv file and save it. Parameters ---------- raw : instance of Raw The data as MNE-Python Raw object. fname : str | BIDSPath Filename to save the optodes.tsv to. overwrite : bool Whether to overwrite the existing file. Defaults to False. verbose : bool Set verbose output to True or False. """ picks = _picks_to_idx(raw.info, 'fnirs', exclude=[], allow_empty=True) sources = np.zeros(picks.shape) detectors = np.zeros(picks.shape) for ii in picks: # NIRS channel names take a specific form in MNE-Python. # The channel names always reflect the source and detector # pair, followed by the wavelength frequency. # The following code extracts the source and detector # numbers from the channel name. ch1_name_info = re.match(r'S(\d+)_D(\d+) (\d+)', raw.info['chs'][ii]['ch_name']) sources[ii] = ch1_name_info.groups()[0] detectors[ii] = ch1_name_info.groups()[1] unique_sources = np.unique(sources) n_sources = len(unique_sources) unique_detectors = np.unique(detectors) names = np.concatenate( (["S" + str(s) for s in unique_sources.astype(int)], ["D" + str(d) for d in unique_detectors.astype(int)])) xs = np.zeros(names.shape) ys = np.zeros(names.shape) zs = np.zeros(names.shape) for i, source in enumerate(unique_sources): s_idx = np.where(sources == source)[0][0] xs[i] = raw.info["chs"][s_idx]["loc"][3] ys[i] = raw.info["chs"][s_idx]["loc"][4] zs[i] = raw.info["chs"][s_idx]["loc"][5] for i, detector in enumerate(unique_detectors): d_idx = np.where(detectors == detector)[0][0] xs[i + n_sources] = raw.info["chs"][d_idx]["loc"][6] ys[i + n_sources] = raw.info["chs"][d_idx]["loc"][7] zs[i + n_sources] = raw.info["chs"][d_idx]["loc"][8] ch_data = { 'name': names, 'type': np.concatenate( (np.full(len(unique_sources), 'source'), np.full(len(unique_detectors), 'detector'))), 'x': xs, 'y': ys, 'z': zs, } _write_tsv(fname, ch_data, overwrite, verbose)
def _electrodes_tsv(ch_names, ch_coords, fname, overwrite=False, verbose=True): """Create an electrodes.tsv file and save it. Parameters ---------- ch_names : list | np.ndarray Name of the electrode contact point. Corresponds to ``name`` in iEEG-BIDS for electrodes.tsv file. ch_coords : list | np.ndarray List of sensor xyz positions. Corresponds to ``x``, ``y``, ``z`` in iEEG-BIDS for electrodes.tsv file. fname : str Filename to save the electrodes.tsv to. overwrite : bool Defaults to False. Whether to overwrite the existing data in the file. If there is already data for the given `fname` and overwrite is False, an error will be raised. verbose : bool Set verbose output to true or false. """ # create list of channel coordinates and names x, y, z, names = list(), list(), list(), list() for ch, coord in zip(ch_names, ch_coords): if any(np.isnan(_coord) for _coord in coord): x.append("n/a") y.append("n/a") z.append("n/a") else: x.append(coord[0]) y.append(coord[1]) z.append(coord[2]) names.append(ch) # create OrderedDict to write to tsv file # XXX: size should be included in the future sizes = ["n/a"] * len(names) data = OrderedDict([ ("name", names), ("x", x), ("y", y), ("z", z), ("size", sizes), ]) # note that any coordsystem.json file shared within sessions # will be the same across all runs (currently). So # overwrite is set to True always # XXX: improve later when BIDS is updated # check that there already exists a coordsystem.json if Path(fname).exists() and not overwrite: electrodes_tsv = _from_tsv(fname) # cast values to str to make equality check work if any([ list(map(str, vals1)) != list(vals2) for vals1, vals2 in zip(data.values(), electrodes_tsv.values()) ]): raise RuntimeError( f"Trying to write electrodes.tsv, but it already " f"exists at {fname} and the contents do not match. " f"You must differentiate this electrodes.tsv file " f'from the existing one, or set "overwrite" to True.') _write_tsv(fname, data, overwrite=True, verbose=verbose)