def test_baseline(): d = Dataset(micromed_file) ev = [ev['start'] for ev in d.read_markers()][1] chans = d.header['chan_name'][:2] data = d.read_data(events=ev, pre=1, post=1, chan=chans) time_interval = (-.5, -.1) out = apply_baseline(data, time=time_interval) mout = math(select(out, time=time_interval), operator_name='mean', axis='time') assert_array_almost_equal(mout(trial=0), array([1, 1])) out = apply_baseline(data, time=time_interval, baseline='zscore') mout = math(select(out, time=time_interval), operator_name='mean', axis='time') assert_array_almost_equal(mout(trial=0), array([0, 0])) out = apply_baseline(data, time=time_interval, baseline='percent') mout = math(select(out, time=time_interval), operator_name='mean', axis='time') assert_array_almost_equal(mout(trial=0), array([0, 0])) freq_interval = (10, 15) freq = frequency(data) out = apply_baseline(freq, freq=freq_interval, baseline='dB') mout = math(select(out, freq=freq_interval), operator_name='mean', axis='freq') assert_array_almost_equal(mout(trial=0), array([0, 0])) out = apply_baseline(freq, freq=freq_interval, baseline='normchange') assert out.data[0].max() <= 1 assert out.data[0].min() >= -1
def compute_percent(hfa_A, hfa_B): x_A = math(hfa_A, operator_name='mean', axis=hfa_A.list_of_axes[1]) x_B = math(hfa_B, operator_name='mean', axis=hfa_A.list_of_axes[1]) perc = (x_A(trial=0) - x_B(trial=0)) / x_B(trial=0) * 100 data_perc = Data(perc, hfa_A.s_freq, chan=hfa_A.chan[0]) return data_perc
def test_math_operator_name_on_axis(): data1 = math(data, operator_name='mean', axis='time') assert len(data1.axis) == data1.data[0].ndim assert len(data1.axis['chan'][0]) == data1.data[0].shape[0] data1 = math(data, operator_name='mean', axis='chan') assert len(data1.axis) == data1.data[0].ndim assert len(data1.axis['time'][0]) == data1.data[0].shape[0]
def estimate_ieeg_prf(ieeg_file, method, freq=(60, 80)): with ieeg_file.open('rb') as f: data = load(f) stimuli = data.attr['stimuli'] data = select(data, freq=freq) data = math(data, operator_name='mean', axis='time') data = math(data, operator_name='mean', axis='freq') data = concatenate(data, 'trial') compute_prf(ieeg_file, data.data[0], data.chan[0], stimuli, method) return replace_extension(ieeg_file, 'prf.tsv')
def reject_channels(dat, reject_chan_thresh): dat_std = math(dat, operator_name='nanstd', axis='time') THRESHOLD = reject_chan_thresh x = dat_std.data[0] thres = [mean(x) + THRESHOLD * std(x)] clean_labels = list(dat_std.chan[0][dat_std.data[0] < thres]) return clean_labels
def test_trans_timefrequency_spectrogram(): seed(0) data = create_data(n_trial=1, n_chan=2, s_freq=s_freq, time=(0, dur)) # the first channel is ~5 times larger than the second channel data.data[0][0, :] *= 5 timefreq = timefrequency(data, method='spectrogram', detrend=None, taper=None, overlap=0) p_time = math(data, operator_name=('square', 'sum'), axis='time') p_freq = math(timefreq, operator_name='sum', axis='freq') assert (4.7**2 < p_freq.data[0][0, :] / p_freq.data[0][1, :]).all() assert (p_freq.data[0][0] / p_freq.data[0][1] < 5.7**2).all() # with random data, parseval only holds with boxcar assert_array_almost_equal(p_time(trial=0), sum(p_freq(trial=0) * data.s_freq, axis=1))
def correct_baseline(freq_A, freq_B, frequency): move = select(freq_A, freq=frequency) rest = select(freq_B, freq=frequency) merged = merge_datasets(move, rest) merged = concatenate(merged, 'time') baseline = math(merged, operator_name='mean', axis='time') move.data[0] /= baseline.data[0][:, None, :] rest.data[0] /= baseline.data[0][:, None, :] return move, rest
def test_math_diff(): data1 = math(data, operator_name='diff', axis='time') # shape should not change assert_array_equal(data1.data[0].shape, data.data[0].shape) assert_array_equal(data1.data[-1].shape, data.data[-1].shape) # check that the values are correct dat = data(trial=0, chan='chan01')[2] - data(trial=0, chan='chan01')[1] dat1 = data1(trial=0, chan='chan01')[2] assert dat == dat1
def pipeline_fitting(subject, run, model_name, response=None, event_type='cues'): """ response : str if None, it's trial-based 'mean' : take the mean for that channel """ data, names = load('data', subject, run, event_type=event_type) electrodes = load('electrodes', subject, run) surf = load('surface', subject, run) tf_m = compute_timefreq(data, baseline=P['spectrum']['baseline']['type'], mean=False) data = get_chantime(tf_m) model = MODELS[model_name] if model['type'] == 'trial-based' and response is None: data = math(data, operator_name='mean', axis='time') elif model['type'] == 'time-based' and response is not None: raise ValueError('You cannot use a time-based model and use an empirical response') if model.get('grouped', False): data, names = group_per_condition(data, names) if response is None: parallel = True else: parallel = False model['response'] = response result = fit_data(model, data, names, parallel=parallel) divs = [] fig = estimate_and_plot(get_trialdata(data), model, names, result, data.chan[0]) divs.append(to_div(fig)) for param in (['rsquared', ] + list(model['parameters'])): if param == 'rsquared' or model['parameters'][param]['to_plot']: fig = plot_prf_results(result, param, data.chan[0], electrodes, surf) divs.append(to_div(fig)) html_file = FITTING_DIR / model_name / FOLDER_NAME / f'{subject}_run-{run}_{event_type}.html' to_html(divs, html_file) output = [ f"{nanmax(result['rsquared']):0.3f}", f"{(result['rsquared'] >= 0.10).sum():d} / {len(result):d}", ] csv_file = html_file.with_suffix('.csv') export_results(result, data, csv_file) return output
def compute_quick_spectrogram(ieeg_file, freq): with ieeg_file.open('rb') as f: data = load(f) # TODO: from parameters reref = 'average' method = 'spectrogram' duration = 2 data = montage(data, ref_to_avg=True, method=reref) tf = timefrequency(data, method=method, duration=duration) dat0 = math(select(tf, freq=freq), operator_name='mean', axis='freq') return dat0
def test_copy_axis(): """Sometimes we remove an axis. So when we copy it, we need to make sure that the new dataset doesn't have the removed axis. """ # remove one axis data = create_data() data = math(data, axis='chan', operator_name='mean') assert len(data.axis) == 1 output = data._copy(axis=True) assert len(data.axis) == len(output.axis) output = data._copy(axis=False) assert len(data.axis) == len(output.axis)
def find_tstat_per_finger(subject, run, event_type='cues'): """Get tstat for each finger TODO ---- this function can be merged with the one above """ data, names = load('data', subject, run, event_type=event_type) tf = compute_timefreq(data, mean=False) tf_m = math(tf, operator_name='mean', axis='trial_axis') tf_cht = get_chantime(tf_m) best_chan, best_time = find_max_point(tf_cht) tf_ch = get_chan(tf, time=best_time) t, events = group_per_condition(tf_ch, names, 'tstat') return t, events
def find_activity_per_finger(subject, run, event_type='cues'): """ TODO ---- this function could be rewritten using preexisting code """ data, events = load('data', subject, run, event_type=event_type) tf = compute_timefreq(data, mean=True) tf = get_chantime(tf) best_time = find_max_point(tf)[1] tf = compute_timefreq(data, mean=False) tf = get_chan(tf, time=best_time) values = {} for f in FINGERS: i_finger = create_bool(events, f) tf_finger = select(tf, trial_axis=i_finger) tf_finger_chan = math(tf_finger, operator_name='mean', axis='trial_axis') values[f] = tf_finger_chan(trial=0) v = c_[values['thumb'], values['index'], values['middle'], values['ring'], values['little']] return v, tf.chan[0]
def test_trans_frequency(): seed(0) data = create_data(n_trial=1, n_chan=2, s_freq=s_freq, time=(0, dur)) # the first channel is ~5 times larger than the second channel data.data[0][0, :] *= 5 # with random data, parseval only holds with boxcar freq = frequency(data, detrend=None, taper=None, scaling='power') p_time = math(data, operator_name=('square', 'sum'), axis='time') p_freq = math(freq, operator_name='sum', axis='freq') assert_array_almost_equal(p_time(trial=0), p_freq(trial=0) * s_freq) # one channel is 5 times larger than the other channel, # the square of this relationship should hold in freq domain freq = frequency(data, detrend=None, taper=None, scaling='power', duration=1) p_freq = math(freq, operator_name='sum', axis='freq') assert 4.7**2 < (p_freq.data[0][0] / p_freq.data[0][1]) < (5.4**2) freq = frequency(data, detrend=None, taper=None, scaling='energy', duration=1) p_freq = math(freq, operator_name='sum', axis='freq') assert 4.7**2 < (p_freq.data[0][0] / p_freq.data[0][1]) < (5.4**2) freq = frequency(data, detrend=None, taper='dpss', scaling='power') p_freq = math(freq, operator_name='sum', axis='freq') assert 4.7**2 < (p_freq.data[0][0] / p_freq.data[0][1]) < (5.4**2) freq = frequency(data, detrend=None, sides='two') p_freq = math(freq, operator_name='sum', axis='freq') assert 4.7**2 < (p_freq.data[0][0] / p_freq.data[0][1]) < (5.45**2)
def extract_band_power( edf_filepath: str, bands: dict = pysleep_defaults.default_freq_bands, chans_to_consider: List[str] = None, epochoffset_secs: float = None, end_time: float = None, epoch_len: int = pysleep_defaults.epoch_len) -> pd.DataFrame: """ :param edf_filepath: The edf to extract bandpower for :param bands: bands to extract power in, if None, then defaults will be used i.e. bands = { 'delta': (1, 4), 'theta': (4, 7), 'alpha': (8, 12), 'sigma': (11, 16), 'slow_sigma': (11, 13), 'fast_sigma': (13, 16), 'beta': (13, 30) } :param chans_to_consider: which channels to consider :param epochoffset_secs: start time of the recording to extract band power for (when do epochs start), onset is measured from this :param end_time: end time of the recording to extract band power for :param epoch_len: how long a time bin you want your power to be averaged over :return: chan_epoch_band as a numpy array, and times, bands, chans """ d = Dataset(edf_filepath) if not (epochoffset_secs is None or epochoffset_secs >= 0): raise error_handling.EEGError('Epochoffset is negative!' + str(epochoffset_secs)) if not ((end_time is None) or (end_time <= d.header['n_samples'] / d.header['s_freq'])): raise error_handling.EEGError("end time (" + str(end_time) + ") larger than record end!" + str(d.header['n_samples'] / d.header['s_freq'])) data = d.read_data(begtime=epochoffset_secs, endtime=end_time, chan=chans_to_consider) power = timefrequency(data, method='spectrogram') abs_power = math(power, operator_name='abs') chan_time_freq = abs_power.data[0] all_chans = np.ones((chan_time_freq.shape[0], ), dtype=bool) epochoffset_secs = 0 if epochoffset_secs is None else epochoffset_secs time_axis = np.round(abs_power.axis['time'][0], 2) - epochoffset_secs freq_axis = np.round(abs_power.axis['freq'][0], 2) chan_axis = abs_power.axis['chan'][0] freq_binsize = freq_axis[1] - freq_axis[0] assert epoch_len > 0, "epoch len must be greater than zero" times = np.arange(0, time_axis[-1], epoch_len) cont = [] for band, freqs in bands.items(): freq_mask = (freqs[0] <= freq_axis) & (freqs[1] >= freq_axis) for win_start in times: time_mask = (win_start < time_axis) & (time_axis < win_start + epoch_len) idx = np.ix_(all_chans, time_mask, freq_mask) if idx: chan_epoch_per_band = chan_time_freq[idx].mean(axis=1).mean( axis=1) / freq_binsize else: chan_epoch_per_band = np.zeros((len(chans_to_consider), )) for chan, power in zip(chan_axis, chan_epoch_per_band): cont.append( pd.Series({ 'onset': win_start, 'duration': epoch_len, 'band': band.split('_')[0], 'chan': chan, 'power': power })) band_power = pd.concat( cont, axis=1).T.apply(lambda x: pd.to_numeric(x, errors='ignore')) return band_power
def merge(freq, method, frequency): freq = select(freq, freq=frequency) if method == '1a': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='mean', axis='freq') # only one value out = Data(freq.data[0][:, None], freq.s_freq, chan=freq.chan[0], time=(0, )) elif method == '1b': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='dB') freq = math(freq, operator_name='mean', axis='freq') freq = math(freq, operator_name='mean', axis='time') # only one value out = Data(freq.data[0][:, None], freq.s_freq, chan=freq.chan[0], time=(0, )) elif method == '1c': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='mean', axis='freq') freq = math(freq, operator_name='dB') freq = math(freq, operator_name='mean', axis='time') # only one value out = Data(freq.data[0][:, None], freq.s_freq, chan=freq.chan[0], time=(0, )) elif method == '1d': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='mean', axis='freq') freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='dB') # only one value out = Data(freq.data[0][:, None], freq.s_freq, chan=freq.chan[0], time=(0, )) elif method == '2a': freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='mean', axis='freq') # one value per trial out = concatenate(freq, axis='trial') elif method == '2b': freq = math(freq, operator_name='dB') freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='mean', axis='freq') # one value per trial out = concatenate(freq, axis='trial') elif method == '2c': freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='dB') freq = math(freq, operator_name='mean', axis='freq') # one value per trial out = concatenate(freq, axis='trial') elif method == '2d': freq = math(freq, operator_name='mean', axis='time') freq = math(freq, operator_name='mean', axis='freq') freq = math(freq, operator_name='dB') # one value per trial out = concatenate(freq, axis='trial') elif method == '3a': freq = concatenate(freq, axis='time') # values per time point out = math(freq, operator_name='mean', axis='freq') elif method == '3b': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='dB') # values per time point out = math(freq, operator_name='mean', axis='freq') elif method == '3c': freq = concatenate(freq, axis='time') freq = math(freq, operator_name='mean', axis='freq') # values per time point out = math(freq, operator_name='dB') elif method == 'dh2012': # identical to 3b, but use log instead of dB freq = concatenate(freq, axis='time') freq = math(freq, operator_name='log') # values per time point out = math(freq, operator_name='mean', axis='freq') return out
def test_math_incompatible_parameters(): with raises(TypeError): math(operator_name=('square'), operator=(power))
def extract_broadband(data, method): if method == '1': # 'abs(hilbert)' data = math(data, operator=whiten) data = math(data, operator=mean, axis='filter') data = math(data, operator_name=['hilbert', 'abs'], axis='time') elif method == '2': # 'abs(hilbert(bp))' data = math(data, operator=whiten) data = math(data, operator_name='mean', axis='filter') data = math(data, operator_name=['hilbert', 'abs', 'square'], axis='time') elif method == '3': # 'abs(hilbert(sum(whiten(bp))))' data = math(data, operator=whiten) data = math(data, operator_name=['hilbert', 'abs'], axis='time') data = math(data, operator=gmean, axis='filter') elif method == '4': # 'sum(abs(hilbert(whiten(bp))))' data = math(data, operator=whiten) data = math(data, operator_name=['hilbert', 'abs', 'square'], axis='time') data = math(data, operator=gmean, axis='filter') elif method == '5': # 'sum(abs(hilbert(bp)))' data = math(data, operator_name=['hilbert', 'abs', 'square'], axis='time') data = math(data, operator=gmean, axis='filter') return data
def test_math_incorrectly_on_axis_tuple(): with raises(TypeError): math(operator_name=('square', 'mean', 'sqrt'))
def test_math_operator_name(): data1 = math(data, operator_name='square') assert_array_equal(data1.data[0]**.5, abs(data.data[0]))
def test_own_funct(): def func(x, axis, keepdims=None): return nanmax(x, axis=axis) m_data = math(data, operator=func, axis='time') assert len(m_data.list_of_axes) == 1
def test_math_lambda_with_axis(): std_ddof = lambda x, axis: std(x, axis, ddof=1) math(data, operator=std_ddof, axis='time')
def test_math_lambda(): p3 = lambda x: power(x, 3) math(data, operator=(p3, ))
def test_math_twice_on_same_axis(): with raises(ValueError): math(data, operator_name=('mean', 'std'), axis='time')
def timeseries_ieeg(parameters): ieeg_dir = parameters['paths']['output'] / 'workflow' / 'ieeg' subject = parameters['plot']['subject'] freq = parameters['ieeg']['ecog_compare']['frequency_bands'][-1] ieeg_subj_dir = ieeg_dir / f'_subject_{subject}' ieeg_compare_file = next( ieeg_subj_dir.glob( f'_frequency_{freq[0]}.{freq[1]}/ecog_compare/sub-*_compare.tsv')) ieeg0_file = next(ieeg_subj_dir.rglob('*_task-motoractive_*_ieeg.pkl')) ieeg1_file = next(ieeg_subj_dir.rglob('*_task-motorbaseline_*_ieeg.pkl')) subj_dir = parameters['paths']['input'] / f'sub-{subject}' events_ieeg_file = next(subj_dir.glob('ses-*/ieeg/*_events.tsv')) dat0 = compute_quick_spectrogram(ieeg0_file, freq) dat1 = compute_quick_spectrogram(ieeg1_file, freq) dat = dat0._copy() dat.data = concat([dat0.data, dat1.data]) dat.axis['time'] = concat([dat0.time, dat1.time]) dat.axis['chan'] = concat([dat0.chan, dat1.chan]) dat = concatenate(dat, axis='time') ieeg_compare = read_tsv(ieeg_compare_file) chans = ieeg_compare['channel'][ieeg_compare['measure'] > 10] x0 = math(select(dat, chan=chans), operator_name='mean', axis='chan') t = dat.time[0] x = x0(trial=0) i_t = argsort(t) events = read_tsv(events_ieeg_file) i_start = where(events['trial_type'] == 'rest')[0][0] offset = events['onset'][i_start] events['onset'] -= offset traces = [ go.Scatter(x=t[i_t] - offset, y=x[i_t], line=dict(color='black', )), ] layout = merge( LAYOUT, dict( height=100, width=450, xaxis=dict( tick0=0, dtick=30, range=(0, 330), ), yaxis=dict( dtick=0.1, range=(0, 0.4), ), shapes=event_shapes(events), ), ) fig = go.Figure(data=traces, layout=layout) return fig
def test_math_operator_name_tuple(): data1 = math(data, operator_name=('hilbert', 'abs'), axis='time') assert data1.data[0].shape == data.data[0].shape
def test_trans_frequency_doc_01(): # generate data data = create_data(n_chan=2, signal='sine', amplitude=1) traces = [ go.Scatter( x=data.time[0], y=data(trial=0, chan='chan00')) ] layout = go.Layout( xaxis=dict( title='Time (s)'), yaxis=dict( title='Amplitude (V)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_01_data') # default options freq = frequency(data, detrend=None) traces = [ go.Scatter( x=freq.freq[0], y=freq(trial=0, chan='chan00')) ] layout = go.Layout( xaxis=dict( title='Frequency (Hz)', range=(0, 20)), yaxis=dict( title='Amplitude (V<sup>2</sup>/Hz)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_02_freq') # Parseval's theorem p_time = math(data, operator_name=('square', 'sum'), axis='time') p_freq = math(freq, operator_name='sum', axis='freq') assert_array_almost_equal(p_time(trial=0), p_freq(trial=0) * data.s_freq) # generate very long data data = create_data(n_chan=1, signal='sine', time=(0, 100)) freq = frequency(data, taper='hann', duration=1, overlap=0.5) traces = [ go.Scatter( x=freq.freq[0], y=freq(trial=0, chan='chan00')), ] layout = go.Layout( xaxis=dict( title='Frequency (Hz)', range=(0, 20)), yaxis=dict( title='Amplitude (V<sup>2</sup>/Hz)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_03_welch') # dpss data = create_data(n_chan=1, signal='sine') freq = frequency(data, taper='dpss', halfbandwidth=5) traces = [ go.Scatter( x=freq.freq[0], y=freq(trial=0, chan='chan00')), ] layout = go.Layout( xaxis=dict( title='Frequency (Hz)', range=(0, 20)), yaxis=dict( title='Amplitude (V<sup>2</sup>/Hz)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_04_dpss') # ESD DURATION = 2 data = create_data(n_chan=1, signal='sine', time=(0, DURATION)) data.data[0][0, :] *= hann(data.data[0].shape[1]) traces = [ go.Scatter( x=data.time[0], y=data(trial=0, chan='chan00')) ] layout = go.Layout( xaxis=dict( title='Time (s)'), yaxis=dict( title='Amplitude (V)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_05_esd') freq = frequency(data, detrend=None, scaling='energy') traces = [ go.Scatter( x=freq.freq[0], y=freq(trial=0, chan='chan00')) ] layout = go.Layout( xaxis=dict( title='Frequency (Hz)', range=(0, 20)), yaxis=dict( title='Amplitude (V<sup>2</sup>)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_06_esd') # Parseval's theorem p_time = math(data, operator_name=('square', 'sum'), axis='time') p_freq = math(freq, operator_name='sum', axis='freq') assert_array_almost_equal(p_time(trial=0), p_freq(trial=0) * data.s_freq * DURATION) # Complex data = create_data(n_chan=1, signal='sine') freq = frequency(data, output='complex', sides='two', scaling='energy') traces = [ go.Scatter( x=freq.freq[0], y=abs(freq(trial=0, chan='chan00', taper=0))) ] layout = go.Layout( xaxis=dict( title='Frequency (Hz)' ), yaxis=dict( title='Amplitude (V)'), ) fig = go.Figure(data=traces, layout=layout) save_plotly_fig(fig, 'freq_07_complex')
def test_math_operator_name_tuple_axis(): data1 = math(data, operator_name=('square', 'mean', 'sqrt'), axis='time') assert data1.data[0].shape == (data.number_of('chan')[0], )
def test_math_incorrectly_on_axis(): with raises(TypeError): math(operator=mean)