def __init__(self, idpac=(1, 2, 3), f_pha=[2, 4], f_amp=[60, 200], dcomplex='hilbert', filt='fir1', cycle=(3, 6), filtorder=3, width=7, n_bins=18, verbose=None): """Check and initialize.""" set_log_level(verbose) self._idcheck(idpac) _PacObj.__init__(self, f_pha=f_pha, f_amp=f_amp, dcomplex=dcomplex, filt=filt, cycle=cycle, filtorder=filtorder, width=width) _PacPlt.__init__(self) self.n_bins = int(n_bins) logger.info("Phase Amplitude Coupling object defined")
def __init__(self, x, sf, f_pha=[2, 4], dcomplex='hilbert', cycle=3, width=7, edges=None, n_jobs=-1, verbose=None): """Init.""" set_log_level(verbose) _PacObj.__init__(self, f_pha=f_pha, f_amp=[60, 80], dcomplex=dcomplex, cycle=(cycle, 6), width=width) _PacVisual.__init__(self) # check x = np.atleast_2d(x) assert x.ndim <= 2, ("`x` input should be an array of shape " "(n_epochs, n_times)") self._n_trials = x.shape[0] logger.info("Inter-Trials Coherence (ITC)") logger.info(f" extracting {len(self.xvec)} phases") # extract phase and amplitude kw = dict(keepfilt=False, edges=edges, n_jobs=n_jobs) pha = self.filter(sf, x, 'phase', **kw) # compute itc self._itc = np.abs(np.exp(1j * pha).mean(1)).squeeze() self._sf = sf
def test_logger(self): """Test logger levels.""" set_log_level("profiler") logger.profiler("profiler") logger.debug("debug") logger.info("info") logger.warning("warning") logger.critical("critical")
def __init__(self, x, sf, cue, times=None, f_pha=[5, 7], f_amp='hres', cycle=(3, 6), n_jobs=-1, verbose=None): """Init.""" set_log_level(verbose) # initialize to retrieve filtering methods _PacObj.__init__(self, f_pha=f_pha, f_amp=f_amp, dcomplex='hilbert', cycle=cycle) _PacVisual.__init__(self) logger.info("PeakLockedTF object defined") # inputs checking x = np.atleast_2d(x) assert isinstance(x, np.ndarray) and (x.ndim == 2) assert isinstance(sf, (int, float)) assert isinstance(cue, (int, float)) assert isinstance(f_pha, (list, tuple)) and (len(f_pha) == 2) n_epochs, n_times = x.shape # manage cur conversion if times is None: cue = int(cue) times = np.arange(n_times) logger.info(f" align on sample cue={cue}") else: assert isinstance(times, np.ndarray) and (len(times) == n_times) cue_time = cue cue = np.abs(times - cue).argmin() - 1 logger.info(f" align on time-point={cue_time} (sample={cue})") self.cue, self._times = cue, times # extract phase and amplitudes logger.info(f" extract phase and amplitudes " f"(n_amps={len(self.yvec)})") kw = dict(keepfilt=False, n_jobs=n_jobs) pha = self.filter(sf, x, 'phase', n_jobs=n_jobs, keepfilt=True) amp = self.filter(sf, x, 'amplitude', n_jobs=n_jobs) self._pha, self._amp = pha, amp**2 # peak detection logger.info(f" running peak detection around sample={cue}") self.shifts = self._peak_detection(self._pha.squeeze(), cue) # realign phases and amplitudes logger.info(f" realign the {n_epochs} phases and amplitudes") self.amp_a = self._shift_signals(self._amp, self.shifts, fill_with=0.) self.pha_a = self._shift_signals(self._pha, self.shifts, fill_with=0.)
def fit(self, pha, amp, method='circular', smooth=None, n_jobs=-1, verbose=None): """Compute the Event-Related Phase-Amplitude Coupling (ERPAC). The ERPAC [#f6]_ is used to measure PAC across trials and is interesting for real-time estimation. Parameters ---------- pha, amp : array_like Respectively the phase of slower oscillations of shape (n_pha, n_epochs, n_times) and the amplitude of faster oscillations of shape (n_pha, n_epochs, n_times). method : {'circular', 'gc'} Name of the method for computing erpac. Use 'circular' for reproducing [#f6]_ or 'gc' for a Gaussian-Copula based erpac. smooth : int | None Half number of time-points to use to produce a smoothing. Only active with the Gaussian-Copula ('gc') method. Returns ------- erpac : array_like The ERPAC estimation of shape (n_amp, n_pha, n_times) References ---------- .. [#f6] `Voytek et al, 2013 <https://www.ncbi.nlm.nih.gov/pubmed/ 22986076>`_ .. [#f7] `Ince et al, 2017 <https://onlinelibrary.wiley.com/doi/full/10 .1002/hbm.23471>`_ """ set_log_level(verbose) pha, amp = self._phampcheck(pha, amp) self.method = method # method switch if method == 'circular': self.method = "ERPAC (Voytek et al. 2013)" logger.info(f" Compute {self.method}") er, self.pvalues = erpac(pha, amp) elif method == 'gc': self.method = "Gaussian-Copula ERPAC (Ince et al. 2017)" logger.info(f" Compute {self.method}") er = ergcpac(pha, amp, smooth=smooth, n_jobs=n_jobs) self.pvalues = None self._erpac = er return self.erpac
def test_log_level(self): """Test setting the log level.""" for l in levels: set_log_level(l) set_log_level(False) set_log_level(True) set_log_level(match="ok") logger.info("show me ok") logger.info("show me")
def __init__(self, f_pha=[2, 4], f_amp=[60, 200], dcomplex='hilbert', cycle=(3, 6), width=7, verbose=None): """Check and initialize.""" set_log_level(verbose) _PacObj.__init__(self, f_pha=f_pha, f_amp=f_amp, dcomplex=dcomplex, cycle=cycle, width=width) _PacPlt.__init__(self) logger.info("Event Related PAC object defined")
def __init__(self, f_pha=[2, 4], f_amp=[60, 200], dcomplex='hilbert', cycle=(3, 6), width=7, verbose=None): """Check and initialize.""" set_log_level(verbose) _PacObj.__init__(self, f_pha=f_pha, f_amp=f_amp, dcomplex=dcomplex, cycle=cycle, width=width) _PacPlt.__init__(self) logger.info("Preferred phase object defined") self.method = 'Preferred-Phase (PP)'
""" Tensorpac ========= Tensorpac is an open-source Python toolbox designed for computing Phase-Amplitude Coupling. """ import logging from tensorpac import methods, signals, utils, stats # noqa from tensorpac.pac import (Pac, EventRelatedPac, PreferredPhase) # noqa from tensorpac.io import set_log_level # Set 'info' as the default logging level logger = logging.getLogger('brainets') set_log_level('info') __version__ = "0.6.5"
def fit(self, pha, amp, method='circular', smooth=None, n_jobs=-1, n_perm=None, p=.05, mcp='fdr', verbose=None): """Compute the Event-Related Phase-Amplitude Coupling (ERPAC). The ERPAC :cite:`voytek2013method` is used to measure PAC across trials and is interesting for real-time estimation. Parameters ---------- pha, amp : array_like Respectively the phase of slower oscillations of shape (n_pha, n_epochs, n_times) and the amplitude of faster oscillations of shape (n_pha, n_epochs, n_times). method : {'circular', 'gc'} Name of the method for computing erpac. Use 'circular' for reproducing :cite:`voytek2013method` or 'gc' for a Gaussian-Copula based erpac :cite:`ince2017statistical`. smooth : int | None Half number of time-points to use to produce a smoothing. Only active with the Gaussian-Copula ('gc') method. n_perm : int | None Number of permutations to compute for assessing p-values for the gaussian-copula ('gc') method. Statistics are performed by randomly swapping phase trials p : float | 0.05 Statistical threshold for the gaussian-copula ('gc') method mcp : {'fdr', 'bonferroni'} Correct the p-values for multiple comparisons. This is needed when using the circular ERPAC (:cite:`voytek2013method`). Note that the correction is performed using MNE-Python. Returns ------- erpac : array_like The ERPAC estimation of shape (n_amp, n_pha, n_times) """ set_log_level(verbose) pha, amp = self._phampcheck(pha, amp) self.method = method self._pvalues = None # move the trial axis to the end (n_freqs, n_times, n_epochs) pha, amp = np.moveaxis(pha, 1, -1), np.moveaxis(amp, 1, -1) # method switch if method == 'circular': self.method = "ERPAC (Voytek et al. 2013)" logger.info(f" Compute {self.method}") self._erpac, self._pvalues = erpac(pha, amp) self.infer_pvalues(p=p, mcp=mcp) elif method == 'gc': self.method = "Gaussian-Copula ERPAC" logger.info(f" Compute {self.method}") # copnorm phases and amplitudes then compute erpac sco = copnorm(np.stack([np.sin(pha), np.cos(pha)], axis=-2)) amp = copnorm(amp)[..., np.newaxis, :] self._erpac = ergcpac(sco, amp, smooth=smooth, n_jobs=n_jobs) # compute permutations (if needed) if isinstance(n_perm, int) and (n_perm > 0): logger.info(f" Compute {n_perm} permutations") self._surrogates = _ergcpac_perm(sco, amp, smooth=smooth, n_jobs=n_jobs, n_perm=n_perm) self.infer_pvalues(p=p, mcp=mcp) return self.erpac
def fit(self, pha, amp, n_perm=200, p=.05, mcp='maxstat', n_jobs=-1, random_state=None, verbose=None): """Compute PAC on filtered data. Parameters ---------- pha : array_like Array of phases of shape (n_pha, n_epochs, n_times). Angles should be in rad. amp : array_like Array of amplitudes of shape (n_amp, n_epochs, n_times). n_perm : int | 200 Number of surrogates to compute. p : float | 0.05 Statistical threshold mcp : {'fdr', 'bonferroni'} Correct the p-values for multiple comparisons. Use either : * 'maxstat' : maximum statistics * 'fdr' : FDR correction (need MNE-Python) * 'bonferroni' : Bonferroni correction (need MNE-Python) n_jobs : int | -1 Number of jobs to compute PAC in parallel. For very large data, set this parameter to 1 in order to prevent large memory usage. random_state : int | None Fix the random state of the machine for reproducible results. Returns ------- pac : array_like Phase-Amplitude Coupling measure of shape (n_amp, n_pha, n_epochs) Attributes ---------- pac : array_like Unormalized Phase-Amplitude Coupling measure of shape (n_amp, n_pha, n_epochs) pvalues : array_like Array of p-values of shape (n_amp, n_pha) surrogates : array_like Array of surrogates of shape (n_perm, n_amp, n_pha, n_epochs) """ set_log_level(verbose) # --------------------------------------------------------------------- # input checking pha, amp = self._phampcheck(pha, amp) self._pvalues, self._surrogates = None, None # for the plv, extract the phase of the amplitude if self._idpac[0] == 5: amp = np.angle(hilbertm(amp)) # --------------------------------------------------------------------- # check if permutations should be computed if self._idpac[1] == 0: n_perm = None if not isinstance(n_perm, int) or not (n_perm > 0): self._idpac = (self._idpac[0], 0, 0) compute_surro = False else: compute_surro = True # --------------------------------------------------------------------- # copnorm if gaussian copula is used if self._idpac[0] == 6: logger.debug(f" copnorm the phase and the amplitude") pha = copnorm(np.stack([np.sin(pha), np.cos(pha)], axis=-2)) amp = copnorm(amp[..., np.newaxis, :]) # --------------------------------------------------------------------- # true pac estimation logger.info(f' true PAC estimation using {self.method}') fcn = get_pac_fcn(self.idpac[0], self.n_bins, p) pac = fcn(pha, amp) self._pac = pac.copy() # --------------------------------------------------------------------- # compute surrogates (if needed) if compute_surro: if random_state is None: random_state = int(np.random.randint(0, 10000, size=1)) logger.info(f" compute surrogates ({self.str_surro}, {n_perm} " f"permutations, random_state={random_state})") surro = compute_surrogates(pha, amp, self.idpac[1], fcn, n_perm, n_jobs, random_state) self._surrogates = surro # infer pvalues self.infer_pvalues(p, mcp=mcp) # --------------------------------------------------------------------- # normalize (if needed) if self._idpac[2] != 0: # Get the mean / deviation of surrogates logger.info(" normalize true PAC estimation by surrogates " f"({self.str_norm})") normalize(self.idpac[2], pac, surro) return pac
def fit(self, pha, amp, n_perm=200, p=.05, n_jobs=-1, verbose=None): """Compute PAC on filtered data. Parameters ---------- pha : array_like Array of phases of shape (n_pha, n_epochs, n_times). Angles should be in rad. amp : array_like Array of amplitudes of shape (n_amp, n_epochs, n_times). n_perm : int | 200 Number of surrogates to compute. p : float | 0.05 Statistical threhold n_jobs : int | -1 Number of jobs to compute PAC in parallel. For very large data, set this parameter to 1 in order to prevent large memory usage. Returns ------- pac : array_like Phase-Amplitude Coupling measure of shape (n_amp, n_pha, n_epochs) Attributes ---------- pac : array_like Unormalized Phase-Amplitude Coupling measure of shape (n_amp, n_pha, n_epochs) pvalues : array_like Array of p-values of shape (n_amp, n_pha) surrogates : array_like Array of surrogates of shape (n_perm, n_amp, n_pha, n_epochs) """ set_log_level(verbose) # --------------------------------------------------------------------- # input checking pha, amp = self._phampcheck(pha, amp) self._pvalues, self._surrogates = None, None # for the phase synchrony, extract the phase of the amplitude if self._idpac[0] == 5: amp = np.angle(hilbertm(amp)) # --------------------------------------------------------------------- # check if permutations should be computed if self._idpac[1] == 0: n_perm = None if not isinstance(n_perm, int) or not (n_perm > 0): self._idpac = (self._idpac[0], 0, 0) compute_surro = False else: compute_surro = True # --------------------------------------------------------------------- # copnorm if gaussian copula is used if self._idpac[0] == 6: logger.info(f" copnorm the phase and the amplitude") pha = copnorm(np.stack([np.sin(pha), np.cos(pha)], axis=-2)) amp = copnorm(amp[..., np.newaxis, :]) # --------------------------------------------------------------------- # true pac estimation logger.info(f' true PAC estimation using {self.method}') fcn = get_pac_fcn(self.idpac[0], self.n_bins, p) pac = fcn(pha, amp) self._pac = pac # --------------------------------------------------------------------- # compute surrogates (if needed) if compute_surro: logger.info(f" compute surrogates ({self.str_surro}, {n_perm} " "permutations)") surro = compute_surrogates(pha, amp, self.idpac[1], fcn, n_perm, n_jobs) self._surrogates = surro # infer pvalues self.infer_pvalues(p) # --------------------------------------------------------------------- # normalize (if needed) if self._idpac[2] != 0: # Get the mean / deviation of surrogates logger.info(" normalize true PAC estimation by surrogates " f"({self.str_norm})") normalize(self.idpac[2], pac, surro) return pac
def fit(self, pha, amp, method='circular', smooth=None, n_jobs=-1, n_perm=None, p=.05, verbose=None): """Compute the Event-Related Phase-Amplitude Coupling (ERPAC). The ERPAC [#f6]_ is used to measure PAC across trials and is interesting for real-time estimation. Parameters ---------- pha, amp : array_like Respectively the phase of slower oscillations of shape (n_pha, n_epochs, n_times) and the amplitude of faster oscillations of shape (n_pha, n_epochs, n_times). method : {'circular', 'gc'} Name of the method for computing erpac. Use 'circular' for reproducing [#f6]_ or 'gc' for a Gaussian-Copula based erpac. smooth : int | None Half number of time-points to use to produce a smoothing. Only active with the Gaussian-Copula ('gc') method. n_perm : int | None Number of permutations to compute for assessing p-values for the gaussian-copula ('gc') method. Statistics are performed by randomly swapping phase trials p : float | 0.05 Statistical threshold for the gaussian-copula ('gc') method Returns ------- erpac : array_like The ERPAC estimation of shape (n_amp, n_pha, n_times) References ---------- .. [#f6] `Voytek et al, 2013 <https://www.ncbi.nlm.nih.gov/pubmed/ 22986076>`_ .. [#f7] `Ince et al, 2017 <https://onlinelibrary.wiley.com/doi/full/10 .1002/hbm.23471>`_ """ set_log_level(verbose) pha, amp = self._phampcheck(pha, amp) self.method = method self._pvalues = None # move the trial axis to the end (n_freqs, n_times, n_epochs) pha, amp = np.moveaxis(pha, 1, -1), np.moveaxis(amp, 1, -1) # method switch if method == 'circular': self.method = "ERPAC (Voytek et al. 2013)" logger.info(f" Compute {self.method}") self._erpac, self._pvalues = erpac(pha, amp) elif method == 'gc': self.method = "Gaussian-Copula ERPAC (Ince et al. 2017)" logger.info(f" Compute {self.method}") # copnorm phases and amplitudes then compute erpac sco = copnorm(np.stack([np.sin(pha), np.cos(pha)], axis=-2)) amp = copnorm(amp)[..., np.newaxis, :] self._erpac = ergcpac(sco, amp, smooth=smooth, n_jobs=n_jobs) # compute permutations (if needed) if isinstance(n_perm, int) and (n_perm > 0): logger.info(f" Compute {n_perm} permutations") self._surrogates = _ergcpac_perm(sco, amp, smooth=smooth, n_jobs=n_jobs, n_perm=n_perm) self.infer_pvalues(p=p) return self.erpac