def test_combine_channels_metadata(): """Test if metadata is correctly retained in combined object.""" import pandas as pd raw = read_raw_fif(raw_fname, preload=True) epochs = Epochs(raw, read_events(eve_fname), preload=True) metadata = pd.DataFrame({ "A": np.arange(len(epochs)), "B": np.ones(len(epochs)) }) epochs.metadata = metadata good = dict(foo=[0, 1, 3, 4], bar=[5, 2]) # good grad and mag combined_epochs = combine_channels(epochs, good) pd.testing.assert_frame_equal(epochs.metadata, combined_epochs.metadata)
evoked_file = f'{sub}_task-{task}_ref-avg_lpf-none_ave.fif.gz' scene_diff = read_evokeds(out_erps / evoked_file, condition='scene-object', verbose=False) face_diff = read_evokeds(out_erps / evoked_file, condition='face-object', verbose=False) # Make virtual electrodes new_chans = { 'mean(P7/PO7)': pick_channels(scene_diff.info['ch_names'], ['PO7', 'P7']), 'mean(P8/PO8)': pick_channels(scene_diff.info['ch_names'], ['PO8', 'P8']) } scene_diff = combine_channels(scene_diff, new_chans) face_diff = combine_channels(face_diff, new_chans) # Extract data scene_peaks = mean_amplitude(scene_diff, tmin=.15, tmax=.224) scene_peaks.insert(0, 'id', sub.replace('sub-', '')) scene_peaks.insert(1, 'age_group', age) scene_peaks.insert(2, 'condition', 'scene') scene_peaks.insert(3, 'hemisphere', ['left', 'right']) face_peaks = mean_amplitude(face_diff, tmin=.1, tmax=.17) face_peaks.insert(0, 'id', sub.replace('sub-', '')) face_peaks.insert(1, 'age_group', age) face_peaks.insert(2, 'condition', 'face') face_peaks.insert(3, 'hemisphere', ['left', 'right']) sub_df = pd.concat([scene_peaks, face_peaks])
def test_combine_channels(): """Test channel combination on Raw, Epochs, and Evoked.""" raw = read_raw_fif(raw_fname, preload=True) raw_ch_bad = read_raw_fif(raw_fname, preload=True) raw_ch_bad.info['bads'] = ['MEG 0113', 'MEG 0112'] epochs = Epochs(raw, read_events(eve_fname)) evoked = epochs.average() good = dict(foo=[0, 1, 3, 4], bar=[5, 2]) # good grad and mag # Test good cases combine_channels(raw, good) combine_channels(epochs, good) combine_channels(evoked, good) combine_channels(raw, good, drop_bad=True) combine_channels(raw_ch_bad, good, drop_bad=True) # Test with stimulus channels combine_stim = combine_channels(raw, good, keep_stim=True) target_nchan = len(good) + len(pick_types(raw.info, meg=False, stim=True)) assert combine_stim.info['nchan'] == target_nchan # Test results with one ROI good_single = dict(foo=[0, 1, 3, 4]) # good grad combined_mean = combine_channels(raw, good_single, method='mean') combined_median = combine_channels(raw, good_single, method='median') combined_std = combine_channels(raw, good_single, method='std') foo_mean = np.mean(raw.get_data()[good_single['foo']], axis=0) foo_median = np.median(raw.get_data()[good_single['foo']], axis=0) foo_std = np.std(raw.get_data()[good_single['foo']], axis=0) assert np.array_equal(combined_mean.get_data(), np.expand_dims(foo_mean, axis=0)) assert np.array_equal(combined_median.get_data(), np.expand_dims(foo_median, axis=0)) assert np.array_equal(combined_std.get_data(), np.expand_dims(foo_std, axis=0)) # Test bad cases bad1 = dict(foo=[0, 376], bar=[5, 2]) # out of bounds bad2 = dict(foo=[0, 2], bar=[5, 2]) # type mix in same group with pytest.raises(ValueError, match='"method" must be a callable, or'): combine_channels(raw, good, method='bad_method') with pytest.raises(TypeError, match='"keep_stim" must be of type bool'): combine_channels(raw, good, keep_stim='bad_type') with pytest.raises(TypeError, match='"drop_bad" must be of type bool'): combine_channels(raw, good, drop_bad='bad_type') with pytest.raises(ValueError, match='Some channel indices are out of'): combine_channels(raw, bad1) with pytest.raises(ValueError, match='Cannot combine sensors of diff'): combine_channels(raw, bad2) # Test warnings raw_no_stim = read_raw_fif(raw_fname, preload=True) raw_no_stim.pick_types(meg=True, stim=False) warn1 = dict(foo=[375, 375], bar=[5, 2]) # same channel in same group warn2 = dict(foo=[375], bar=[5, 2]) # one channel (last channel) warn3 = dict(foo=[0, 4], bar=[5, 2]) # one good channel left with pytest.warns(RuntimeWarning, match='Could not find stimulus'): combine_channels(raw_no_stim, good, keep_stim=True) with pytest.warns(RuntimeWarning, match='Less than 2 channels') as record: combine_channels(raw, warn1) combine_channels(raw, warn2) combine_channels(raw_ch_bad, warn3, drop_bad=True) assert len(record) == 3
def get_erp_measures_from_cross_condition_data( erp_arrays: List[EvokedArray], cross_condition_data: pd.DataFrame, interval_in_seconds: float, ): erp_measures = pd.DataFrame(columns=[ "fid", "ch_name", "tmin", "tmax", "mode", "peak_latency", "peak_amplitude", "mean_amplitude", ]) picks = cross_condition_data['ch_name'].values[0].split() mode = cross_condition_data['mode'].values[0] for erp in erp_arrays: picks_idx = pick_channels(erp.info['ch_names'], include=picks) if len(picks_idx) > 1: roi_erp = combine_channels(erp, dict(roi=picks_idx), method='mean') tmin = cross_condition_data['peak_latency'].values[ 0] - interval_in_seconds tmax = cross_condition_data['peak_latency'].values[ 0] + interval_in_seconds if tmax > erp.tmax: tmax = erp.tmax if tmin < erp.tmin: tmin = erp.tmin _, lat, amp = roi_erp.get_peak(ch_type='eeg', tmin=tmin, tmax=tmax, mode=mode, return_amplitude=True) mean_amp = get_mean_amplitude(erp=roi_erp, tmin=tmin, tmax=tmax, mode=mode) fid = Path(erp.comment.replace("\\", "/")).name ch_name = cross_condition_data['ch_name'].values[0] erp_measures = erp_measures.append(dict(fid=fid, ch_name=ch_name, tmin=tmin, tmax=tmax, mode=mode, peak_latency=lat, peak_amplitude=amp * 1e6, mean_amplitude=mean_amp), ignore_index=True) else: for ch_name in cross_condition_data['ch_name']: tmin = cross_condition_data[ cross_condition_data['ch_name'] == ch_name]['peak_latency'] - interval_in_seconds tmax = cross_condition_data[ cross_condition_data['ch_name'] == ch_name]['peak_latency'] + interval_in_seconds tmin = tmin.values[0] tmax = tmax.values[0] if tmax > erp.tmax: tmax = erp.tmax if tmin < erp.tmin: tmin = erp.tmin _, lat, amp = erp.copy().pick(ch_name).get_peak( ch_type='eeg', tmin=tmin, tmax=tmax, mode=mode, return_amplitude=True) mean_amp = get_mean_amplitude(erp=erp.copy().pick(ch_name), tmin=tmin, tmax=tmax, mode=mode) fid = Path(erp.comment.replace("\\", "/")).name erp_measures = erp_measures.append(dict( fid=fid, ch_name=ch_name, tmin=tmin, tmax=tmax, mode=mode, peak_latency=lat, peak_amplitude=amp * 1e6, mean_amplitude=mean_amp), ignore_index=True) return erp_measures
def get_erp_peak_measures(erp: EvokedArray, tmin: float, tmax: float, mode: str, picks=None, combine='mean') -> pd.DataFrame: """ Computes peak measures (peak latency, peak amplitude) from Evoked instance for a given time interval defined by tmin and tmax in seconds. Peak measures can be computed for ROIs (averages data over given list of channels) by defining the list of channel names (e.g. ['F2', 'F5', 'F7']) that will be aggregated first, and then the measures computed. If picks is not defined, peak measures are computed for each channel. Parameters ---------- erp tmin tmax mode: 'pos': finds the peak with a positive voltage (ignores negative voltages) 'neg': finds the peak with a negative voltage (ignores positive voltages) 'abs': finds the peak with the largest absolute voltage regardless of sign (positive or negative) combine: whether to combine channels (defined by picks) using 'mean', 'median' or 'std' use None to not combine channels but get peak measures separately for each channel picks Returns ------- DataFrame containing the peak measures for each channel or for a given ROI """ if picks is None: picks = [] erp_measures = pd.DataFrame(columns=[ "fid", "ch_name", "tmin", "tmax", "mode", "peak_latency", "peak_amplitude", ]) if combine: picks_idx = pick_channels(erp.info["ch_names"], include=picks) roi_erp = combine_channels(erp, dict(roi=picks_idx), method=combine) _, lat, amp = roi_erp.get_peak(ch_type='eeg', tmin=tmin, tmax=tmax, mode=mode, return_amplitude=True) ch_name = ' '.join(picks) erp_measures = erp_measures.append(dict(fid=erp.comment, ch_name=ch_name, tmin=tmin, tmax=tmax, mode=mode, peak_latency=lat, peak_amplitude=amp * 1e6), ignore_index=True) else: for ch_name in picks: _, lat, amp = erp.copy().pick(ch_name).get_peak( ch_type='eeg', tmin=tmin, tmax=tmax, mode=mode, return_amplitude=True) erp_measures = erp_measures.append(dict(fid=erp.comment, ch_name=ch_name, tmin=tmin, tmax=tmax, mode=mode, peak_latency=lat, peak_amplitude=amp * 1e6), ignore_index=True) return erp_measures
############################################################################### # Evoked response averaged across channels by ROI # ----------------------------------------------- # # It is possible to average channels by region of interest (for example left # and right) when studying the response to this left auditory stimulus. Here we # use our Raw object on which the average reference projection has been added # back. evoked = mne.Epochs(raw, **epochs_params).average() left_idx = mne.pick_channels(evoked.info['ch_names'], ['EEG 017', 'EEG 018', 'EEG 025', 'EEG 026']) right_idx = mne.pick_channels(evoked.info['ch_names'], ['EEG 023', 'EEG 024', 'EEG 034', 'EEG 035']) roi_dict = dict(Left=left_idx, Right=right_idx) evoked_combined = combine_channels(evoked, roi_dict, method='mean') title = 'Evoked response averaged by side' evoked_combined.plot(titles=dict(eeg=title), time_unit='s') ############################################################################### # Evoked arithmetic (e.g. differences) # ------------------------------------ # # Trial subsets from Epochs can be selected using 'tags' separated by '/'. # Evoked objects support basic arithmetic. # First, we create an Epochs object containing 4 conditions. event_id = {'left/auditory': 1, 'right/auditory': 2, 'left/visual': 3, 'right/visual': 4} epochs_params = dict(events=events, event_id=event_id, tmin=tmin, tmax=tmax,