def plot_decompose(self, result_index, **kwargs): """Plot periodic and aperiodic signal decomposition.""" if self.results[result_index].sig_pe is None or self.results[ result_index].sig_ap is None: self.decompose() times = np.arange(0, len(self.sig) / self.fs, 1 / self.fs) figsize = kwargs.pop('figsize', (15, 2)) alpha = kwargs.pop('alpha', [0.75, 1]) # Plot the periodic decomposition plot_time_series(times, [self.sig, self.results[result_index].sig_pe], labels=['Original', 'Periodic'], title='Periodic Reconstruction', alpha=alpha, figsize=figsize, **kwargs) # Plot the aperiodic decomposition plot_time_series(times, [self.sig, self.results[result_index].sig_ap], labels=['Original', 'Aperiodic'], title='Aperiodic Reconstruction', alpha=alpha, figsize=figsize, **kwargs)
s_rate = 1000 n_seconds = 4 times = create_times(n_seconds, s_rate) # Set random seed, for consistency generating simulated data set_random_seed(21) ################################################################################################### # Simulate a signal of aperiodic activity: pink noise sig = sim_powerlaw(n_seconds, s_rate, exponent=-1) ################################################################################################### # Plot our simulated time series plot_time_series(times, sig) ################################################################################################### # Filtering Aperiodic Signals # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Now that we have a simulated signal, let's filter it into each of our frequency bands. # # To do so, we will loop across our band definitions, and plot the filtered version # of the signal. # ################################################################################################### # Apply band-by-band filtering of our signal into each defined frequency band _, axes = plt.subplots(len(bands), 1, figsize=(12, 15))
def plot_burst_detect_param(df, sig, fs, burst_param, thresh, xlim=None, ax=None, interp=True, **kwargs): """Plot a burst detection parameter and threshold. Parameters ---------- df : pandas.DataFrame Dataframe output of :func:`~.compute_features`. sig : 1d array Time series to plot. fs : float Sampling rate, in Hz. burst_param : str Column name of the parameter of interest in ``df``. thresh : float The burst parameter threshold. Parameter values greater than ``thresh`` are considered bursts. xlim : tuple of (float, float), optional, default: None Start and stop times for plot. ax : matplotlib.Axes, optional Figure axes upon which to plot. interp : bool Interpolates points if true. **kwargs Keyword arguments to pass into `plot_time_series`. Notes ----- Default keyword arguments include: - ``figsize``: tuple of (float, float), default: (15, 3) - ``xlabel``: str, default: 'Time (s)' - ``ylabel``: str, default: 'Voltage (uV) - ``color``: str, default: 'r'. - Note: ``color`` here is the fill color, rather than line color. """ # Set default kwargs figsize = kwargs.pop('figsize', (15, 3)) xlabel = kwargs.pop('xlabel', 'Time (s)') ylabel = kwargs.pop('ylabel', burst_param) color = kwargs.pop('color', 'r') # Determine time array and limits times = np.arange(0, len(sig) / fs, 1 / fs) xlim = (times[0], times[-1]) if xlim is None else xlim if ax is None: fig, ax = plt.subplots(figsize=figsize) # Determine extrema strings center_e, side_e = get_extrema(df) # Limit dataframe, sig and times df = limit_df(df, fs, start=xlim[0], stop=xlim[1]) sig, times = limit_signal(times, sig, start=xlim[0], stop=xlim[1]) # Remove start/end cycles that tlims falls between df = df[df['sample_last_' + side_e] >= 0] df = df[df['sample_next_' + side_e] < xlim[1] * fs] # Plot burst param if interp: plot_time_series([times[df['sample_' + center_e]], xlim], [df[burst_param], [thresh] * 2], ax=ax, colors=['k', 'k'], ls=['-', '--'], marker=["o", None], lim=xlim, xlabel=xlabel, ylabel="{0:s}\nthreshold={1:.2f}".format( ylabel, thresh), **kwargs) else: # Create steps, from side to side of each cycle, and set the y-value to the burst parameter # value for that cycle. side_times = np.array([]) side_param = np.array([]) for _, cyc in df.iterrows(): # Get the times for the last and next side of a cycle side_times = np.append(side_times, [ times[cyc['sample_last_' + side_e]], times[cyc['sample_next_' + side_e]] ]) # Set the y-value, from side to side, to the burst param for a cycle. side_param = np.append(side_param, [cyc[burst_param]] * 2) plot_time_series([side_times, xlim], [side_param, [thresh] * 2], ax=ax, colors=['k', 'k'], ls=['-', '--'], marker=["o", None], xlim=xlim, xlabel=xlabel, ylabel="{0:s}\nthreshold={1:.2f}".format( ylabel, thresh), **kwargs) # Highlight where param falls below threshold for _, cyc in df.iterrows(): if cyc[burst_param] <= thresh: ax.axvspan(times[cyc['sample_last_' + side_e]], times[cyc['sample_next_' + side_e]], alpha=0.5, color=color, lw=0)
# ~~~~~~~~~~~~~~~ # # The Dirac delta is arguably the simplest signal, as it's a signal of all zeros, # except for a single value of 1. # ################################################################################################### # Simulate a delta function dirac_sig = np.zeros([n_points]) dirac_sig[500] = 1 ################################################################################################### # Plot the time series of the delta signal plot_time_series(times, dirac_sig) ################################################################################################### # # Next, lets compute the frequency representation of the delta function. # ################################################################################################### # Compute a power spectrum of the Dirac delta freqs, powers = compute_spectrum_welch(dirac_sig, 100) ################################################################################################### # Plot the power spectrum of the Dirac delta plot_power_spectra(freqs, powers)
def plot_spikes(df_features, sig, fs, spikes=None, index=None, xlim=None, ax=None): """Plot a group of spikes or the cyclepoints for an individual spike. Parameters ---------- df_features : pandas.DataFrame Dataframe containing shape and burst features for each spike. sig : 1d or 2d array Voltage timeseries. May be 2d if spikes are split. fs : float Sampling rate, in Hz. spikes : 1d array, optional, default: None Spikes that have been split into a 2d array. Ignored if ``index`` is passed. index : int, optional, default: None The index in ``df_features`` to plot. If None, plot all spikes. xlim : tuple Upper and lower time limits. Ignored if spikes or index is passed. ax : matplotlib.Axes, optional, default: None Figure axes upon which to plot. """ ax = check_ax(ax, (10, 4)) center_e, _ = get_extrema_df(df_features) # Plot a single spike if index is not None: times = np.arange(0, len(sig) / fs, 1 / fs) # Get where spike starts/ends start = df_features.iloc[index]['sample_start'].astype(int) end = df_features.iloc[index]['sample_end'].astype(int) sig_lim = sig[start:end + 1] times_lim = times[start:end + 1] # Plot the spike waveform plot_time_series(times_lim, sig_lim, ax=ax) # Plot cyclespoints labels, keys = _infer_labels(center_e) colors = ['C0', 'C1', 'C2', 'C3'] for idx, key in enumerate(keys): sample = df_features.iloc[index][key].astype('int') plot_time_series(np.array([times[sample]]), np.array([sig[sample]]), colors=colors[idx], labels=labels[idx], ls='', marker='o', ax=ax) # Plot as stack of spikes elif index is None and spikes is not None: times = np.arange(0, len(spikes[0]) / fs, 1 / fs) plot_time_series(times, spikes, ax=ax) # Plot as continuous timeseries elif index is None and spikes is None: ax = check_ax(ax, (15, 3)) times = np.arange(0, len(sig) / fs, 1 / fs) plot_time_series(times, sig, ax=ax, xlim=xlim) if xlim is None: sig_lim = sig df_lim = df_features times_lim = times starts = df_lim['sample_start'] else: cyc_idxs = (df_features['sample_start'].values >= xlim[0] * fs) & \ (df_features['sample_end'].values <= xlim[1] * fs) df_lim = df_features.iloc[cyc_idxs].copy() sig_lim, times_lim = limit_signal(times, sig, start=xlim[0], stop=xlim[1]) starts = df_lim['sample_start'] - int(fs * xlim[0]) ends = starts + df_lim['period'].values is_spike = np.zeros(len(sig_lim), dtype='bool') for start, end in zip(starts, ends): is_spike[start:end] = True plot_bursts(times_lim, sig_lim, is_spike, ax=ax)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Now let's see how each signal looks in time. The third plot of spikes is # added to pink noise to make the second plot which is the spurious pac. # This is so that where the spikes occur can be noted in the spurious pac plot. # #################################################################################################### time = np.arange(0, n_seconds, 1/fs) fig, axes = plt.subplots(nrows=4, figsize=(16, 12), sharex=True) xlim = (0, 1) # Plot PAC plot_time_series(time, sig_pac, title=titles[0], xlabel='', colors='C0', ax=axes[0], xlim=xlim) # Plot spurious PAC plot_time_series(time, sig_spurious_pac, title=titles[1], xlabel='', colors='C1', ax=axes[1], xlim=xlim) # Plot spikes plot_time_series(time, spikes, title='Spikes', xlabel='', colors='C2', ax=axes[2], xlim=xlim) # Plot signal with no PAC plot_time_series(time, sig_no_pac, title=titles[2], colors='C3', ax=axes[3], xlim=xlim) #################################################################################################### # Compute cycle-by-cycle features # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Here we use the bycycle compute_features function to compute the cycle-by-
n_seconds_filter = .5 # Compute amplitude and phase sig_filt = filter_signal(sig, fs, 'bandpass', f_alpha, n_seconds=n_seconds_filter) theta_amp = amp_by_time(sig, fs, f_alpha, n_seconds=n_seconds_filter) theta_phase = phase_by_time(sig, fs, f_alpha, n_seconds=n_seconds_filter) # Plot signal times = create_times(n_seconds, fs) xlim = (2, 6) tidx = np.logical_and(times >= xlim[0], times < xlim[1]) fig, axes = plt.subplots(figsize=(15, 9), nrows=3) # Plot the raw signal plot_time_series(times[tidx], sig[tidx], ax=axes[0], ylabel='Voltage (mV)', xlabel='', lw=2, labels='raw signal') # Plot the filtered signal and oscillation amplitude plot_instantaneous_measure(times[tidx], [sig_filt[tidx], theta_amp[tidx]], ax=axes[1], measure='amplitude', lw=2, xlabel='', labels=['filtered signal', 'amplitude']) # Plot the phase plot_instantaneous_measure(times[tidx], theta_phase[tidx], ax=axes[2], colors='r', measure='phase', lw=2, xlabel='Time (s)') #################################################################################################### # # This conventional analysis has some advantages and disadvantages. As for advantages: # # - Quick calculation
'f_range': (2, None) }, 'sim_bursty_oscillation': { 'freq': freq } } comp_vars = [0.25, 1] # Simulate a signal with bursty oscillations at 20 Hz sig = sim_combined(n_seconds, fs, comps, comp_vars) times = create_times(n_seconds, fs) ################################################################################################### # Plot a segment of our simulated time series plot_time_series(times, sig, xlim=[0, 2]) ################################################################################################### # Compute Wavelet Transform # ------------------------- # # Now, let's use the compute Morlet wavelet transform algorithm to compute a # time-frequency representation of our simulated data, using Morlet wavelets. # # To apply the continuous Morlet wavelet transform, we need to specify frequencies of # interest. The wavelet transform can then be used to compute the power at these # frequencies across time. # # For this example, we'll compute the Morlet wavelet transform on 50 equally-spaced # frequencies from 5 Hz to 100 Hz. #
sig[:fs] = 0 ################################################################################################### # Define the frequency band of interest passband = 'bandpass' f_range = (4, 8) # Filter the data sig_filt_short = filter_signal(sig, fs, passband, f_range, n_seconds=.1) sig_filt_long = filter_signal(sig, fs, passband, f_range, n_seconds=1) ################################################################################################### # Plot filtered signal plot_time_series(times, [sig, sig_filt_short, sig_filt_long], ['Raw', 'Short Filter', 'Long Filter']) ################################################################################################### # # In the plot above, we can see that the short filter preserves the start of the oscillation # better than the long filter (i.e. the short filter has better temporal resolution). # # Notice also that the long filter correctly removed the 1Hz oscillation, but the short # filter did not (i.e. the long filter has better frequency resolution). # # Another way to examine these properties is by looking at the properties of the two filters. # ################################################################################################### # Filter and visualize properties for the short filter
# Lowpass filter sig_low = filter_signal(sig, fs, 'lowpass', f_lowpass, n_seconds=n_seconds, remove_edges=False) # Plot signal times = np.arange(0, len(sig) / fs, 1 / fs) xlim = (2, 5) tidx = np.logical_and(times >= xlim[0], times < xlim[1]) plot_time_series(times[tidx], [sig[tidx], sig_low[tidx]], colors=['k', 'k'], alpha=[.5, 1], lw=2) #################################################################################################### # # 1. Localize peaks and troughs # ----------------------------- # # In order to characterize the oscillation, it is useful to know the precise times of peaks and # troughs. For one, this will allow us to compute the periods and rise-decay symmetries of the # individual cycles. To do this, the signal is first narrow-bandpass filtered in order to estimate # "zero-crossings." Then, in between these zerocrossings, the absolute maxima and minima are found # and labeled as the peaks and troughs, respectively. # Narrowband filter signal n_seconds_theta = .75
################################################################################################### # Apply # ----- # # The filter we previously designed may now be applied to a signal, which can be done with # the :func:`~.apply_iir_filter` function. # ################################################################################################### # Apply the filter to our signal sig_filt = apply_iir_filter(sig, sos) # Plot the filtered and original time series plot_time_series(times, [sig, sig_filt], ['Raw', 'Filtered']) ################################################################################################### # # In the above, we can see both the original signal, and the filtered version. # # Note that inspecting the filtered signal together with the original signal is recommended. # ################################################################################################### # Using filter_signal # ~~~~~~~~~~~~~~~~~~~ # # In the above, we did a step-by-step procedure of designing, evaluating, and applying our filter. # # Note that all of these elements can also be done directly through the
return_times=True) #################################################################################################### # # Plot time series for each recording # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Now let's see how each signal looks in time. This looks like standard EEG # data. # #################################################################################################### # Plot the signal plot_time_series(times, [sig * 1e6 for sig in sigs], labels=chs, title='EEG Signal') #################################################################################################### # Compute cycle-by-cycle features # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Here we use the bycycle compute_features function to compute the cycle-by- # cycle features of the three signals. # #################################################################################################### # Set parameters for defining oscillatory bursts threshold_kwargs = { 'amp_fraction_threshold': 0.3,
def plot_transform(self, result_index, center='peak', xlim=None, figsize=(10, 1.5)): if self.results[result_index].sig_pe is None or self.results[ result_index].sig_ap is None: self.decompose() fig, axes = plt.subplots(figsize=(figsize[0], figsize[1] * (7)), nrows=7, sharex=True) side = 'trough' if center == 'peak' else 'peak' starts = self.results[result_index].df_features['sample_last_' + side] ends = self.results[result_index].df_features['sample_next_' + side] # Get affine matrix parameters tforms = self.results[result_index].tforms rotations = [tform.rotation for tform in tforms] translations_x = [tform.translation[0] for tform in tforms] translations_y = [tform.translation[1] for tform in tforms] scales_x = [tform.scale[0] for tform in tforms] scales_y = [tform.scale[0] for tform in tforms] shears = [tform.shear for tform in tforms] params = [ rotations, translations_x, translations_y, scales_x, scales_y, shears ] param_arr = np.zeros((len(params), len(self.sig))) param_arr[:, :] = np.nan for idx, params in enumerate(params): for cyc_idx, (start, end) in enumerate(zip(starts, ends)): param_arr[idx][start:end] = params[cyc_idx] # Plot bursts times = np.arange(0, len(self.sig) / self.fs, 1 / self.fs) plot_time_series(times, [self.sig, self.results[result_index].sig_pe], xlim=xlim, alpha=[0.5, 1, 1], ax=axes[0]) axes[0].set_ylabel("") axes[0].set_xlabel("") axes[0].set_title('Motif Detection and Fitting', fontsize=20) axes[0].tick_params(axis='y', labelsize=12) # Plot affine matrix params titles = [ 'Rotation', 'Translation X', 'Translation Y', 'Scale X', 'Scale Y', 'Shear' ] for idx in range(len(param_arr)): axes[idx + 1].plot(times, param_arr[idx]) axes[idx + 1].set_xlim(xlim) axes[idx + 1].set_title(titles[idx], fontsize=16) axes[len(param_arr)].set_xlabel('Time', fontsize=16)
for idx in range(len(sigs)): sigs[idx] = filter_signal(sigs[idx], fs, 'lowpass', 30, n_seconds=.2, remove_edges=False) #################################################################################################### # Plot an example signal n_signals = len(sigs) n_seconds = len(sigs[0]) / fs times = np.arange(0, n_seconds, 1 / fs) plot_time_series(times, sigs[0], lw=2) #################################################################################################### # # Compute cycle-by-cycle features # ------------------------------- #################################################################################################### f_alpha = (7, 13) # Frequency band of interest burst_kwargs = { 'amp_fraction_threshold': .2, 'amp_consistency_threshold': .5, 'period_consistency_threshold': .5, 'monotonicity_threshold': .8, 'n_cycles_min': 3
s_rate = 1000 n_seconds = 4 times = create_times(n_seconds, s_rate) # Set random seed, for consistency generating simulated data set_random_seed(21) ################################################################################################### # Simulate a signal of aperiodic activity: pink noise sig = sim_powerlaw(n_seconds, s_rate, exponent=-1) ################################################################################################### # Plot our simulated time series plot_time_series(times, sig) ################################################################################################### # Filtering Aperiodic Signals # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Now that we have a simulated signal, let's filter it into each of our frequency bands. # # To do so, we will loop across our band definitions, and plot the filtered version # of the signal. # ################################################################################################### # Apply band-by-band filtering of our signal into each defined frequency band _, axes = plt.subplots(len(bands), 1, figsize=(12, 15))
t_start = 20000 t_stop = int(t_start + (10 * fs)) ################################################################################################### # Extract an example channel to explore sig, times = raw.get_data(mne.pick_channels(raw.ch_names, [ch_label]), start=t_start, stop=t_stop, return_times=True) sig = np.squeeze(sig) ################################################################################################### # Plot a segment of the extracted time series data plot_time_series(times, sig) ################################################################################################### # Calculate Power Spectra # ----------------------- # # Next lets check the data in the frequency domain, calculating a power spectrum # with the median welch's procedure from NeuroDSP. # ################################################################################################### # Calculate the power spectrum, using a median welch & extract a frequency range of interest freqs, powers = compute_spectrum(sig, fs, method='welch', avg_type='median') freqs, powers = trim_spectrum(freqs, powers, [3, 30])
def plot_burst_detect_param(df_features, sig, fs, burst_param, thresh, xlim=None, interp=True, ax=None, **kwargs): """Plot a burst detection parameter and threshold. Parameters ---------- df_features : pandas.DataFrame Dataframe output of :func:`~.compute_features`. sig : 1d array Time series to plot. fs : float Sampling rate, in Hz. burst_param : str Column name of the parameter of interest in ``df``. thresh : float The burst parameter threshold. Parameter values greater than ``thresh`` are considered bursts. xlim : tuple of (float, float), optional, default: None Start and stop times for plot. interp : bool, optional, default: True Interpolates points if true. ax : matplotlib.Axes, optional Figure axes upon which to plot. **kwargs Keyword arguments to pass into `plot_time_series`. Notes ----- Default keyword arguments include: - ``figsize``: tuple of (float, float), default: (15, 3) - ``xlabel``: str, default: 'Time (s)' - ``ylabel``: str, default: 'Voltage (uV) - ``color``: str, default: 'r'. - Note: ``color`` here is the fill color, rather than line color. Examples -------- Plot the monotonicity of a bursting signal: >>> from bycycle.features import compute_features >>> from neurodsp.sim import sim_bursty_oscillation >>> fs = 500 >>> sig = sim_bursty_oscillation(10, fs, freq=10) >>> threshold_kwargs = {'amp_fraction_threshold': 0., 'amp_consistency_threshold': .5, ... 'period_consistency_threshold': .5, 'monotonicity_threshold': .8} >>> df_features = compute_features(sig, fs, f_range=(8, 12), ... threshold_kwargs=threshold_kwargs) >>> plot_burst_detect_param(df_features, sig, fs, 'monotonicity', .8) """ # Ensure arguments are within valid range check_param_range(fs, 'fs', (0, np.inf)) # Set default kwargs figsize = kwargs.pop('figsize', (15, 3)) xlabel = kwargs.pop('xlabel', 'Time (s)') ylabel = kwargs.pop('ylabel', burst_param) color = kwargs.pop('color', 'r') # Determine time array and limits times = np.arange(0, len(sig) / fs, 1 / fs) xlim = (times[0], times[-1]) if xlim is None else xlim if ax is None: fig, ax = plt.subplots(figsize=figsize) # Determine extrema strings center_e, side_e = get_extrema_df(df_features) # Limit dataframe, sig and times df = limit_df(df_features, fs, start=xlim[0], stop=xlim[1]) sig, times = limit_signal(times, sig, start=xlim[0], stop=xlim[1]) # Remove start / end cycles that tlims falls between df = df[(df['sample_last_' + side_e] >= 0) & \ (df['sample_next_' + side_e] < xlim[1]*fs)] # Plot burst param if interp: plot_time_series([times[df['sample_' + center_e]], xlim], [df[burst_param], [thresh] * 2], ax=ax, colors=['k', 'k'], ls=['-', '--'], marker=["o", None], xlabel=xlabel, ylabel="{0:s}\nthreshold={1:.2f}".format( ylabel, thresh), **kwargs) else: # Create steps, from side to side of each cycle, and set the y-value # to the burst parameter value for that cycle side_times = np.array([]) side_param = np.array([]) for _, cyc in df.iterrows(): # Get the times for the last and next side of a cycle side_times = np.append(side_times, [ times[int(cyc['sample_last_' + side_e])], times[int( cyc['sample_next_' + side_e])] ]) # Set the y-value, from side to side, to the burst param for each cycle side_param = np.append(side_param, [cyc[burst_param]] * 2) plot_time_series([side_times, xlim], [side_param, [thresh] * 2], ax=ax, colors=['k', 'k'], ls=['-', '--'], marker=["o", None], xlim=xlim, xlabel=xlabel, ylabel="{0:s}\nthreshold={1:.2f}".format( ylabel, thresh), **kwargs) # Highlight where param falls below threshold for _, cyc in df.iterrows(): if cyc[burst_param] <= thresh: ax.axvspan(times[int(cyc['sample_last_' + side_e])], times[int(cyc['sample_next_' + side_e])], alpha=0.5, color=color, lw=0)
def plot_cyclepoints_array(sig, fs, peaks=None, troughs=None, rises=None, decays=None, plot_sig=True, xlim=None, ax=None, **kwargs): """Plot extrema and/or zero-crossings from arrays. Parameters ---------- sig : 1d array Time series to plot. fs : float Sampling rate, in Hz. peaks : 1d array, optional Peak signal indices from :func:`.find_extrema`. troughs : 1d array, optional Trough signal indices from :func:`.find_extrema`. rises : 1d array, optional Zero-crossing rise indices from :func:`~.find_zerox`. decays : 1d array, optional Zero-crossing decay indices from :func:`~.find_zerox`. plot_sig : bool, optional, default: True Whether to also plot the raw signal. xlim : tuple of (float, float), optional Start and stop times. ax : matplotlib.Axes, optional, default: None Figure axes upon which to plot. **kwargs Keyword arguments to pass into `plot_time_series`. Notes ----- Default keyword arguments include: - ``figsize``: tuple of (float, float), default: (15, 3) - ``xlabel``: str, default: 'Time (s)' - ``ylabel``: str, default: 'Voltage (uV) - ``colors``: list, default: ['k', 'b', 'r', 'g', 'm'] Examples -------- Plot cyclepoints using arrays from :func:`.find_extrema` and :func:`~.find_zerox`: >>> from bycycle.cyclepoints import find_extrema, find_zerox >>> from neurodsp.sim import sim_bursty_oscillation >>> fs = 500 >>> sig = sim_bursty_oscillation(10, fs, freq=10) >>> peaks, troughs = find_extrema(sig, fs, f_range=(8, 12), boundary=0) >>> rises, decays = find_zerox(sig, peaks, troughs) >>> plot_cyclepoints_array(sig, fs, peaks=peaks, troughs=troughs, rises=rises, decays=decays) """ # Ensure arguments are within valid range check_param_range(fs, 'fs', (0, np.inf)) # Set times and limits times = np.arange(0, len(sig) / fs, 1 / fs) # Restrict sig and times to xlim if xlim is not None: sig, times = limit_signal(times, sig, start=xlim[0], stop=xlim[1]) # Set default kwargs figsize = kwargs.pop('figsize', (15, 3)) xlabel = kwargs.pop('xlabel', 'Time (s)') ylabel = kwargs.pop('ylabel', 'Voltage (uV)') default_colors = ['b', 'r', 'g', 'm'] # Extend plotting based on given arguments x_values = [] y_values = [] colors = ['k'] for idx, points in enumerate([peaks, troughs, rises, decays]): if points is not None: # Limit times and shift indices of cyclepoints (cps) cps = points[(points >= times[0] * fs) & (points < times[-1] * fs)] cps = cps - int(times[0] * fs) y_values.append(sig[cps]) x_values.append(times[cps]) colors.append(default_colors[idx]) # Allow custom colors to overwrite default colors = kwargs.pop('colors', colors) if ax is None: fig, ax = plt.subplots(figsize=figsize) if plot_sig: plot_time_series(times, sig, colors=colors[0], ax=ax) colors = colors[1:] plot_time_series(x_values, y_values, ax=ax, xlabel=xlabel, ylabel=ylabel, colors=colors, marker='o', ls='', **kwargs)
def plot_cyclepoints_array(sig, fs, peaks=None, troughs=None, rises=None, decays=None, plot_sig=True, xlim=None, ax=None, **kwargs): """Plot extrema and/or zero-crossings using arrays to define points. Parameters ---------- sig : 1d array Time series to plot. fs : float Sampling rate, in Hz. xlim : tuple of (float, float), optional, default: None Start and stop times. peaks : 1d array, optional, default: None Peak signal indices from :func:`.find_extrema`. troughs : 1d array, optional, default: None Trough signal indices from :func:`.find_extrema`. rises : 1d array, optional, default: None Zero-crossing rise indices from :func:`~.find_zerox`. decays : 1d array, optional, default: None Zero-crossing decay indices from :func:`~.find_zerox`. ax : matplotlib.Axes, optional, default: None Figure axes upon which to plot. **kwargs Keyword arguments to pass into `plot_time_series`. Notes ----- Default keyword arguments include: - ``figsize``: tuple of (float, float), default: (15, 3) - ``xlabel``: str, default: 'Time (s)' - ``ylabel``: str, default: 'Voltage (uV) - ``colors``: list, default: ['k', 'b', 'r', 'g', 'm'] """ # Set times and limits times = np.arange(0, len(sig) / fs, 1 / fs) xlim = (times[0], times[-1]) if xlim is None else xlim # Restrict sig and times to xlim sig, times = limit_signal(times, sig, start=xlim[0], stop=xlim[1]) # Set default kwargs figsize = kwargs.pop('figsize', (15, 3)) xlabel = kwargs.pop('xlabel', 'Time (s)') ylabel = kwargs.pop('ylabel', 'Voltage (uV)') default_colors = ['b', 'r', 'g', 'm'] # Extend plotting based on given arguments x_values = [] y_values = [] colors = ['k'] for idx, points in enumerate([peaks, troughs, rises, decays]): if points is not None: # Limit times and shift indices of cyclepoints (cps) cps = points[(points >= xlim[0] * fs) & (points < xlim[1] * fs)] cps = cps - int(xlim[0] * fs) y_values.append(sig[cps]) x_values.append(times[cps]) colors.append(default_colors[idx]) # Allow custom colors to overwrite default colors = kwargs.pop('colors', colors) if ax is None: fig, ax = plt.subplots(figsize=figsize) if plot_sig: plot_time_series(times, sig, colors=colors[0], ax=ax) colors = colors[1:] plot_time_series(x_values, y_values, ax=ax, xlabel=xlabel, ylabel=ylabel, colors=colors, marker='o', ls='', **kwargs)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #################################################################################################### # Choose samples to plot samplims = (10000, 12000) ca1_plt = ca1_raw[samplims[0]:samplims[1]] / 1000 ec3_plt = ec3_raw[samplims[0]:samplims[1]] / 1000 times = np.arange(0, len(ca1_plt) / fs, 1 / fs) fig, axes = plt.subplots(figsize=(15, 6), nrows=2) plot_time_series(times, ca1_plt, ax=axes[0], xlim=(0, 1.6), ylim=(-2.4, 2.4), xlabel="Time (s)", ylabel="CA1 Voltage (mV)") plot_time_series(times, ec3_plt, ax=axes[1], colors='r', xlim=(0, 1.6), ylim=(-2.4, 2.4), xlabel="Time (s)", ylabel="EC3 Voltage (mV)") #################################################################################################### #
phase_filt_signal = filter_signal(data[:, ch], fs, 'bandpass', phase_providing_band) ampl_filt_signal = filter_signal(data[:, ch], fs, 'bandpass', amplitude_providing_band) # calculate the phase phase_signal = phase_by_time(data[:, ch], fs, phase_providing_band) # Compute instaneous amplitude from a signal amp_signal = amp_by_time(sig, fs, amplitude_providing_band) #%% Plot the phase # plot of phase: raw data, filtered, and phase _, axs = plt.subplots(3, 1, figsize=(15, 6)) plot_time_series(times, data[:, ch], xlim=plt_time, xlabel=None, ax=axs[0]) plot_time_series(times, phase_filt_signal, xlim=plt_time, xlabel=None, ax=axs[1]) plot_instantaneous_measure(times, phase_signal, xlim=plt_time, ax=axs[2]) #%% Plot the amplitudes # plot of amplitude: raw + abs ampls, and filtered + abs ampls _, axs = plt.subplots(2, 1, figsize=(15, 6)) plot_instantaneous_measure(times, [data[:, ch], amp_signal], 'amplitude', labels=['Raw Voltage', 'Amplitude'], xlim=plt_time,