import matplotlib.pyplot as plt import numpy as np import utils as ut from definitions import SAVE_PATH_FIGURES """ Plot the mean coherence over subjects. select for every subject the channel with the largest amplitude in coherence. """ # load data suffix = '' window_length = 1024 data = ut.load_data_analysis('coh_icoh_allsubjects_w{}_{}.p'.format( window_length, suffix)) # now make a plot of all selected channels and the histogram over peaks f = data['frequs'] mask = ut.get_array_mask(f > 1, f < 30) coh_mat = data['coh_mat'][:, :, mask] icoh_mat = data['icoh_mat'][:, :, mask] n_subjects, n_channels, n_frequ_samples = coh_mat.shape max_coh_channels = np.zeros((n_subjects, n_frequ_samples)) max_icoh_channels = np.zeros((n_subjects, n_frequ_samples)) for subject_idx in range(n_subjects): # select the channel with the largest coherence channel_idx = np.argmax(np.max(coh_mat[subject_idx, ], axis=1)) max_coh_channels[subject_idx, ] = coh_mat[subject_idx, channel_idx, :] max_icoh_channels[subject_idx, ] = icoh_mat[subject_idx, channel_idx, :] # take mean and SE over subjects
# look at the pac data and select useful frequency ranges for every condition, hemisphere and mean channel # look at left and right values separately pac_left = pac_matrix[left_channel_idx, ].mean( axis=(0, 2)) # mean over channels within a hemisphere pac_right = pac_matrix[right_channel_idx, ].mean( axis=(0, 2)) # , and over amp f? # new shape: (phase-f) # goal: find bands for every hemisphere bands = dict(left=[], right=[]) for condition_idx, condition in enumerate(conditions): # for left # consider reasonable beta range mask = ut.get_array_mask(f_phase > 10, f_phase < 40).squeeze() f_mask = f_phase[mask] data = pac_left[condition_idx, mask] # smooth the mean PAC smoother_pac_left = ut.smooth_with_mean_window(data, window_size=5) max_idx = np.argmax(smoother_pac_left) # plt.subplot(1, 2, 1) # plt.title('Subject {}, {}'.format(subject_id, 'left')) # plt.plot(f_mask, data, alpha=.5) # plt.plot(f_mask, smoother_pac_left, label=condition) # plt.plot(f_mask[max_idx], smoother_pac_left[max_idx], 'ro') # plt.legend() # select the band +-5 Hz around the peak bands['left'].append([f_mask[max_idx] - 5, f_mask[max_idx] + 5])
rdsr = np.zeros(n_epochs) mpl = np.zeros(n_epochs) # mean phase vector length mpa = np.zeros(n_epochs) # amplitude beta_amp = np.zeros(n_epochs) # for every epoch for epoch_idx, epoch in enumerate(channel_lfp.T): # do preprocessing a la Cole et al # low pass filter lfp_pre = ut.low_pass_filter(y=epoch, fs=fs, cutoff=100, numtaps=250) # extract beta amplitude # calculate psd frequs, psd = ut.calculate_psd(lfp_pre, fs=fs, window_length=1024) # get the mask of the current band band_mask = ut.get_array_mask(frequs >= beta_bands[subject_idx][0], frequs <= beta_bands[subject_idx][1]) # calculate beta amplitude beta_amp[epoch_idx] = np.mean(psd[band_mask]) # band pass filter lfp_band = ut.band_pass_iir(y=lfp_pre, fs=fs, band=beta_bands[subject_idx]) # remove potential ringing artifacts idx_167ms = int((fs / 1000) * 167) lfp_band = lfp_band[idx_167ms:-idx_167ms] lfp_band -= lfp_band.mean() lfp_pre = lfp_pre[idx_167ms:-idx_167ms] lfp_pre -= lfp_pre.mean()
for epoch_idx, epoch in enumerate(channel_lfp.T): # do preprocessing a la Cole et al # low pass filter lfp_pre = ut.low_pass_filter(y=epoch, fs=fs, cutoff=100, numtaps=250) # extract beta amplitude # calculate psd frequs, psd = ut.calculate_psd(lfp_pre, fs=fs, window_length=1024) # get the mask of the current band band_mask = ut.get_array_mask(frequs >= current_band[0], frequs <= current_band[1]) # calculate beta amplitude beta_amp[epoch_idx] = np.mean(psd[band_mask]) # band pass filter lfp_band = ut.band_pass_iir(y=lfp_pre, fs=fs, band=current_band) # remove potential ringing artifacts idx_167ms = int((fs / 1000) * 167) lfp_band = lfp_band[idx_167ms:-idx_167ms] lfp_band -= lfp_band.mean() lfp_pre = lfp_pre[idx_167ms:-idx_167ms] lfp_pre -= lfp_pre.mean()
def plot_beta_band_selection_illustration_for_poster(pac_matrix_sig, pac_matrix_nonsig, sig_matrix1, sig_matrix2, n_phase, n_amplitude, f_phase, f_amp, mask, smoother_pac, max_idx, current_lfp_epochs, subject_id, fs, save=False): # plot both, the sig and the smoothed pac mean fontsize = 20 y_tick_steps = 3 x_tick_steps = 5 tick_size = 15 legend_size = 15 vmin = pac_matrix_sig.min() vmax = pac_matrix_sig.max() plt.figure(figsize=(15, 6)) # plot the PAC matrix plt.subplot2grid((2, 4), (0, 0), rowspan=2) current_pac_data = pac_matrix_nonsig plt.imshow(current_pac_data, interpolation='None', origin='lower', vmin=vmin, vmax=vmax) # plot contours of significance contours = measure.find_contours(sig_matrix2, 0) for n, contour in enumerate(contours): plt.plot(contour[:, 1], contour[:, 0], linewidth=.5, color='orange') plt.xticks(np.linspace(0, n_phase, y_tick_steps), np.linspace(f_phase.min(), f_phase.max(), y_tick_steps, dtype=int), fontsize=tick_size) plt.yticks(np.linspace(0, n_amplitude, x_tick_steps), np.linspace(f_amp.min(), f_amp.max(), x_tick_steps, dtype=int), fontsize=tick_size) plt.xlabel('Phase frequency [Hz]', fontsize=fontsize) plt.ylabel('Amplitude frequency [Hz]', fontsize=fontsize) plt.title('PAC, discarded', fontsize=fontsize) plt.colorbar( pad=0.02, fraction=.09, ticks=np.round( [vmin + 0.01, np.mean((vmin + 0.01, vmax - 0.01)), vmax - 0.01], 2)) plt.subplot2grid((2, 4), (0, 1), rowspan=2) current_pac_data = pac_matrix_sig plt.imshow(current_pac_data, interpolation='None', origin='lower', vmin=vmin, vmax=vmax) # plot contours of significance contours = measure.find_contours(sig_matrix1, 0) for n, contour in enumerate(contours): plt.plot(contour[:, 1], contour[:, 0], linewidth=.5, color='orange') plt.xticks(np.linspace(0, n_phase, y_tick_steps), np.linspace(f_phase.min(), f_phase.max(), y_tick_steps, dtype=int), fontsize=tick_size) plt.yticks(np.linspace(0, n_amplitude, x_tick_steps), np.linspace(f_amp.min(), f_amp.max(), x_tick_steps, dtype=int), fontsize=tick_size) plt.xlabel('Phase frequency [Hz]', fontsize=fontsize) plt.title('PAC, accepted', fontsize=fontsize) plt.tight_layout() # plot the smoothed PAC values averaged over amplitude frequencies: plt.subplot2grid((2, 4), (0, 2), colspan=2) plt.title('Peak PAC and selected beta range', fontsize=fontsize) plt.plot(f_phase[mask], smoother_pac) plt.ylabel('PAC', fontsize=fontsize) xtick_vals_smoothed = np.linspace(f_phase[mask].min(), f_phase[mask].max(), x_tick_steps, dtype=int) plt.xticks(np.linspace(f_phase[mask].min(), f_phase[mask].max(), x_tick_steps), xtick_vals_smoothed, fontsize=tick_size) y_tick_steps = 3 plt.yticks(np.linspace(smoother_pac.min(), smoother_pac.max(), y_tick_steps), np.round( np.linspace(smoother_pac.min(), smoother_pac.max(), y_tick_steps), 2), fontsize=tick_size) # plot the peak plt.axvline(f_phase[mask][max_idx], smoother_pac[max_idx], alpha=.3, color='C1') plt.plot(f_phase[mask][max_idx], smoother_pac[max_idx], 'o', markersize=8, label='peak PAC') plt.legend(frameon=False, prop={'size': legend_size}) # plot the PSD of the corresponding LFP plt.subplot2grid((2, 4), (1, 2), colspan=2) # calculate psd for every epoch, average across epochs f_psd, psd = ut.calculate_psd(y=current_lfp_epochs[:, 0], fs=fs, window_length=1024) # to get the dims for epoch_idx, lfp_epoch in enumerate(current_lfp_epochs[:, 1:].T): f_psd, psd_tmp = ut.calculate_psd(y=lfp_epoch, fs=fs, window_length=1024) psd += psd_tmp # divide by n epochs to average psd /= current_lfp_epochs.shape[1] # interpolate the psd to have the same sample point as in the PAC phase dimensions: psd_inter_f = scipy.interpolate.interp1d(f_psd, psd) psd = psd_inter_f(f_phase) plt.plot(f_phase[mask], psd[mask]) plt.xticks(np.linspace(f_phase[mask].min(), f_phase[mask].max(), x_tick_steps), xtick_vals_smoothed, fontsize=tick_size) plt.yticks(np.linspace(psd[mask].min(), psd[mask].max(), y_tick_steps), np.round( np.linspace(psd[mask].min(), psd[mask].max(), y_tick_steps), 1), fontsize=tick_size) plt.xlabel('Frequency [Hz]', fontsize=fontsize) plt.ylabel('PSD', fontsize=fontsize) # plot the peak and the selected range plt.axvline(f_phase[mask][max_idx], smoother_pac[max_idx], alpha=.5, color='C1') fill_mask = ut.get_array_mask(f_phase >= (f_phase[mask][max_idx] - 6), f_phase <= (f_phase[mask][max_idx] + 6)) plt.fill_between(f_phase, psd[mask].min(), psd[mask].max(), where=fill_mask, color='C1', alpha=0.1, label='selected') plt.legend(prop={'size': legend_size}, frameon=False) plt.tight_layout() if save: plt.savefig( os.path.join( SAVE_PATH_FIGURES, 'example_beta_range_selection_subj{}.pdf'.format(subject_id))) plt.show()
import matplotlib.pyplot as plt import numpy as np import utils as ut from definitions import SAVE_PATH_FIGURES """ Plot figure figure 1A from the Neumann et al 2017 paper manuscript: the average psd over subjects as well as the histogram over psd peaks in beta and in theta range """ # load data suffix = '_linear_search_and_amp' data = ut.load_data_analysis('psd_maxamp_theta_beta{}.p'.format(suffix)) # now make a plot of all selected channels and the histogram over peaks frequs = data['frequs'] mask = ut.get_array_mask(frequs > 4, frequs < 40) plt.figure(figsize=(7, 5)) # plot individual stectra # plt.plot(frequs[mask], data['psd_beta'][:, mask].T, linewidth=.7, color='C1', alpha=.5) # plt.plot(frequs[mask], data['psd_theta'][:, mask].T, linewidth=.7, color='C4', alpha=.5) # plot std envelope joined_psd_mean = np.mean(np.vstack((data['psd_theta'], data['psd_beta'])), axis=0) se = ut.standard_error(np.vstack((data['psd_theta'], data['psd_beta'])), axis=0) plt.fill_between(frequs[mask], joined_psd_mean[mask] + se[mask], joined_psd_mean[mask] - se[mask], alpha=.2, color='C3',
# for every subject file for sub, sub_file in enumerate(file_list): # load data d = ut.load_data_analysis(sub_file, data_folder=data_folder) # make new entries in the dict d['freqs'] = {} d['psd'] = {} for i, c in enumerate(d['conditions']): # notch filter around artefact in 24-26 Hz subharmonics of 50Hz noise d['lfp'][c] = ut.band_stop_filter(d['lfp'][c], d['fs'][c], band=[23, 27]) # get psd and save it freqs, psd = ut.calculate_psd(d['lfp'][c], d['fs'][c]) # interpolate between the neighboring bins to remove the dip mask = ut.get_array_mask(freqs > 23, freqs < 27) psd[mask] = np.mean(psd[[np.where(mask)[0][0]-1, np.where(mask)[0][-1]+1]]) d['freqs'][c], d['psd'][c] = freqs, psd # plotting mask = ut.get_array_mask(freqs > 2, freqs < 40) plt.plot(d['freqs'][c][mask], d['psd'][c][mask], label=c) plt.ylabel('power ') plt.xlabel('Frequency [Hz]') plt.title('Subject file {}, id {}'.format(sub_file[:-2], d['id']['rest'])) plt.legend() # save data ut.save_data(data_dict=d, filename='subject_{}_cleaned_psd.p'.format(d['number']),
# collect the psd of this mask in a matrix over subjects # prelocate with mask around the mean peak mean_peak_theta = data['theta_peaks_all'].mean() mean_peak_beta = data['beta_peaks_all'].mean() frequ_samples = 12 psd_range_mat_theta = -1 * np.ones((subject_mask.sum(), frequ_samples)) psd_range_mat_beta = -1 * np.ones((n_subjects, frequ_samples)) for sub in range(n_subjects): # get the peak peak_beta = data['beta_peaks_max'][sub] # build a mask -3, +8 Hz around the peak mask_beta = ut.get_array_mask(frequs > (peak_beta - 3), frequs < (peak_beta + 8)) beta_frequs = frequs[mask_beta] # collect the psd of this mask in a matrix psd_range_mat_beta[sub, ] = data['psd_beta'][sub, mask_beta] for sub in range(np.sum(subject_mask)): # get the peak peak_theta = theta_peaks[sub] # build a mask -3, +8 Hz around the peak mask_theta = ut.get_array_mask(frequs > peak_theta - 3, frequs < peak_theta + 8) # collect the psd of this mask in a matrix
for file in file_list: if file.startswith('spmeeg_'): d = ut.load_data_spm(file) fs = d['fsample'][0][0] channel_labels = d['chanlabels'][0] fig = plt.figure(figsize=(15, 8)) for i, lfp in enumerate(d['data']): f, t, sxx = ut.calculate_spectrogram(lfp, fs=fs) # transform to log ssx_log = np.log(sxx) # define a mask and build a grid mask = ut.get_array_mask(f > 4, f < 12) xgrid, ygrid = np.meshgrid(f[mask], t) # plotting ax = fig.add_subplot(3, 2, i + 1, projection='3d') surf = ax.plot_surface(X=xgrid, Y=ygrid, Z=ssx_log[mask, :].T, cmap='viridis') ax.set_xlabel('Frequency [Hz]') ax.set_ylabel('Time [s]') ax.set_zlabel('log power ') fig.colorbar(surf, shrink=0.5, aspect=5) # save figure filename_save = file[:-4] + '_spectro.pdf' plt.savefig(os.path.join(SAVE_PATH_FIGURES, filename_save)) # plt.show()
lfp = d['data'][idx] if lfp is None: raise ValueError( 'Could not find the specified channel in the data file: {}'.format( channel_name)) # remove mean lfp = lfp - np.mean(lfp) # filter in theta range: lfp_filt = band_pass_filter(y=lfp, fs=fs, band=[4, 12], plot_response=False) # construct the time vector dt = 1 / fs t = np.arange(0, d['data'].shape[1] * dt, dt) # design plotting mask window_length = 3 # in sec window_start = 250 mask = get_array_mask(t > window_start, t < window_start + window_length) plt.figure(figsize=(7, 3)) plt.plot(t[mask], lfp[mask], label='raw') plt.plot(t[mask], lfp_filt[mask], label='filtered') plt.ylabel('[$\muV]') plt.xlabel('time [s]') plt.title('contact pair GPiR23 from case 19') plt.legend() plt.savefig(os.path.join(SAVE_PATH_FIGURES, 'figure_1C.pdf')) # plt.show()
psds = np.zeros((n_channels, n_frequ_samples)) theta_peak_frequency = np.zeros(n_channels) beta_peak_frequency = np.zeros(n_channels) plt.figure(figsize=(10, 5)) for channel_idx, lfp in enumerate(d['data']): # remove 50Hz noise lfp_clean = lfp # lfp_clean = ut.band_stop_filter(lfp, fs, band=[49, 51], plot_response=False) # calculate psd frequs, psd = ut.calculate_psd(lfp_clean, fs=fs, window_length=window_length) # normalize like in the paper: take sd of the psd between 4-45 and 55-95Hz mask = np.logical_or(ut.get_array_mask(frequs > 5, frequs < 45), ut.get_array_mask(frequs > 55, frequs < 95)) psd /= np.std(psd[mask]) # remove 1 / f component # frequs_linear, psd_linear = ut.remove_1f_component(frequs, psd) # save for later psds[channel_idx, ] = psd # find peak in theta: use the linearized spectra for finding peaks idx_theta, peak_amp_theta, ftheta, psd_theta = ut.find_peak_in_band( frequs, psd, [4, 12], linearize=True) # save the frequency at which the peak occured, in one long list for the histogram theta_peaks[electrode_idx] = ftheta[idx_theta] # save it in a matrix to select it per subject for the alignment theta_peak_frequency[channel_idx] = ftheta[idx_theta]
# best band selection illustration plot for channel_idx, channel_label in enumerate(channel_labels): # the customized freqeuncy bands are saved per hemisphere, therefore we have to find the current hemi current_hemi = 'left' if channel_label in left_channels else 'right' # add a new list for condition bands of the current channel bands[current_hemi][channel_label] = [] for condition_idx, condition in enumerate(conditions): # get current lfp data current_lfp_epochs = lfp_dict[condition]['data'][channel_idx] # consider reasonable beta range mask = ut.get_array_mask(f_phase >= 12, f_phase <= 40).squeeze() f_mask = f_phase[mask] data = pac_phase[channel_idx, condition_idx, mask] # smooth the mean PAC smoother_pac = ut.smooth_with_mean_window(data, window_size=3) max_idx = np.argmax(smoother_pac) # sum logical significance values across the amplitude frequency dimension # calculate the binary groups in the significance map lw, num = measurements.label(sig_matrix[channel_idx, condition_idx, :, :]) # calculate the area of the clusters: # from http://stackoverflow.com/questions/25664682/how-to-find-cluster-sizes-in-2d-numpy-array area = measurements.sum(sig_matrix[channel_idx, condition_idx, ], lw, index=np.arange(lw.max() + 1)) # get the size of the largest group
# or conditions # or both bands = hemi_dict['bands'] f_phase = hemi_dict['f_phase'] # do it for every band for band_idx, band in enumerate(bands): # for PAC analysis # average across low beta and high and across all HFO amplitude frequencies # then average across channels # or look at channels independently # or conditions # or both # get the mask for the current band phase_band_mask = ut.get_array_mask(f_phase >= band[0], f_phase <= band[1]).squeeze() # extract pac values for the current phase band pac_phase_band = hemi_dict['pac_matrix'][:, :, :, phase_band_mask] # average over frequency amplitude and over low beta frequencies pac_phase_band = pac_phase_band.mean(axis=(-2, -1)) # save per condition and channel pac_results['per_cond_channel'][band_idx, hemi_idx, :, :] = pac_phase_band # save pac per channel pac_results['per_channel'][band_idx, hemi_idx, :] = pac_phase_band.mean( axis=1) # average over conditions