def _save_bads(*, bads, bids_path, verbose): """Update the set of channels marked as bad.""" channels_tsv_fname = bids_path.copy().update(suffix='channels', extension='.tsv') channels_tsv_data = _from_tsv(channels_tsv_fname) descriptions = [] for ch_name in bads: idx = channels_tsv_data['name'].index(ch_name) if channels_tsv_data['status'][idx] == 'bad': # Channel was already marked as bad, retain existing description. description = channels_tsv_data['status_description'][idx] else: # Channel has been manually marked as bad during inspection, assign # default description. description = 'Manual inspection via MNE-BIDS' descriptions.append(description) # We pass overwrite=True, causing all channels not passed as bad here to # be marked as good. mark_bad_channels(ch_names=bads, descriptions=descriptions, bids_path=bids_path, overwrite=True, verbose=verbose)
def _handle_events_reading_core(events_fname, raw): """Read associated events.tsv and populate raw. Handle onset, duration, and description of each event. """ events_dict = _from_tsv(events_fname) if ('value' in events_dict) and ('trial_type' in events_dict): events_dict = _drop(events_dict, 'n/a', 'trial_type') events_dict = _drop(events_dict, 'n/a', 'value') descriptions = np.asarray([ a + ':' + b for a, b in zip(events_dict["trial_type"], events_dict["value"]) ], dtype=str) # Get the descriptions of the events elif 'trial_type' in events_dict: # Drop events unrelated to a trial type events_dict = _drop(events_dict, 'n/a', 'trial_type') descriptions = np.asarray(events_dict['trial_type'], dtype=str) # If we don't have a proper description of the events, perhaps we have # at least an event value? elif 'value' in events_dict: # Drop events unrelated to value events_dict = _drop(events_dict, 'n/a', 'value') descriptions = np.asarray(events_dict['value'], dtype=str) # Worst case, we go with 'n/a' for all events else: descriptions = 'n/a' # Deal with "n/a" strings before converting to float ons = [np.nan if on == 'n/a' else on for on in events_dict['onset']] dus = [0 if du == 'n/a' else du for du in events_dict['duration']] onsets = np.asarray(ons, dtype=float) durations = np.asarray(dus, dtype=float) # Keep only events where onset is known good_events_idx = ~np.isnan(onsets) onsets = onsets[good_events_idx] durations = durations[good_events_idx] descriptions = descriptions[good_events_idx] del good_events_idx # Add Events to raw as annotations annot_from_events = mne.Annotations(onset=onsets, duration=durations, description=descriptions, orig_time=None) raw.set_annotations(annot_from_events) return raw
def test_inspect_auto_flats(tmp_path, save_changes): """Test flat channel & segment detection.""" import matplotlib import matplotlib.pyplot as plt matplotlib.use('Agg') plt.close('all') bids_root = setup_bids_test_dir(tmp_path) bids_path = _bids_path.copy().update(root=bids_root) channels_tsv_fname = bids_path.copy().update(suffix='channels', extension='.tsv') raw = read_raw_bids(bids_path=bids_path, verbose='error') # Inject an entirely flat channel. raw.load_data() raw._data[10] = np.zeros_like(raw._data[10], dtype=raw._data.dtype) # Add a a flat time segment (approx. 100 ms) to another channel raw._data[20, 500:500 + int(np.ceil(0.1 * raw.info['sfreq']))] = 0 raw.save(raw.filenames[0], overwrite=True) old_bads = raw.info['bads'].copy() inspect_dataset(bids_path) raw_fig = mne_bids.inspect._global_vars['raw_fig'] # Closing the window should open a dialog box. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] if save_changes: key = 'return' else: key = 'escape' fig_dialog.canvas.key_press_event(key) raw = read_raw_bids(bids_path=bids_path, verbose='error') if save_changes: assert old_bads != raw.info['bads'] assert raw.ch_names[10] in raw.info['bads'] channels_tsv_data = _from_tsv(channels_tsv_fname) assert (channels_tsv_data['status_description'][10] == 'Flat channel, auto-detected via MNE-BIDS') # This channel should not have been added to `bads`, but produced a # flat annotation. assert raw.ch_names[20] not in raw.info['bads'] assert 'BAD_flat' in raw.annotations.description else: assert old_bads == raw.info['bads'] assert 'BAD_flat' not in raw.annotations.description
def test_count_no_events_column(tmpdir): """Test case where events.tsv doesn't contain [stim,trial]_type column.""" subject, task, run, session, datatype = '01', 'task1', '01', '01', 'meg' root, events, event_id = _make_dataset(tmpdir, [subject], [task], [run], [session]) # Delete the `stim_type` column. events_tsv_fpath = BIDSPath(root=root, subject=subject, task=task, run=run, session=session, datatype=datatype, suffix='events', extension='.tsv').fpath events_tsv = _from_tsv(events_tsv_fpath) events_tsv['stim_type'] = events_tsv['trial_type'] del events_tsv['trial_type'] _write_tsv(fname=events_tsv_fpath, dictionary=events_tsv, overwrite=True) counts = count_events(root) _check_counts(counts, events, event_id, [subject], [task], [run], [session])
def _save_raw_if_changed(*, old_bads, new_bads, flat_chans, old_annotations, new_annotations, bids_path, verbose): """Save bad channel selection if it has been changed. Parameters ---------- old_bads : list The original bad channels. new_bads : list The updated set of bad channels (i.e. **all** of them, not only the changed ones). flat_chans : list The auto-detected flat channels. This is either an empty list or a subset of ``new_bads``. old_annotations : mne.Annotations The original Annotations. new_annotations : mne.Annotations The new Annotations. """ assert set(flat_chans).issubset(set(new_bads)) if set(old_bads) == set(new_bads): bads = None bad_descriptions = [] else: bads = new_bads bad_descriptions = [] # Generate entries for the `status_description` column. channels_tsv_fname = bids_path.copy().update(suffix='channels', extension='.tsv') channels_tsv_data = _from_tsv(channels_tsv_fname) for ch_name in bads: idx = channels_tsv_data['name'].index(ch_name) if channels_tsv_data['status'][idx] == 'bad': # Channel was already marked as bad in the data, so retain # existing description. description = channels_tsv_data['status_description'][idx] elif ch_name in flat_chans: description = 'Flat channel, auto-detected via MNE-BIDS' else: # Channel has been manually marked as bad during inspection description = 'Interactive inspection via MNE-BIDS' bad_descriptions.append(description) del ch_name, description del channels_tsv_data, channels_tsv_fname, if _annotations_almost_equal(old_annotations, new_annotations): annotations = None else: annotations = new_annotations if bads is None and annotations is None: # Nothing has changed, so we can just exit. return None return _save_raw_dialog_box(bads=bads, bad_descriptions=bad_descriptions, annotations=annotations, bids_path=bids_path, verbose=verbose)