def calc_circ_stats(elec_pair_phase_diff, recalled, do_perm=False): if do_perm: recalled = np.random.permutation(recalled) # compute rayleigh on the phase difference elec_pair_pval, elec_pair_z = pycircstat.rayleigh(elec_pair_phase_diff, axis=0) # compute rvl on the phase difference elec_pair_rvl = pycircstat.resultant_vector_length(elec_pair_phase_diff, axis=0) # also compute for recalled and not recalled items elec_pair_pval_rec, elec_pair_z_rec = pycircstat.rayleigh(elec_pair_phase_diff[recalled], axis=0) elec_pair_pval_nrec, elec_pair_z_nrec = pycircstat.rayleigh(elec_pair_phase_diff[~recalled], axis=0) # and also compute resultant vector length elec_pair_rvl_rec = pycircstat.resultant_vector_length(elec_pair_phase_diff[recalled], axis=0) elec_pair_rvl_nrec = pycircstat.resultant_vector_length(elec_pair_phase_diff[~recalled], axis=0) return {'elec_pair_pval': elec_pair_pval, 'elec_pair_z': elec_pair_z, 'elec_pair_rvl': elec_pair_rvl, 'elec_pair_pval_rec': elec_pair_pval_rec, 'elec_pair_z_rec': elec_pair_z_rec, 'elec_pair_pval_nrec': elec_pair_pval_nrec, 'elec_pair_z_nrec': elec_pair_z_nrec, 'elec_pair_rvl_rec': elec_pair_rvl_rec, 'elec_pair_rvl_nrec': elec_pair_rvl_nrec}
def calc_circ_stats(elec_pair_phase_diff, recalled, do_perm=False): if do_perm: recalled = np.random.permutation(recalled) # compute rayleigh on the phase difference elec_pair_pval, elec_pair_z = pycircstat.rayleigh(elec_pair_phase_diff, axis=0) # compute rvl on the phase difference elec_pair_rvl = pycircstat.resultant_vector_length(elec_pair_phase_diff, axis=0) # also compute for recalled and not recalled items elec_pair_pval_rec, elec_pair_z_rec = pycircstat.rayleigh(elec_pair_phase_diff[recalled], axis=0) elec_pair_pval_nrec, elec_pair_z_nrec = pycircstat.rayleigh(elec_pair_phase_diff[~recalled], axis=0) # and also compute resultant vector length elec_pair_rvl_rec = pycircstat.resultant_vector_length(elec_pair_phase_diff[recalled], axis=0) elec_pair_rvl_nrec = pycircstat.resultant_vector_length(elec_pair_phase_diff[~recalled], axis=0) return {'elec_pair_pval': elec_pair_pval, 'elec_pair_z': elec_pair_z, 'elec_pair_rvl': elec_pair_rvl, 'elec_pair_pval_rec': elec_pair_pval_rec, 'elec_pair_z_rec': elec_pair_z_rec, 'elec_pair_pval_nrec': elec_pair_pval_nrec, 'elec_pair_z_nrec': elec_pair_z_nrec, 'elec_pair_rvl_rec': elec_pair_rvl_rec, 'elec_pair_rvl_nrec': elec_pair_rvl_nrec}
def head_direction_stats(head_angle_bins, rate): """ Calculeate firing rate at head direction in head angles for time t Parameters ---------- head_angle_bins : quantities.Quantity array in degrees binned head directions rate : np.ndarray firing rate magnitude coresponding to angles Returns ------- out : float, float mean angle, mean vector length """ import math import pycircstat as pc if head_angle_bins.units == pq.degrees: head_angle_bins = [math.radians(deg) for deg in head_angle_bins] * pq.radians nanIndices = np.where(np.isnan(rate))[0] nanIndices = np.unique(nanIndices) rate = np.delete(rate, nanIndices) head_angle_bins = np.delete(head_angle_bins, nanIndices) mean_ang = pc.mean(head_angle_bins, w=rate) mean_vec_len = pc.resultant_vector_length(head_angle_bins, w=rate) # ci_lim = pc.mean_ci_limits(head_angle_bins, w=rate) return math.degrees(mean_ang), mean_vec_len
def _make_tuples(self, key): repeats, poisson_rate, alpha, kappa = \ (PowerParameters() & key).fetch1['repeats', 'poisson_rate','alpha','kappa'] p = stats.poisson(poisson_rate) v = stats.vonmises(kappa) for trials in range(2, 15): print('Trials', trials) cut_off = self.compute_cutoff(poisson_rate, alpha, trials) beta = [] for r in range(repeats): n = p.rvs(trials) vs = np.mean([circ.resultant_vector_length(v.rvs(m) % (2*np.pi)) for m in n]) beta.append(vs < cut_off) self.insert1(dict(key, n=trials, power=1 - np.mean(beta)))
def _make_tuples(self, key): repeats, poisson_rate, alpha, kappa = \ (PowerParameters() & key).fetch1('repeats', 'poisson_rate','alpha','kappa') p = stats.poisson(poisson_rate) v = stats.vonmises(kappa) for trials in range(2, 15): print('Trials', trials) cut_off = self.compute_cutoff(poisson_rate, alpha, trials) beta = [] for r in range(repeats): n = p.rvs(trials) vs = np.mean([ circ.resultant_vector_length(v.rvs(m) % (2 * np.pi)) for m in n ]) beta.append(vs < cut_off) self.insert1(dict(key, n=trials, power=1 - np.mean(beta)))
def test_vector_strength_spectrum(): T = 3 # 2s sampling_rate = 10000. firing_rate = 10 # 1000Hz s = T * np.random.rand(np.random.poisson(firing_rate * T)) w, vs_spec = es.vector_strength_spectrum(s, sampling_rate) F0 = [] R = [] lowcut, highcut = 500, 550 idx = (w >= lowcut) & (w <= highcut) for i in np.where(idx)[0]: f0 = w[i] p0 = 1 / f0 rho = pycircstat.resultant_vector_length((s % p0) / p0 * 2 * np.pi) F0.append(f0) R.append(rho) assert_allclose(R, vs_spec[idx])
def test_vector_strength_spectrum(): T = 3 # 2s sampling_rate = 10000. firing_rate = 10 # 1000Hz s = T * np.random.rand(np.random.poisson(firing_rate * T)) w, vs_spec = es.vector_strength_spectrum(s, sampling_rate) F0 = [] R = [] lowcut, highcut = 500, 550 idx = (w >= lowcut) & (w <= highcut) for i in np.where(idx)[0]: f0 = w[i] p0 = 1 / f0 rho = pycircstat.resultant_vector_length((s % p0) / p0 * 2 * np.pi) F0.append(f0) R.append(rho) assert_allclose(R, vs_spec[idx])
def gaborbank_orientation_variance(d): """ Compute the orientation variance. Orientation variance can be any value from 0 (no variance, all responses point in one direction) to 1 (no dominant direction). Computed using pycircstat's mean resultant vector function. """ res = d['res'] theta = d['theta'] e = res.real**2 + res.imag**2 e = e.sum(axis=2) # sum energy over scales. # reshape the angles into an image plane for each angle: t = np.tile(theta, e.shape[0] * e.shape[1]) t = np.reshape(t, e.shape) # t has the same shape as e, with each orientation along axis 2. """compute orientation variance with energy as weights. Axial correction is to change direction 0-pi --> orientation 0-2*pi. Correct afterward by folding orientations > pi back around. """ out = circ.resultant_vector_length(t, w=e, axis=2, axial_correction=2) return 1 - out
def head_direction_score(head_angle_bins, rate): """ Calculeate firing rate at head direction in head angles for time t Parameters ---------- head_angle_bins : array in radians binned head directions rate : array firing rate magnitude coresponding to angles Returns ------- out : float, float mean angle, mean vector length """ import math import pycircstat as pc nanIndices = np.where(np.isnan(rate)) head_angle_bins = np.delete(head_angle_bins, nanIndices) mean_ang = pc.mean(head_angle_bins, w=rate) mean_vec_len = pc.resultant_vector_length(head_angle_bins, w=rate) # ci_lim = pc.mean_ci_limits(head_angle_bins, w=rate) return mean_ang, mean_vec_len
def gaborbank_orientation_variance(d): """ Compute the orientation variance. Orientation variance can be any value from 0 (no variance, all responses point in one direction) to 1 (no dominant direction). Computed using pycircstat's mean resultant vector function. """ res = d['res'] theta = d['theta'] e = res.real**2 + res.imag**2 e = e.sum(axis=2) # sum energy over scales. # reshape the angles into an image plane for each angle: t = np.tile(theta, e.shape[0]*e.shape[1]) t = np.reshape(t, e.shape) # t has the same shape as e, with each orientation along axis 2. """compute orientation variance with energy as weights. Axial correction is to change direction 0-pi --> orientation 0-2*pi. Correct afterward by folding orientations > pi back around. """ out = circ.resultant_vector_length(t, w=e, axis=2, axial_correction=2) return 1 - out
def plot_cluster_stats(self, cluster_name): """ Multi panel plot showing: 1. brain map of electrodes in the cluster, color-coded by phase 2. brain map of electrodes in the cluster, color-coded by subsequent memory effect 3. timecourse of resultant vector length of wave direction, averaged across trials 4. timecourse of r^2, averaged across trials 5. polor plot of left-frontal and hippocampal electrode phases 6/7. same as 5, but for recalled and not recalled items only Data are taken from the timepoint with the highest r-square value. Figure creation code is so ugly sorry. """ ############################ # GET TIME TIME FOR X-AXIS # ############################ time_axis = self.res['traveling_waves'][cluster_name]['time'] ##################### # SET UP THE FIGURE # ##################### gs = gridspec.GridSpec(6, 3) ax1 = plt.subplot(gs[0, :]) ax2 = plt.subplot(gs[2, :]) ax3 = plt.subplot(gs[3, :]) ax4 = plt.subplot(gs[4, 0], projection='polar') ax6 = plt.subplot(gs[4, 1], projection='polar') ax7 = plt.subplot(gs[4, 2], projection='polar') ax8 = plt.subplot(gs[5, 0], projection='polar') ax9 = plt.subplot(gs[5, 1], projection='polar') ax10 = plt.subplot(gs[5, 2], projection='polar') ax5 = plt.subplot(gs[1, :]) # some figure parameters fig = plt.gcf() fig.set_size_inches(15, 30) mpl.rcParams['xtick.labelsize'] = 18 mpl.rcParams['ytick.labelsize'] = 18 ############################################# # INFO ABOUT THE ELECTRODES IN THIS CLUSTER # ############################################# cluster_rows = self.res['clusters'][cluster_name].notna() regions_all = self.get_electrode_roi_by_hemi() regions = regions_all[cluster_rows]['merged_col'].unique() regions_str = ', '.join(regions) xyz = self.res['clusters'][cluster_rows][['x', 'y', 'z']].values ############################### # ROW 1: electrodes and phase # ############################### mean_r2 = np.nanmean(self.res['traveling_waves'][cluster_name]['cluster_r2_adj'], axis=1) argmax_r2 = np.argmax(mean_r2) print(argmax_r2) phases = self.res['traveling_waves'][cluster_name]['phase_data'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases[phases<0] += np.pi*2 # phases *= 180. / np.pi # phases -= phases.min() - 1 colors = np.stack([[0., 0., 0., 0.]] * len(phases)) cm = clrs.LinearSegmentedColormap.from_list('cm', cc.cyclic_mrybm_35_75_c68_s25) cNorm = clrs.Normalize(vmin=0, vmax=np.pi * 2) colors[~np.isnan(phases)] = cmx.ScalarMappable(norm=cNorm, cmap=cm).to_rgba(phases[~np.isnan(phases)]) ni_plot.plot_connectome(np.eye(xyz.shape[0]), xyz, node_kwargs={'alpha': 0.7, 'edgecolors': None}, node_size=45, node_color=colors, display_mode='lzr', axes=ax1) mean_freq = self.res['traveling_waves'][cluster_name]['mean_freq'] plt.suptitle('{0} ({1:.2f} Hz): {2}'.format(self.subject, mean_freq, regions_str), y=.9) divider = make_axes_locatable(ax1) cax = divider.append_axes('right', size='6%', pad=15) cb1 = mpl.colorbar.ColorbarBase(cax, cmap=cm, norm=cNorm, orientation='vertical', ticks=[0, np.pi / 2, np.pi, np.pi * 3 / 2, np.pi * 2]) cb1.ax.yaxis.set_ticklabels(['0°', '90°', '180°', '270°', '360°']) cb1.ax.tick_params(labelsize=14) for label in cb1.ax.yaxis.get_majorticklabels(): label.set_transform(label.get_transform() + mpl.transforms.ScaledTranslation(0.15, 0, fig.dpi_scale_trans)) ################################################## # ROW 2: electrodes and subsequent memory effect # ################################################## sme = self.res['traveling_waves'][cluster_name]['sme_t'][:, argmax_r2] colors = np.stack([[0., 0., 0., 0.]] * len(sme)) cm = plt.get_cmap('RdBu_r') clim = np.max(np.abs(sme)) cNorm = clrs.Normalize(vmin=-clim, vmax=clim) colors[~np.isnan(sme)] = cmx.ScalarMappable(norm=cNorm, cmap=cm).to_rgba(sme[~np.isnan(sme)]) ni_plot.plot_connectome(np.eye(xyz.shape[0]), xyz, node_kwargs={'alpha': 0.7, 'edgecolors': None}, node_size=45, node_color=colors, display_mode='lzr', axes=ax5) divider = make_axes_locatable(ax5) cax = divider.append_axes('right', size='6%', pad=15) cb2 = mpl.colorbar.ColorbarBase(cax, cmap='RdBu_r', norm=cNorm, orientation='vertical') cb2.ax.tick_params(labelsize=14) for label in cb2.ax.yaxis.get_majorticklabels(): label.set_transform(label.get_transform() + mpl.transforms.ScaledTranslation(0.15, 0, fig.dpi_scale_trans)) ############################ # ROW 3: timecourse of RVL # ############################ rvl = pycircstat.resultant_vector_length(self.res['traveling_waves'][cluster_name]['cluster_wave_ang'], axis=1) ax2.plot(time_axis, rvl, lw=2) ax2.set_ylabel('RVL', fontsize=20) ################################## # ROW 4: timecourse of r-squared # ################################## ax3.plot(time_axis, np.nanmean(self.res['traveling_waves'][cluster_name]['cluster_r2_adj'], axis=1), lw=2) ax3.set_xlabel('Time (ms)', fontsize=20) ax3.set_ylabel('mean($R^{2}$)', fontsize=20) ############################ # ROW 5a: phase polar plots # ############################ # phases = np.deg2rad(phases) cluster_regions = regions_all[cluster_rows]['merged_col'] phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax4.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax4.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax4.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax4.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax4.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax4.spines['polar'].set_visible(False) ax4.set_ylim(0, 1.3) ax4.set_yticklabels([]) ax4.set_aspect('equal', 'box') red_patch = mpatches.Patch(color='#67a9cf', label='L. Frontal') blue_patch = mpatches.Patch(color='#ef8a62', label='Hipp') _ = ax4.legend(handles=[red_patch, blue_patch], loc='lower left', bbox_to_anchor=(0.9, 0.9), frameon=False, fontsize=16) ################################################ # ROW 5b: phase polar plots for recalled items # ################################################ phases = self.res['traveling_waves'][cluster_name]['phase_data_recalled'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases *= 180. / np.pi # phases -= phases.min() - 1 # phases = np.deg2rad(phases) phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax6.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax6.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax6.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax6.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax6.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax6.spines['polar'].set_visible(False) ax6.set_ylim(0, 1.3) ax6.set_yticklabels([]) ax6.set_aspect('equal', 'box') ax6.set_title('Recalled items', y=1.12) #################################################### # ROW 5c: phase polar plots for not recalled items # #################################################### phases = self.res['traveling_waves'][cluster_name]['phase_data_not_recalled'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases *= 180. / np.pi # phases -= phases.min() - 1 # phases = np.deg2rad(phases) phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax7.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax7.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax7.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax7.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax7.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax7.spines['polar'].set_visible(False) ax7.set_ylim(0, 1.3) ax7.set_yticklabels([]) ax7.set_aspect('equal', 'box') ax7.set_title('Not recalled items', y=1.12) #################################################### # ROW 6: #################################################### recalled = self.res['traveling_waves']['cluster1']['recalled'] if ('left-Frontal' in self.res['traveling_waves'][cluster_name]['phase_by_roi']) & \ ('both-Hipp' in self.res['traveling_waves'][cluster_name]['phase_by_roi']): phase_by_roi = self.res['traveling_waves'][cluster_name]['phase_by_roi'] phase_left_front_roi = phase_by_roi['left-Frontal'][:, argmax_r2] # phase_left_front_roi = (phase_left_front_roi + np.pi) % (2 * np.pi) phase_hipp_roi = phase_by_roi['both-Hipp'][:, argmax_r2] # phase_hipp_roi = (phase_hipp_roi + np.pi) % (2 * np.pi) # phase_left_front_roi = (phase_left_front_roi + np.pi) % (2 * np.pi) - np.pi # phase_left_front_roi *= 180. / np.pi # phase_left_front_roi -= phase_left_front_roi.min() - 1 # phase_left_front_roi = np.deg2rad(phase_left_front_roi) # phase_hipp_roi = (phase_hipp_roi + np.pi) % (2 * np.pi) - np.pi # phase_hipp_roi *= 180. / np.pi # phase_hipp_roi -= phase_hipp_roi.min() - 1 # phase_hipp_roi = np.deg2rad(phase_hipp_roi) # LEFT ax8 = self.rose_plot(phase_left_front_roi, n_bins=30, ax=ax8) ax8 = self.rose_plot(phase_hipp_roi, n_bins=30, ax=ax8) ax8.spines['polar'].set_visible(False) ax8.set_yticks([ax8.get_ylim()[1]]) ax8.set_aspect('equal', 'box') ax8.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax8.plot([r, r], [0, ax8.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax8.grid() # MIDDLE ax9 = self.rose_plot(phase_left_front_roi[recalled], n_bins=30, ax=ax9) ax9 = self.rose_plot(phase_hipp_roi[recalled], n_bins=30, ax=ax9) ax9.spines['polar'].set_visible(False) ax9.set_yticks([ax9.get_ylim()[1]]) ax9.set_aspect('equal', 'box') ax9.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax9.plot([r, r], [0, ax9.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax9.grid() # RIGHT ax10 = self.rose_plot(phase_left_front_roi[~recalled], n_bins=30, ax=ax10) ax10 = self.rose_plot(phase_hipp_roi[~recalled], n_bins=30, ax=ax10) ax10.spines['polar'].set_visible(False) ax10.set_yticks([ax10.get_ylim()[1]]) ax10.set_aspect('equal', 'box') ax10.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax10.plot([r, r], [0, ax10.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax10.grid() plt.subplots_adjust(hspace=.5) return fig
def compute_phase_stats_with_shuffle(events, spike_rel_times, phase_data_hilbert, phase_bin_start, phase_bin_stop, do_permute=False, shuffle_type=1): spike_rel_times_tmp = spike_rel_times.copy() e_tmp = events.copy() if do_permute: if shuffle_type == 1: # permute the novel novel_events = np.where(events.isFirst.values)[0] perm_novel_events = np.random.permutation(novel_events) spike_rel_times_tmp[novel_events] = spike_rel_times_tmp[perm_novel_events] # and repeated separately rep_events = np.where(~events.isFirst.values)[0] perm_rep_events = np.random.permutation(rep_events) spike_rel_times_tmp[rep_events] = spike_rel_times_tmp[perm_rep_events] else: e_tmp['isFirst'] = np.random.permutation(e_tmp.isFirst) # get the phases at which the spikes occurred and bin into novel and repeated items for each hilbert band spike_phases_hilbert = _compute_spike_phase_by_freq(spike_rel_times_tmp, phase_bin_start, phase_bin_stop, phase_data_hilbert, events) # bin into repeated and novel phases novel_phases, rep_phases = _bin_phases_into_cond(spike_phases_hilbert, e_tmp) if (len(novel_phases) > 0) & (len(rep_phases) > 0): # test phase locking for all spikes comboined all_spikes_phases = np.vstack([novel_phases, rep_phases]) rayleigh_pval_all, rayleigh_z_all = pycircstat.rayleigh(all_spikes_phases, axis=0) rvl_all = pycircstat.resultant_vector_length(all_spikes_phases, axis=0) # rayleigh test for uniformity rvl_novel = pycircstat.resultant_vector_length(novel_phases, axis=0) rvl_rep = pycircstat.resultant_vector_length(rep_phases, axis=0) rvl_diff = rvl_novel - rvl_rep # compute rayleigh test for each condition rayleigh_pval_novel, rayleigh_z_novel = pycircstat.rayleigh(novel_phases, axis=0) rayleigh_pval_rep, rayleigh_z_rep = pycircstat.rayleigh(rep_phases, axis=0) rayleigh_diff = rayleigh_z_novel - rayleigh_z_rep # watson williams test for equal means ww_pval, ww_tables = pycircstat.watson_williams(novel_phases, rep_phases, axis=0) ww_fstat = np.array([x.loc['Columns'].F for x in ww_tables]) # kuiper test, to test for difference in dispersion (not mean, because I'm making them equal) kuiper_pval, stat_kuiper = pycircstat.kuiper(novel_phases - pycircstat.mean(novel_phases), rep_phases - pycircstat.mean(rep_phases), axis=0) return (rvl_novel, rvl_rep, rvl_diff, ww_fstat, stat_kuiper, rayleigh_z_novel, rayleigh_z_rep, rayleigh_diff, rayleigh_z_all, rvl_all), \ (rayleigh_pval_novel, rayleigh_pval_rep, ww_pval, kuiper_pval, rayleigh_pval_all), novel_phases, rep_phases else: return (np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2])), \ (np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2])), novel_phases, rep_phases
def compute_rvl_by_memory(recalled, data, do_perm=False): if do_perm: recalled = np.random.permutation(recalled) rec_rvl = pycircstat.resultant_vector_length(data[:, recalled], axis=1) nrec_rvl = pycircstat.resultant_vector_length(data[:, ~recalled], axis=1) return rec_rvl, nrec_rvl
def analysis(self): """ For each cluster in res['clusters']: 1. """ # make sure we have data if self.subject_data is None: print('%s: compute or load data first with .load_data()!' % self.subject) return # we must have 'clusters' in self.res if 'clusters' in self.res: self.res['traveling_waves'] = {} # get cluster names from dataframe columns cluster_names = list(filter(re.compile('cluster[0-9]+').match, self.res['clusters'].columns)) # get circular-linear regression parameters theta_r, params = self.compute_grid_parameters() # compute cluster stats for each cluster with Parallel(n_jobs=12, verbose=5) as parallel: for this_cluster_name in cluster_names: cluster_res = {} # get the names of the channels in this cluster cluster_elecs = self.res['clusters'][self.res['clusters'][this_cluster_name].notna()]['label'] # for the channels in this cluster, bandpass and then hilbert to get the phase info phase_data, power_data, cluster_mean_freq = self.compute_hilbert_for_cluster(this_cluster_name) # reduce to only time inverval of interest time_inds = (phase_data.time >= self.cluster_stat_start_time) & ( phase_data.time <= self.cluster_stat_end_time) phase_data = phase_data[:, :, time_inds] # get electrode coordinates in 2d norm_coords = self.compute_2d_elec_coords(this_cluster_name) # run the cluster stats for time-averaged data mean_rel_phase = pycircstat.mean(phase_data.data, axis=2) mean_cluster_wave_ang, mean_cluster_wave_freq, mean_cluster_r2_adj = \ circ_lin_regress(mean_rel_phase.T, norm_coords, theta_r, params) cluster_res['mean_cluster_wave_ang'] = mean_cluster_wave_ang cluster_res['mean_cluster_wave_freq'] = mean_cluster_wave_freq cluster_res['mean_cluster_r2_adj'] = mean_cluster_r2_adj # and run it for each time point num_times = phase_data.shape[-1] data_as_list = zip(phase_data.T, [norm_coords] * num_times, [theta_r] * num_times, [params] * num_times) res_as_list = parallel(delayed(circ_lin_regress)(x[0].data, x[1], x[2], x[3]) for x in data_as_list) cluster_res['cluster_wave_ang'] = np.stack([x[0] for x in res_as_list], axis=0).astype('float32') cluster_res['cluster_wave_freq'] = np.stack([x[1] for x in res_as_list], axis=0).astype('float32') cluster_res['cluster_r2_adj'] = np.stack([x[2] for x in res_as_list], axis=0).astype('float32') cluster_res['mean_freq'] = cluster_mean_freq cluster_res['channels'] = cluster_elecs.values cluster_res['time'] = phase_data.time.data cluster_res['phase_data'] = pycircstat.mean(phase_data, axis=1).astype('float32') cluster_res['phase_rvl'] = pycircstat.resultant_vector_length(phase_data, axis=1).astype('float32') # finally, compute the subsequent memory effect if hasattr(self, 'recall_filter_func') and callable(self.recall_filter_func): recalled = self.recall_filter_func(self.subject_data) cluster_res['recalled'] = recalled delta_z, ts, ps = self.compute_sme_for_cluster(power_data) cluster_res['sme_t'] = ts cluster_res['sme_z'] = delta_z cluster_res['ps'] = ps cluster_res['phase_data_recalled'] = pycircstat.mean(phase_data[:, recalled], axis=1).astype( 'float32') cluster_res['phase_data_not_recalled'] = pycircstat.mean(phase_data[:, ~recalled], axis=1).astype( 'float32') # compute resultant vector length for recalled and not recalled. Then take the difference # between recalled and not recalled rec_rvl, not_rec_rvl = compute_rvl_by_memory(recalled, phase_data, False) rvl_sme = rec_rvl - not_rec_rvl # compute a null distribution of rvl_sme vules rvl_shuff_list = parallel(delayed(compute_rvl_by_memory)(recalled, phase_data, True) for _ in range(self.num_perms)) rvl_sme_shuff = np.stack([x[0] - x[1] for x in rvl_shuff_list]) # get the rank of the real sme values compared to the shuffled data rvl_sme_shuff_perc = (rvl_sme > rvl_sme_shuff).mean(axis=0) rvl_sme_shuff_perc[rvl_sme_shuff_perc == 0] += 1 / self.num_perms rvl_sme_shuff_perc[rvl_sme_shuff_perc == 1] -= 1 / self.num_perms # convert the ranks to a zscore z = norm.ppf(rvl_sme_shuff_perc) # store in res along with the number of significant electrodes in each direction cluster_res['rvl_sme_z'] = z.astype('float32') cluster_res['rvl_sme_sig_pos_n'] = np.sum(rvl_sme_shuff_perc > 0.975, axis=0) cluster_res['rvl_sme_sig_neg_n'] = np.sum(rvl_sme_shuff_perc < 0.025, axis=0) # finally finally, bin phase by roi cluster_res['phase_by_roi'] = self.bin_phase_by_region(phase_data, this_cluster_name) self.res['traveling_waves'][this_cluster_name] = cluster_res else: print('{}: self.res must have a clusters entry before running.'.format(self.subject)) return
fdata = open(drpath + "/" + dirname + "_Summary.txt", 'w') fdata.write("Directory used: \n" + updir + dirname + "\nFiles analysed: \n") for filename in os.listdir(drpath): if "_sep_log.csv" in filename: fdata.write(filename + "\n") file_data = pd.read_csv(drpath + "/" + filename) principal_angle = file_data['principal_angle'] Rad_angle = np.deg2rad(principal_angle) Rad_angle2 = (np.deg2rad(principal_angle)) * 2 circ_mean = np.rad2deg( stats.circmean(Rad_angle, high=np.pi, low=0)) circ_std = np.rad2deg( stats.circstd(Rad_angle, high=np.pi, low=0)) RVL = pycircstat.resultant_vector_length(Rad_angle2) ani_mean = np.mean(file_data['anisotropy']) ani_std = np.std(file_data['anisotropy']) fdata.write("Circ_Mean Angle to x (+-Std) --> " + str(circ_mean) + "+-" + str(circ_std) + " degrees\nResultant_vector_length " + str(RVL) + "\nMean Anisotropy (+-Std) --> " + str(ani_mean) + "+-" + str(ani_std) + "\n\n") Crack_data_[dirname].append(file_data) data = pd.concat(Crack_data_[dirname], ignore_index=True) principal_angles = data['principal_angle'] Rad_angles = np.deg2rad(principal_angles) Rad_angles2 = (np.deg2rad(principal_angles)) * 2 circ_mean_all = np.rad2deg( stats.circmean(Rad_angles, high=np.pi, low=0))
def test_resultant_vector_length_axis(): data = np.ones((10, 2)) assert_allclose(pycircstat.resultant_vector_length(data, axis=1), np.ones(10))
def compute_phase_stats_with_shuffle(events, spike_rel_times, phase_data_hilbert, phase_bin_start, phase_bin_stop, do_permute=False): spike_rel_times_tmp = spike_rel_times.copy() if do_permute: # permute the novel novel_events = np.where(events.isFirst.values)[0] perm_novel_events = np.random.permutation(novel_events) spike_rel_times_tmp[novel_events] = spike_rel_times_tmp[perm_novel_events] # and repeated separately rep_events = np.where(~events.isFirst.values)[0] perm_rep_events = np.random.permutation(rep_events) spike_rel_times_tmp[rep_events] = spike_rel_times_tmp[perm_rep_events] # get the phases at which the spikes occurred and bin into novel and repeated items for each hilbert band spike_phases_hilbert = _compute_spike_phase_by_freq(spike_rel_times_tmp, phase_bin_start, phase_bin_stop, phase_data_hilbert, events) # bin into repeated and novel phases novel_phases, rep_phases = _bin_phases_into_cond(spike_phases_hilbert, events) if (len(novel_phases) > 0) & (len(rep_phases) > 0): # rayleigh test for uniformity rvl_novel = pycircstat.resultant_vector_length(novel_phases, axis=0) rvl_rep = pycircstat.resultant_vector_length(rep_phases, axis=0) rvl_diff = rvl_novel - rvl_rep # compute rayleigh test for each condition rayleigh_pval_novel, rayleigh_z_novel = pycircstat.rayleigh(novel_phases, axis=0) rayleigh_pval_rep, rayleigh_z_rep = pycircstat.rayleigh(rep_phases, axis=0) rayleigh_diff = rayleigh_z_novel - rayleigh_z_rep # watson williams test for equal means ww_pval, ww_tables = pycircstat.watson_williams(novel_phases, rep_phases, axis=0) ww_fstat = np.array([x.loc['Columns'].F for x in ww_tables]) # kuiper test, to test for difference in dispersion (not mean, because I'm making them equal) kuiper_pval, stat_kuiper = pycircstat.kuiper(novel_phases - pycircstat.mean(novel_phases), rep_phases - pycircstat.mean(rep_phases), axis=0) return (rvl_novel, rvl_rep, rvl_diff, ww_fstat, stat_kuiper, rayleigh_z_novel, rayleigh_z_rep, rayleigh_diff), \ (rayleigh_pval_novel, rayleigh_pval_rep, ww_pval, kuiper_pval), novel_phases, rep_phases else: return (np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2])), \ (np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2]), np.array([np.nan] * phase_data_hilbert.shape[2])), novel_phases, rep_phases
#mean_angle=np.rad2deg(stats.circmean(Rad_angle_to_x, high = np.pi/2, low = -np.pi/2)) #print np.mean(angle_to_x) #print np.std(angle_to_x) #print np.mean(anisotropy) #print np.std(anisotropy) fdata.write('Number of cells analysed: ' + str(len(angle_to_x)) + '\n' + 'Circ_Mean Angle to x (+-Std) --> ' + str( np.rad2deg( stats.circmean( Rad_angle_pi_[filename], high=np.pi, low=0))) + '+-' + str( np.rad2deg( stats.circstd( Rad_angle_pi_[filename], high=np.pi, low=0))) + ' degrees' + '\n' + 'Resultant_vector_length ' + str( pycircstat.resultant_vector_length( np.array(Rad_angle_pi_X2_[filename]))) + '\n' + 'Mean Anisotropy (+-Std) --> ' + str(np.mean(anisotropy)) + '+-' + str(np.std(anisotropy)) + '\n' + '\n') ###Polar histogram figure = plt.figure() figure.clf() figure.patch.set_facecolor('k') ax = figure.add_subplot(111, polar=True) colormap = "plasma" n_bins = 36 for offset in [0, np.pi]: histo, bins, patches = figure.gca().hist( offset + angle_to_x * np.pi / 180, bins=offset + np.linspace(-90, 90, n_bins / 2 + 1) * np.pi / 180., ec='k',
def plot_cluster_stats(self, cluster_name): """ Multi panel plot showing: 1. brain map of electrodes in the cluster, color-coded by phase 2. brain map of electrodes in the cluster, color-coded by subsequent memory effect 3. timecourse of resultant vector length of wave direction, averaged across trials 4. timecourse of r^2, averaged across trials 5. polor plot of left-frontal and hippocampal electrode phases 6/7. same as 5, but for recalled and not recalled items only Data are taken from the timepoint with the highest r-square value. Figure creation code is so ugly sorry. """ ############################ # GET TIME TIME FOR X-AXIS # ############################ time_axis = self.res['traveling_waves'][cluster_name]['time'] ##################### # SET UP THE FIGURE # ##################### gs = gridspec.GridSpec(6, 3) ax1 = plt.subplot(gs[0, :]) ax2 = plt.subplot(gs[2, :]) ax3 = plt.subplot(gs[3, :]) ax4 = plt.subplot(gs[4, 0], projection='polar') ax6 = plt.subplot(gs[4, 1], projection='polar') ax7 = plt.subplot(gs[4, 2], projection='polar') ax8 = plt.subplot(gs[5, 0], projection='polar') ax9 = plt.subplot(gs[5, 1], projection='polar') ax10 = plt.subplot(gs[5, 2], projection='polar') ax5 = plt.subplot(gs[1, :]) # some figure parameters fig = plt.gcf() fig.set_size_inches(15, 30) mpl.rcParams['xtick.labelsize'] = 18 mpl.rcParams['ytick.labelsize'] = 18 ############################################# # INFO ABOUT THE ELECTRODES IN THIS CLUSTER # ############################################# cluster_rows = self.res['clusters'][cluster_name].notna() regions_all = self.get_electrode_roi_by_hemi() regions = regions_all[cluster_rows]['merged_col'].unique() regions_str = ', '.join(regions) xyz = self.res['clusters'][cluster_rows][['x', 'y', 'z']].values ############################### # ROW 1: electrodes and phase # ############################### mean_r2 = np.nanmean( self.res['traveling_waves'][cluster_name]['cluster_r2_adj'], axis=1) argmax_r2 = np.argmax(mean_r2) print(argmax_r2) phases = self.res['traveling_waves'][cluster_name][ 'phase_data'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases[phases<0] += np.pi*2 # phases *= 180. / np.pi # phases -= phases.min() - 1 colors = np.stack([[0., 0., 0., 0.]] * len(phases)) cm = clrs.LinearSegmentedColormap.from_list( 'cm', cc.cyclic_mrybm_35_75_c68_s25) cNorm = clrs.Normalize(vmin=0, vmax=np.pi * 2) colors[~np.isnan(phases)] = cmx.ScalarMappable( norm=cNorm, cmap=cm).to_rgba(phases[~np.isnan(phases)]) ni_plot.plot_connectome(np.eye(xyz.shape[0]), xyz, node_kwargs={ 'alpha': 0.7, 'edgecolors': None }, node_size=45, node_color=colors, display_mode='lzr', axes=ax1) mean_freq = self.res['traveling_waves'][cluster_name]['mean_freq'] plt.suptitle('{0} ({1:.2f} Hz): {2}'.format(self.subject, mean_freq, regions_str), y=.9) divider = make_axes_locatable(ax1) cax = divider.append_axes('right', size='6%', pad=15) cb1 = mpl.colorbar.ColorbarBase( cax, cmap=cm, norm=cNorm, orientation='vertical', ticks=[0, np.pi / 2, np.pi, np.pi * 3 / 2, np.pi * 2]) cb1.ax.yaxis.set_ticklabels(['0°', '90°', '180°', '270°', '360°']) cb1.ax.tick_params(labelsize=14) for label in cb1.ax.yaxis.get_majorticklabels(): label.set_transform( label.get_transform() + mpl.transforms.ScaledTranslation(0.15, 0, fig.dpi_scale_trans)) ################################################## # ROW 2: electrodes and subsequent memory effect # ################################################## sme = self.res['traveling_waves'][cluster_name]['sme_t'][:, argmax_r2] colors = np.stack([[0., 0., 0., 0.]] * len(sme)) cm = plt.get_cmap('RdBu_r') clim = np.max(np.abs(sme)) cNorm = clrs.Normalize(vmin=-clim, vmax=clim) colors[~np.isnan(sme)] = cmx.ScalarMappable( norm=cNorm, cmap=cm).to_rgba(sme[~np.isnan(sme)]) ni_plot.plot_connectome(np.eye(xyz.shape[0]), xyz, node_kwargs={ 'alpha': 0.7, 'edgecolors': None }, node_size=45, node_color=colors, display_mode='lzr', axes=ax5) divider = make_axes_locatable(ax5) cax = divider.append_axes('right', size='6%', pad=15) cb2 = mpl.colorbar.ColorbarBase(cax, cmap='RdBu_r', norm=cNorm, orientation='vertical') cb2.ax.tick_params(labelsize=14) for label in cb2.ax.yaxis.get_majorticklabels(): label.set_transform( label.get_transform() + mpl.transforms.ScaledTranslation(0.15, 0, fig.dpi_scale_trans)) ############################ # ROW 3: timecourse of RVL # ############################ rvl = pycircstat.resultant_vector_length( self.res['traveling_waves'][cluster_name]['cluster_wave_ang'], axis=1) ax2.plot(time_axis, rvl, lw=2) ax2.set_ylabel('RVL', fontsize=20) ################################## # ROW 4: timecourse of r-squared # ################################## ax3.plot( time_axis, np.nanmean( self.res['traveling_waves'][cluster_name]['cluster_r2_adj'], axis=1), lw=2) ax3.set_xlabel('Time (ms)', fontsize=20) ax3.set_ylabel('mean($R^{2}$)', fontsize=20) ############################ # ROW 5a: phase polar plots # ############################ # phases = np.deg2rad(phases) cluster_regions = regions_all[cluster_rows]['merged_col'] phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[ ~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax4.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax4.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax4.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax4.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax4.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax4.spines['polar'].set_visible(False) ax4.set_ylim(0, 1.3) ax4.set_yticklabels([]) ax4.set_aspect('equal', 'box') red_patch = mpatches.Patch(color='#67a9cf', label='L. Frontal') blue_patch = mpatches.Patch(color='#ef8a62', label='Hipp') _ = ax4.legend(handles=[red_patch, blue_patch], loc='lower left', bbox_to_anchor=(0.9, 0.9), frameon=False, fontsize=16) ################################################ # ROW 5b: phase polar plots for recalled items # ################################################ phases = self.res['traveling_waves'][cluster_name][ 'phase_data_recalled'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases *= 180. / np.pi # phases -= phases.min() - 1 # phases = np.deg2rad(phases) phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[ ~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax6.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax6.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax6.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax6.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax6.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax6.spines['polar'].set_visible(False) ax6.set_ylim(0, 1.3) ax6.set_yticklabels([]) ax6.set_aspect('equal', 'box') ax6.set_title('Recalled items', y=1.12) #################################################### # ROW 5c: phase polar plots for not recalled items # #################################################### phases = self.res['traveling_waves'][cluster_name][ 'phase_data_not_recalled'][:, argmax_r2] # phases = (phases + np.pi) % (2 * np.pi) - np.pi # phases *= 180. / np.pi # phases -= phases.min() - 1 # phases = np.deg2rad(phases) phases_left_front = phases[cluster_regions == 'left-Frontal'] phases_hipp = phases[(cluster_regions == 'left-Hipp') | (cluster_regions == 'right-Hipp')] phases_other = phases[ ~cluster_regions.isin(['left-Frontal', 'left-Hipp', 'right-Hipp'])] for this_phase in phases_left_front: ax7.plot([this_phase, this_phase], [0, 1], lw=3, c='#67a9cf', alpha=.5) for this_phase in phases_hipp: ax7.plot([this_phase, this_phase], [0, 1], lw=3, c='#ef8a62', alpha=.5) for this_phase in phases_other: ax7.plot([this_phase, this_phase], [0, .7], lw=2, c='k', alpha=.4, zorder=-1) ax7.grid() for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax7.plot([r, r], [0, 1.3], lw=1, c=[.7, .7, .7], zorder=-2) ax7.spines['polar'].set_visible(False) ax7.set_ylim(0, 1.3) ax7.set_yticklabels([]) ax7.set_aspect('equal', 'box') ax7.set_title('Not recalled items', y=1.12) #################################################### # ROW 6: #################################################### recalled = self.res['traveling_waves']['cluster1']['recalled'] if ('left-Frontal' in self.res['traveling_waves'][cluster_name]['phase_by_roi']) & \ ('both-Hipp' in self.res['traveling_waves'][cluster_name]['phase_by_roi']): phase_by_roi = self.res['traveling_waves'][cluster_name][ 'phase_by_roi'] phase_left_front_roi = phase_by_roi['left-Frontal'][:, argmax_r2] # phase_left_front_roi = (phase_left_front_roi + np.pi) % (2 * np.pi) phase_hipp_roi = phase_by_roi['both-Hipp'][:, argmax_r2] # phase_hipp_roi = (phase_hipp_roi + np.pi) % (2 * np.pi) # phase_left_front_roi = (phase_left_front_roi + np.pi) % (2 * np.pi) - np.pi # phase_left_front_roi *= 180. / np.pi # phase_left_front_roi -= phase_left_front_roi.min() - 1 # phase_left_front_roi = np.deg2rad(phase_left_front_roi) # phase_hipp_roi = (phase_hipp_roi + np.pi) % (2 * np.pi) - np.pi # phase_hipp_roi *= 180. / np.pi # phase_hipp_roi -= phase_hipp_roi.min() - 1 # phase_hipp_roi = np.deg2rad(phase_hipp_roi) # LEFT ax8 = self.rose_plot(phase_left_front_roi, n_bins=30, ax=ax8) ax8 = self.rose_plot(phase_hipp_roi, n_bins=30, ax=ax8) ax8.spines['polar'].set_visible(False) ax8.set_yticks([ax8.get_ylim()[1]]) ax8.set_aspect('equal', 'box') ax8.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax8.plot([r, r], [0, ax8.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax8.grid() # MIDDLE ax9 = self.rose_plot(phase_left_front_roi[recalled], n_bins=30, ax=ax9) ax9 = self.rose_plot(phase_hipp_roi[recalled], n_bins=30, ax=ax9) ax9.spines['polar'].set_visible(False) ax9.set_yticks([ax9.get_ylim()[1]]) ax9.set_aspect('equal', 'box') ax9.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax9.plot([r, r], [0, ax9.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax9.grid() # RIGHT ax10 = self.rose_plot(phase_left_front_roi[~recalled], n_bins=30, ax=ax10) ax10 = self.rose_plot(phase_hipp_roi[~recalled], n_bins=30, ax=ax10) ax10.spines['polar'].set_visible(False) ax10.set_yticks([ax10.get_ylim()[1]]) ax10.set_aspect('equal', 'box') ax10.tick_params(axis='y', colors=[.7, .7, .7]) for r in np.linspace(0, 2 * np.pi, 5)[:-1]: ax10.plot([r, r], [0, ax10.get_ylim()[1]], lw=1, c=[.7, .7, .7], zorder=-2) ax10.grid() plt.subplots_adjust(hspace=.5) return fig
def analysis(self): """ For each cluster in res['clusters']: 1. """ # make sure we have data if self.subject_data is None: print('%s: compute or load data first with .load_data()!' % self.subject) return # we must have 'clusters' in self.res if 'clusters' in self.res: self.res['traveling_waves'] = {} # get cluster names from dataframe columns cluster_names = list( filter( re.compile('cluster[0-9]+').match, self.res['clusters'].columns)) # get circular-linear regression parameters theta_r, params = self.compute_grid_parameters() # compute cluster stats for each cluster with Parallel(n_jobs=12, verbose=5) as parallel: for this_cluster_name in cluster_names: cluster_res = {} # get the names of the channels in this cluster cluster_elecs = self.res['clusters'][self.res['clusters'][ this_cluster_name].notna()]['label'] # for the channels in this cluster, bandpass and then hilbert to get the phase info phase_data, power_data, cluster_mean_freq = self.compute_hilbert_for_cluster( this_cluster_name) # reduce to only time inverval of interest time_inds = ( phase_data.time >= self.cluster_stat_start_time) & ( phase_data.time <= self.cluster_stat_end_time) phase_data = phase_data[:, :, time_inds] # get electrode coordinates in 2d norm_coords = self.compute_2d_elec_coords( this_cluster_name) # run the cluster stats for time-averaged data mean_rel_phase = pycircstat.mean(phase_data.data, axis=2) mean_cluster_wave_ang, mean_cluster_wave_freq, mean_cluster_r2_adj = \ circ_lin_regress(mean_rel_phase.T, norm_coords, theta_r, params) cluster_res[ 'mean_cluster_wave_ang'] = mean_cluster_wave_ang cluster_res[ 'mean_cluster_wave_freq'] = mean_cluster_wave_freq cluster_res['mean_cluster_r2_adj'] = mean_cluster_r2_adj # and run it for each time point num_times = phase_data.shape[-1] data_as_list = zip(phase_data.T, [norm_coords] * num_times, [theta_r] * num_times, [params] * num_times) res_as_list = parallel( delayed(circ_lin_regress)(x[0].data, x[1], x[2], x[3]) for x in data_as_list) cluster_res['cluster_wave_ang'] = np.stack( [x[0] for x in res_as_list], axis=0).astype('float32') cluster_res['cluster_wave_freq'] = np.stack( [x[1] for x in res_as_list], axis=0).astype('float32') cluster_res['cluster_r2_adj'] = np.stack( [x[2] for x in res_as_list], axis=0).astype('float32') cluster_res['mean_freq'] = cluster_mean_freq cluster_res['channels'] = cluster_elecs.values cluster_res['time'] = phase_data.time.data cluster_res['phase_data'] = pycircstat.mean( phase_data, axis=1).astype('float32') cluster_res[ 'phase_rvl'] = pycircstat.resultant_vector_length( phase_data, axis=1).astype('float32') # finally, compute the subsequent memory effect if hasattr(self, 'recall_filter_func') and callable( self.recall_filter_func): recalled = self.recall_filter_func(self.subject_data) cluster_res['recalled'] = recalled delta_z, ts, ps = self.compute_sme_for_cluster( power_data) cluster_res['sme_t'] = ts cluster_res['sme_z'] = delta_z cluster_res['ps'] = ps cluster_res['phase_data_recalled'] = pycircstat.mean( phase_data[:, recalled], axis=1).astype('float32') cluster_res[ 'phase_data_not_recalled'] = pycircstat.mean( phase_data[:, ~recalled], axis=1).astype('float32') # compute resultant vector length for recalled and not recalled. Then take the difference # between recalled and not recalled rec_rvl, not_rec_rvl = compute_rvl_by_memory( recalled, phase_data, False) rvl_sme = rec_rvl - not_rec_rvl # compute a null distribution of rvl_sme vules rvl_shuff_list = parallel( delayed(compute_rvl_by_memory)(recalled, phase_data, True) for _ in range(self.num_perms)) rvl_sme_shuff = np.stack( [x[0] - x[1] for x in rvl_shuff_list]) # get the rank of the real sme values compared to the shuffled data rvl_sme_shuff_perc = (rvl_sme > rvl_sme_shuff).mean( axis=0) rvl_sme_shuff_perc[rvl_sme_shuff_perc == 0] += 1 / self.num_perms rvl_sme_shuff_perc[rvl_sme_shuff_perc == 1] -= 1 / self.num_perms # convert the ranks to a zscore z = norm.ppf(rvl_sme_shuff_perc) # store in res along with the number of significant electrodes in each direction cluster_res['rvl_sme_z'] = z.astype('float32') cluster_res['rvl_sme_sig_pos_n'] = np.sum( rvl_sme_shuff_perc > 0.975, axis=0) cluster_res['rvl_sme_sig_neg_n'] = np.sum( rvl_sme_shuff_perc < 0.025, axis=0) # finally finally, bin phase by roi cluster_res['phase_by_roi'] = self.bin_phase_by_region( phase_data, this_cluster_name) self.res['traveling_waves'][ this_cluster_name] = cluster_res else: print('{}: self.res must have a clusters entry before running.'. format(self.subject)) return
imgpath = drpath + '/' + files #print 'image path: ' + imgpath Rad_angle_pi_X2_[files] = [] DegAngles = np.genfromtxt(imgpath, delimiter='\t', usecols=5, dtype=None) RadAngles = np.deg2rad(DegAngles) #print RadAngles for a in RadAngles: if a < 0: a = a + (np.pi) b = a * 2 Rad_angle_pi_X2_[files].append(b) #print Rad_angle_pi_X2_[files] RVL = pycircstat.resultant_vector_length( np.array(Rad_angle_pi_X2_[files])) #fdata.write('Sample analysed: '+ imgpath +'\n' + 'Resultant vector length --> ' + str(RVL) + '\n'+ '\n') RVLdata_[dirname].append(RVL) #RVLdata.append(RVL) print str(dirname) + ' :' + str(RVLdata_[dirname]) RVLdata.append(RVLdata_[dirname]) fdata.write('Mean RVL' + str(dirname) + '(+-Std) --> ' + str(np.mean(RVLdata_[dirname])) + '+-' + str(np.std(RVLdata_[dirname])) + '\n') ###Comparaisons sampleA = ['MBD_1%', 'MBD_1%', 'MBD_1%', 'MBD_2,5%', 'MBD_2,5%', 'qua1MBD_1%'] sampleB = [ 'MBD_2,5%', 'qua1MBD_1%', 'qua1MBD_2,5%', 'qua1MBD_1%', 'qua1MBD_2,5%',
def test_resultant_vector_length(): data = np.ones(10) assert_allclose(pycircstat.resultant_vector_length(data), 1.0)
def test_resultant_vector_length(): data = np.ones(10) assert_allclose(pycircstat.resultant_vector_length(data), 1.0)
def test_resultant_vector_length_axis(): data = np.ones((10, 2)) assert_allclose(pycircstat.resultant_vector_length(data, axis=1), np.ones(10))
def compute_rvl_by_memory(recalled, data, do_perm=False): if do_perm: recalled = np.random.permutation(recalled) rec_rvl = pycircstat.resultant_vector_length(data[:, recalled], axis=1) nrec_rvl = pycircstat.resultant_vector_length(data[:, ~recalled], axis=1) return rec_rvl, nrec_rvl