예제 #1
0
    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))
예제 #3
0
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)
예제 #4
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)
예제 #5
0
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)
예제 #6
0
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# 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-
예제 #7
0
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
예제 #8
0
        '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.
#
예제 #9
0
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
예제 #11
0
###################################################################################################
# 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,
예제 #13
0
    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
예제 #15
0
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))
예제 #16
0
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])
예제 #17
0
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)
예제 #18
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)
예제 #19
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 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)")

####################################################################################################
#
예제 #21
0
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,