def test_inspect_bads_and_annotations(tmp_path): """Test adding bads and Annotations in one go.""" from mne.utils._testing import _click_ch_name 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) raw = read_raw_bids(bids_path=bids_path, verbose='error') orig_bads = raw.info['bads'].copy() inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] # Mark some channels as bad by clicking on their name. _click_ch_name(raw_fig, ch_index=0, button=1) # Add custom Annotation. _add_annotation(raw_fig) # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # Check that the changes were saved. raw = read_raw_bids(bids_path=bids_path, verbose='error') new_bads = raw.info['bads'] expected_bads = orig_bads + ['MEG 0113'] assert set(new_bads) == set(expected_bads) assert 'BAD_test' in raw.annotations.description
def test_inspect_single_file(return_bids_test_dir, save_changes): from mne.utils._testing import _click_ch_name import matplotlib matplotlib.use('Agg') bids_path = _bids_path.copy().update(root=return_bids_test_dir) raw = read_raw_bids(bids_path=bids_path, verbose='error') old_bads = raw.info['bads'].copy() inspect_dataset(bids_path) raw_fig = mne_bids.inspect._global_vars['raw_fig'] # Mark some channels as bad by clicking on their name. _click_ch_name(raw_fig, ch_index=0, button=1) _click_ch_name(raw_fig, ch_index=1, button=1) _click_ch_name(raw_fig, ch_index=4, button=1) # 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') new_bads = raw.info['bads'].copy() if save_changes: assert len(new_bads) > len(old_bads) else: assert old_bads == new_bads
def test_inspect_dont_show_annotations(tmp_path): """Test if show_annotations=False works.""" 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) inspect_dataset(bids_path, find_flat=False, show_annotations=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] assert not raw_fig.mne.annotations
def test_inspect_annotations_remove_all(tmp_path): """Test behavior if all Annotations are removed by the user.""" 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) events_tsv_fpath = (bids_path.copy().update(suffix='events', extension='.tsv').fpath) # Remove all Annotations. raw = read_raw_bids(bids_path=bids_path, verbose='error') raw.set_annotations(None) raw.load_data() raw.save(raw.filenames[0], overwrite=True) # Delete events.tsv sidecar. (bids_path.copy().update(suffix='events', extension='.tsv').fpath.unlink()) # Add custom Annotation. inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] _add_annotation(raw_fig) # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # events.tsv sidecar should have been created. assert events_tsv_fpath.exists() # Remove the Annotation. inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] data_ax = raw_fig.mne.ax_main raw_fig.canvas.key_press_event('a') # Toggle Annotation mode _fake_click(raw_fig, data_ax, [1., 1.], xform='data', button=3, kind='press') # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # events.tsv sidecar should not exist anymore. assert not events_tsv_fpath.exists()
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_inspect_multiple_files(return_bids_test_dir): import matplotlib matplotlib.use('Agg') bids_path = _bids_path.copy().update(root=return_bids_test_dir) # Create a second subject raw = read_raw_bids(bids_path=bids_path, verbose='error') write_raw_bids(raw, bids_path.copy().update(subject='02')) del raw # Inspection should end with the second subject. inspect_dataset(bids_path.copy().update(subject=None)) raw_fig = mne_bids.inspect._global_vars['raw_fig'] assert raw_fig.mne.info['subject_info']['participant_id'] == 'sub-02' raw_fig.canvas.key_press_event(raw_fig.mne.close_key)
def test_inspect_annotations(tmp_path): """Test inspection of Annotations.""" 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) raw = read_raw_bids(bids_path=bids_path, verbose='error') orig_annotations = raw.annotations.copy() inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] _add_annotation(raw_fig) # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # Ensure changes were saved. raw = read_raw_bids(bids_path=bids_path, verbose='error') assert 'BAD_test' in raw.annotations.description annot_idx = raw.annotations.description == 'BAD_test' assert raw.annotations.duration[annot_idx].squeeze() == 4 # Remove the Annotation. inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] data_ax = raw_fig.mne.ax_main raw_fig.canvas.key_press_event('a') # Toggle Annotation mode _fake_click(raw_fig, data_ax, [1., 1.], xform='data', button=3, kind='press') # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # Ensure changes were saved. raw = read_raw_bids(bids_path=bids_path, verbose='error') assert 'BAD_test' not in raw.annotations.description assert raw.annotations == orig_annotations
def test_inspect_set_and_unset_bads(tmp_path): """Test marking channels as bad and later marking them as good again.""" from mne.utils._testing import _click_ch_name 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) raw = read_raw_bids(bids_path=bids_path, verbose='error') orig_bads = raw.info['bads'].copy() # Mark some channels as bad by clicking on their name. inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] _click_ch_name(raw_fig, ch_index=0, button=1) _click_ch_name(raw_fig, ch_index=1, button=1) _click_ch_name(raw_fig, ch_index=4, button=1) # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # Inspect the data again, click on two of the bad channels to mark them as # good. inspect_dataset(bids_path, find_flat=False) raw_fig = mne_bids.inspect._global_vars['raw_fig'] _click_ch_name(raw_fig, ch_index=1, button=1) _click_ch_name(raw_fig, ch_index=4, button=1) # Close window and save changes. raw_fig.canvas.key_press_event(raw_fig.mne.close_key) fig_dialog = mne_bids.inspect._global_vars['dialog_fig'] fig_dialog.canvas.key_press_event('return') # Check marking the channels as good has actually worked. expected_bads = orig_bads + ['MEG 0113'] raw = read_raw_bids(bids_path=bids_path, verbose='error') new_bads = raw.info['bads'] assert set(new_bads) == set(expected_bads)
def test_inspect_multiple_files(tmp_path): """Test inspecting a dataset consisting of more than one file.""" 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) # Create a second subject raw = read_raw_bids(bids_path=bids_path, verbose='error') write_raw_bids(raw, bids_path.copy().update(subject='02')) del raw # Inspection should end with the second subject. inspect_dataset(bids_path.copy().update(subject=None)) raw_fig = mne_bids.inspect._global_vars['raw_fig'] assert raw_fig.mne.info['subject_info']['participant_id'] == 'sub-02' raw_fig.canvas.key_press_event(raw_fig.mne.close_key)
def run(): """Run the mark_channels command.""" from mne.commands.utils import get_optparser parser = get_optparser(__file__, usage="usage: %prog options args", prog_prefix='mne_bids', version=mne_bids.__version__) parser.add_option('--bids_root', dest='bids_root', help='The path of the folder containing the BIDS ' 'dataset') parser.add_option('--subject_id', dest='subject', help=('Subject name')) parser.add_option('--session_id', dest='session', help='Session name') parser.add_option('--task', dest='task', help='Task name') parser.add_option('--acq', dest='acquisition', help='Acquisition parameter') parser.add_option('--run', dest='run', help='Run number') parser.add_option('--proc', dest='processing', help='Processing label.') parser.add_option('--rec', dest='recording', help='Recording name') parser.add_option('--type', dest='datatype', help='Recording data type, e.g. meg, ieeg or eeg') parser.add_option('--suffix', dest='suffix', help='The filename suffix, i.e. the last part before ' 'the extension') parser.add_option('--ext', dest='extension', help='The filename extension, including the leading ' 'period, e.g. .fif') parser.add_option('--find_flat', dest='find_flat', help='Whether to auto-detect flat channels and time ' 'segments') parser.add_option('--l_freq', dest='l_freq', help='The high-pass filter cutoff frequency') parser.add_option('--h_freq', dest='h_freq', help='The low-pass filter cutoff frequency') parser.add_option('--verbose', dest='verbose', action='store_true', help='Whether do generate additional diagnostic output') opt, args = parser.parse_args() if args: parser.print_help() parser.error(f'Please do not specify arguments without flags. ' f'Got: {args}.\n') if opt.bids_root is None: parser.print_help() parser.error('You must specify bids_root') bids_path = BIDSPath(subject=opt.subject, session=opt.session, task=opt.task, acquisition=opt.acquisition, run=opt.run, processing=opt.processing, recording=opt.recording, datatype=opt.datatype, suffix=opt.suffix, extension=opt.extension, root=opt.bids_root) find_flat = True if opt.find_flat is None else bool(opt.find_flat) l_freq = None if opt.l_freq is None else float(opt.l_freq) h_freq = None if opt.h_freq is None else float(opt.h_freq) logger.info(f'Inspecting {bids_path.basename} …') inspect_dataset(bids_path=bids_path, find_flat=find_flat, l_freq=l_freq, h_freq=h_freq, verbose=opt.verbose)
raw.info['line_freq'] = 60 # Specify power line frequency as required by BIDS. write_raw_bids(raw, bids_path=bids_path, overwrite=True, verbose=False) ############################################################################### # Interactive use # --------------- # # Using :func:`mne_bids.inspect_dataset`, we can interactively explore the raw # data and toggle the channel status – ``bad`` or ``good`` – by clicking on the # respective traces or channel names. If there are any SSP projectors stored # with the data, a small popup window will allow you to toggle the projectors # on and off. If you changed the selection of bad channels, you will be # prompted whether you would like to save the changes when closing the main # window. inspect_dataset(bids_path) ############################################################################### # You can even apply frequency filters when viewing the data: A high-pass # filter can remove slow drifts, while a low-pass filter will get rid of # high-frequency artifacts. This can make visual inspection easier. Let's # apply filters with a 1-Hz high-pass cutoff, and a 30-Hz low-pass cutoff: inspect_dataset(bids_path, l_freq=1., h_freq=30.) ############################################################################### # Non-interactive (programmatic) bad channel selection # ---------------------------------------------------- # # Read the (now BIDS-formatted) data and print a list of channels currently # marked as bad.
def test_inspect_freq_filter(return_bids_test_dir, l_freq, h_freq): bids_path = _bids_path.copy().update(root=return_bids_test_dir) inspect_dataset(bids_path, l_freq=l_freq, h_freq=h_freq)
def test_inspect_freq_filter(tmp_path, l_freq, h_freq): """Test frequency filter for Raw display.""" bids_root = setup_bids_test_dir(tmp_path) bids_path = _bids_path.copy().update(root=bids_root) inspect_dataset(bids_path, l_freq=l_freq, h_freq=h_freq, find_flat=False)