Example #1
0
def plot_prd_spike_count(spk_cnt, prd, sps, fig):
    """Plot spike count results for period."""

    # Init axes.
    ax_total, ax_per_tr, ax_mean = putil.sps_add_axes(fig, sps, 1, 3)

    # Plot total spike count histogram.
    plot_spike_count_hist(spk_cnt.unstack(), prd + ', all trials', ax_total)

    # Per trial.
    cols = sns.color_palette('Spectral', len(spk_cnt.index))
    for (itr, nspk), col in zip(spk_cnt.iterrows(), cols):
        plot_spike_count_hist(nspk, prd + ', per trial', ax_per_tr,
                              False, 1.0, col, 1)

    # Mean over time.
    x = spk_cnt.index
    y = spk_cnt.median(1)
    pplot.lines(x, y, xlim=[x.min(), x.max()], xlab='trial index',
                ylab='mean spike counts', title='median over time', ax=ax_mean)

    # Format figures.
    for ax in (ax_total, ax_per_tr):
        putil.set_limits(ax, xlim=[-0.5, None], ylim=[0, None])

    return ax_total, ax_per_tr, ax_mean
Example #2
0
def plot_tuning(xfit,
                yfit,
                vals=None,
                meanr=None,
                semr=None,
                color='b',
                baseline=None,
                xticks=None,
                xlim=None,
                ylim=None,
                xlab=None,
                ylab=None,
                title=None,
                ffig=None,
                ax=None,
                **kwargs):
    """Plot tuning curve, optionally with data samples."""

    ax = putil.axes(ax)

    # Plot baseline.
    if baseline is not None:
        putil.add_baseline(baseline, ax=ax)

    # Plot fitted curve.
    pplot.lines(xfit, yfit, color=color, ax=ax)

    # Plot data samples.
    if meanr is not None and semr is not None:
        pplot.errorbar(vals,
                       meanr,
                       yerr=semr,
                       fmt='o',
                       color=color,
                       ax=ax,
                       **kwargs)

    # Set x axis ticks.
    if xticks is not None:
        putil.set_xtick_labels(ax, xticks)
    elif vals is not None:
        putil.set_xtick_labels(ax, vals)

    # Format plot.
    putil.format_plot(ax, xlim, ylim, xlab, ylab, title)

    # Save and return plot.
    putil.save_fig(ffig)
    return ax
Example #3
0
def plot_auc_over_time(auc,
                       tvec,
                       prds=None,
                       evts=None,
                       xlim=None,
                       ylim=None,
                       xlab='time',
                       ylab='AUC',
                       title=None,
                       ax=None):
    """Plot AROC values over time."""

    # Init params.
    ax = putil.axes(ax)
    if xlim is None:
        xlim = [min(tvec), max(tvec)]

    # Plot periods first.
    putil.plot_periods(prds, ax=ax)

    # Plot AUC over time.
    pplot.lines(tvec, auc, ylim, xlim, xlab, ylab, title, color='green', ax=ax)

    # Add chance level line.
    putil.add_chance_level(ax=ax)

    #    # Set minimum y axis scale.
    #    ymin, ymax = ax.get_ylim()
    #    ymin, ymax = min(ymin, 0.3), max(ymax, 0.7)
    #    ax.set_ylim([ymin, ymax])

    # Set y tick labels.
    if ylim is not None and ylim[0] == 0 and ylim[1] == 1:
        tck_marks = np.linspace(0, 1, 5)
        tck_lbls = np.array(tck_marks, dtype=str)
        tck_lbls[1::2] = ''
        putil.set_ytick_labels(ax, tck_marks, tck_lbls)
    putil.set_max_n_ticks(ax, 5, 'y')

    # Plot event markers.
    putil.plot_event_markers(evts, ax=ax)

    return ax
Example #4
0
def plot_qm(u,
            bs_stats,
            stab_prd_res,
            prd_inc,
            tr_inc,
            spk_inc,
            add_lbls=False,
            ftempl=None,
            fig=None,
            sps=None):
    """Plot quality metrics related figures."""

    # Init values.
    waveforms = np.array(u.Waveforms)
    wavetime = u.Waveforms.columns * us
    spk_times = np.array(u.SpikeParams['time'], dtype=float)
    base_rate = u.QualityMetrics['baseline']

    # Minimum and maximum gain.
    gmin = u.SessParams['minV']
    gmax = u.SessParams['maxV']

    # %% Init plots.

    # Disable inline plotting to prevent memory leak.
    putil.inline_off()

    # Init figure and gridspec.
    fig = putil.figure(fig)
    if sps is None:
        sps = putil.gridspec(1, 1)[0]
    ogsp = putil.embed_gsp(sps, 2, 1, height_ratios=[0.02, 1])

    info_sps, qm_sps = ogsp[0], ogsp[1]

    # Info header.
    info_ax = fig.add_subplot(info_sps)
    putil.hide_axes(info_ax)
    title = putil.get_unit_info_title(u)
    putil.set_labels(ax=info_ax, title=title, ytitle=0.80)

    # Create axes.
    gsp = putil.embed_gsp(qm_sps, 3, 2, wspace=0.3, hspace=0.4)
    ax_wf_inc, ax_wf_exc = [fig.add_subplot(gsp[0, i]) for i in (0, 1)]
    ax_wf_amp, ax_wf_dur = [fig.add_subplot(gsp[1, i]) for i in (0, 1)]
    ax_amp_dur, ax_rate = [fig.add_subplot(gsp[2, i]) for i in (0, 1)]

    # Trial markers.
    trial_starts, trial_stops = u.TrData.TrialStart, u.TrData.TrialStop
    tr_markers = pd.DataFrame({'time': trial_starts[9::10]})
    tr_markers['label'] = [
        str(itr + 1) if i % 2 else '' for i, itr in enumerate(tr_markers.index)
    ]

    # Common variables, limits and labels.
    WF_T_START = test_sorting.WF_T_START
    spk_t = u.SessParams.sampl_prd * (np.arange(waveforms.shape[1]) -
                                      WF_T_START)
    ses_t_lim = test_sorting.get_start_stop_times(spk_times, trial_starts,
                                                  trial_stops)
    ss, sa = 1.0, 0.8  # marker size and alpha on scatter plot

    # Color spikes by their occurance over session time.
    my_cmap = putil.get_cmap('jet')
    spk_cols = np.tile(np.array([.25, .25, .25, .25]), (len(spk_times), 1))
    if np.any(spk_inc):  # check if there is any spike included
        spk_t_inc = np.array(spk_times[spk_inc])
        tmin, tmax = float(spk_times.min()), float(spk_times.max())
        spk_cols[spk_inc, :] = my_cmap((spk_t_inc - tmin) / (tmax - tmin))
    # Put excluded trials to the front, and randomise order of included trials
    # so later spikes don't systematically cover earlier ones.
    spk_order = np.hstack((np.where(np.invert(spk_inc))[0],
                           np.random.permutation(np.where(spk_inc)[0])))

    # Common labels for plots
    ses_t_lab = 'Recording time (s)'

    # %% Waveform shape analysis.

    # Plot included and excluded waveforms on different axes.
    # Color included by occurance in session time to help detect drifts.
    s_waveforms, s_spk_cols = waveforms[spk_order, :], spk_cols[spk_order]
    wf_t_lim, glim = [min(spk_t), max(spk_t)], [gmin, gmax]
    wf_t_lab, volt_lab = 'WF time ($\mu$s)', 'Voltage'
    for st in ('Included', 'Excluded'):
        ax = ax_wf_inc if st == 'Included' else ax_wf_exc
        spk_idx = spk_inc if st == 'Included' else np.invert(spk_inc)
        tr_idx = tr_inc if st == 'Included' else np.invert(tr_inc)

        nspsk, ntrs = sum(spk_idx), sum(tr_idx)
        title = '{} WFs, {} spikes, {} trials'.format(st, nspsk, ntrs)

        # Select waveforms and colors.
        rand_spk_idx = spk_idx[spk_order]
        wfs = s_waveforms[rand_spk_idx, :]
        cols = s_spk_cols[rand_spk_idx]

        # Plot waveforms.
        xlab, ylab = (wf_t_lab, volt_lab) if add_lbls else (None, None)
        pwaveform.plot_wfs(wfs,
                           spk_t,
                           cols=cols,
                           lw=0.1,
                           alpha=0.05,
                           xlim=wf_t_lim,
                           ylim=glim,
                           title=title,
                           xlab=xlab,
                           ylab=ylab,
                           ax=ax)

    # %% Waveform summary metrics.

    # Init data.
    wf_amp_all = u.SpikeParams['amplitude']
    wf_amp_inc = wf_amp_all[spk_inc]
    wf_dur_all = u.SpikeParams['duration']
    wf_dur_inc = wf_dur_all[spk_inc]

    # Set common limits and labels.
    dur_lim = [0, wavetime[-2] - wavetime[WF_T_START]]  # same across units
    glim = max(wf_amp_all.max(), gmax - gmin)
    amp_lim = [0, glim]

    amp_lab = 'Amplitude'
    dur_lab = 'Duration ($\mu$s)'

    # Waveform amplitude across session time.
    m_amp, sd_amp = wf_amp_inc.mean(), wf_amp_inc.std()
    title = 'WF amplitude: {:.1f} $\pm$ {:.1f}'.format(m_amp, sd_amp)
    xlab, ylab = (ses_t_lab, amp_lab) if add_lbls else (None, None)
    pplot.scatter(spk_times,
                  wf_amp_all,
                  spk_inc,
                  c='m',
                  bc='grey',
                  s=ss,
                  xlab=xlab,
                  ylab=ylab,
                  xlim=ses_t_lim,
                  ylim=amp_lim,
                  edgecolors='',
                  alpha=sa,
                  id_line=False,
                  title=title,
                  ax=ax_wf_amp)

    # Waveform duration across session time.
    mdur, sdur = wf_dur_inc.mean(), wf_dur_inc.std()
    title = 'WF duration: {:.1f} $\pm$ {:.1f} $\mu$s'.format(mdur, sdur)
    xlab, ylab = (ses_t_lab, dur_lab) if add_lbls else (None, None)
    pplot.scatter(spk_times,
                  wf_dur_all,
                  spk_inc,
                  c='c',
                  bc='grey',
                  s=ss,
                  xlab=xlab,
                  ylab=ylab,
                  xlim=ses_t_lim,
                  ylim=dur_lim,
                  edgecolors='',
                  alpha=sa,
                  id_line=False,
                  title=title,
                  ax=ax_wf_dur)

    # Waveform duration against amplitude.
    title = 'WF duration - amplitude'
    xlab, ylab = (dur_lab, amp_lab) if add_lbls else (None, None)
    pplot.scatter(wf_dur_all[spk_order],
                  wf_amp_all[spk_order],
                  c=spk_cols[spk_order],
                  s=ss,
                  xlab=xlab,
                  ylab=ylab,
                  xlim=dur_lim,
                  ylim=amp_lim,
                  edgecolors='',
                  alpha=sa,
                  id_line=False,
                  title=title,
                  ax=ax_amp_dur)

    # %% Firing rate.

    tmean = np.array(bs_stats['tmean'])
    rmean = util.remove_dim_from_series(bs_stats['rate'])
    prd_tstart, prd_tstop = stab_prd_res['tstart'], stab_prd_res['tstop']

    # Color segments depending on whether they are included / excluded.
    def plot_periods(v, color, ax):
        # Plot line segments.
        for i in range(len(prd_inc[:-1])):
            col = color if prd_inc[i] and prd_inc[i + 1] else 'grey'
            x, y = [(tmean[i], tmean[i + 1]), (v[i], v[i + 1])]
            ax.plot(x, y, color=col)
        # Plot line points.
        for i in range(len(prd_inc)):
            col = color if prd_inc[i] else 'grey'
            x, y = [tmean[i], v[i]]
            ax.plot(x,
                    y,
                    color=col,
                    marker='o',
                    markersize=3,
                    markeredgecolor=col)

    # Firing rate over session time.
    title = 'Baseline rate: {:.1f} spike/s'.format(float(base_rate))
    xlab, ylab = (ses_t_lab, putil.FR_lbl) if add_lbls else (None, None)
    ylim = [0, 1.25 * np.max(rmean)]
    plot_periods(rmean, 'b', ax_rate)
    pplot.lines([], [],
                c='b',
                xlim=ses_t_lim,
                ylim=ylim,
                title=title,
                xlab=xlab,
                ylab=ylab,
                ax=ax_rate)

    # Trial markers.
    putil.plot_events(tr_markers,
                      lw=0.5,
                      ls='--',
                      alpha=0.35,
                      y_lbl=0.92,
                      ax=ax_rate)

    # Excluded periods.
    excl_prds = []
    tstart, tstop = ses_t_lim
    if tstart != prd_tstart:
        excl_prds.append(('beg', tstart, prd_tstart))
    if tstop != prd_tstop:
        excl_prds.append(('end', prd_tstop, tstop))
    putil.plot_periods(excl_prds, ymax=0.92, ax=ax_rate)

    # %% Post-formatting.

    # Maximize number of ticks on recording time axes to prevent covering.
    for ax in (ax_wf_amp, ax_wf_dur, ax_rate):
        putil.set_max_n_ticks(ax, 6, 'x')

    # %% Save figure.
    if ftempl is not None:
        fname = ftempl.format(u.name_to_fname())
        putil.save_fig(fname, fig, title, rect_height=0.92)
        putil.inline_on()

    return [ax_wf_inc, ax_wf_exc], ax_wf_amp, ax_wf_dur, ax_amp_dur, ax_rate
Example #5
0
def plot_DR(dirs,
            resp,
            DSI=None,
            PD=None,
            baseline=None,
            plot_type='line',
            complete_missing_dirs=False,
            color='b',
            title=None,
            ffig=None,
            ax=None):
    """
    Plot response to each directions on polar plot, with a vector pointing to
    preferred direction (PD) with length DSI.
    Use plot_type to change between sector ('bar') and connected ('line') plot
    types.
    """

    ax = putil.axes(ax, polar=True)

    # Plot baseline.
    if baseline is not None:
        putil.add_baseline(baseline, ax=ax)

    # Remove NaNs.
    all_dirs = dirs
    not_nan = np.array(~pd.isnull(dirs) & ~pd.isnull(resp))
    dirs, resp = dirs[not_nan], np.array(resp[not_nan])

    # Prepare data.
    # Complete missing directions with 0 response.
    if complete_missing_dirs:
        for i, d in enumerate(all_dirs):
            if d not in dirs:
                dirs = np.insert(dirs, i, d) * dirs.units
                resp = np.insert(resp, i, 0) * 1 / s

    rad_dirs = dirs.rescale(rad)

    # Plot response to each directions on polar plot.
    if plot_type == 'bar':  # sector plot
        ndirs = all_dirs.size
        left_rad_dirs = rad_dirs - np.pi / ndirs  # no need for this in MPL 2.0?
        w = 2 * np.pi / ndirs  # same with edgecolor and else?
        pplot.bars(left_rad_dirs,
                   resp,
                   width=w,
                   alpha=0.50,
                   color=color,
                   lw=1,
                   edgecolor='w',
                   title=title,
                   ytitle=1.08,
                   ax=ax)
    else:  # line plot
        rad_dirs, resp = [np.append(v, [v[0]]) for v in (rad_dirs, resp)]
        pplot.lines(rad_dirs,
                    resp,
                    color=color,
                    marker='o',
                    lw=1,
                    ms=4,
                    mew=0,
                    title=title,
                    ytitle=1.08,
                    ax=ax)
        ax.fill(rad_dirs, resp, color=color, alpha=0.15)

    # Add arrow representing PD and weighted DSI.
    if DSI is not None and PD is not None:
        rho = np.max(resp) * DSI
        xy = (float(PD.rescale(rad)), rho)
        arr_props = dict(facecolor=color, edgecolor='k', shrink=0.0, alpha=0.5)
        ax.annotate('', xy, xytext=(0, 0), arrowprops=arr_props)

    # Remove spines and tick marks, maximize tick labels.
    putil.set_spines(ax, False, False)
    putil.hide_tick_marks(ax)

    # Save and return plot.
    putil.save_fig(ffig)
    return ax
Example #6
0
def rec_stability_test(UA, fname=None, periods=None):
    """Check stability of recording session across tasks."""

    # Init.
    if periods is None:
        periods = ['whole trial', 'fixation']

    # Init figure.
    fig, gsp, axs = putil.get_gs_subplots(nrow=len(periods), ncol=1,
                                          subw=10, subh=2.5, create_axes=True,
                                          as_array=False)

    for prd, ax in zip(periods, axs):

        # Calculate and plot firing rate during given period in each trial
        # across session for all units.
        colors = putil.get_colors()
        task_stats = pd.DataFrame(columns=['t_start', 't_stops', 'label'])
        for task, color in zip(UA.tasks(), colors):

            # Get activity of all units in task.
            tr_rates = []
            for u in UA.iter_thru([task]):
                rates = u.get_prd_rates(prd, tr_time_idx=True)
                tr_rates.append(util.remove_dim_from_series(rates))
            tr_rates = pd.DataFrame(tr_rates)

            # Not (non-empty and included) unit during task.
            if not len(tr_rates.index):
                continue

            # Plot each rate in task.
            tr_times = tr_rates.columns
            pplot.lines(tr_times, tr_rates.T, zorder=1, alpha=0.5,
                        color=color, ax=ax)

            # Plot mean +- sem rate.
            tr_time = tr_rates.columns
            mean_rate, sem_rate = tr_rates.mean(), tr_rates.std()
            lower, upper = mean_rate-sem_rate, mean_rate+sem_rate
            lower[lower < 0] = 0  # remove negative values
            ax.fill_between(tr_time, lower, upper, zorder=2, alpha=.5,
                            facecolor='grey', edgecolor='grey')
            pplot.lines(tr_time, mean_rate, lw=2, color='k', ax=ax)

            # Add task stats.
            task_lbl = '{}, {} units'.format(task, len(tr_rates.index))

            # Add grand mean FR.
            task_lbl += '\nFR: {:.1f} sp/s'.format(tr_rates.mean().mean())

            # Calculate linear trend to test gradual drift.
            slope, _, _, p_value, _ = sp.stats.linregress(tr_times, mean_rate)
            slope = 3600*slope  # convert to change in spike per hour
            pval = util.format_pvalue(p_value, max_digit=3)
            task_lbl += '\n$\delta$FR: {:.1f} sp/s/h'.format(slope)
            task_lbl += '\n{}'.format(pval)

            task_stats.loc[task] = (tr_times.min(), tr_times.max(), task_lbl)

        # Set axes limits.
        tmin, tmax = task_stats.t_start.min(), task_stats.t_stops.max()
        putil.set_limits(ax, xlim=(tmin, tmax))

        # Add task labels after all tasks have been plotted.
        putil.plot_events(task_stats[['t_start', 'label']], y_lbl=0.75,
                          lbl_ha='left', lbl_rotation=0, ax=ax)

        # Format plot.
        xlab = 'Recording time (s)' if prd == periods[-1] else None
        putil.set_labels(ax, xlab=xlab, ylab=prd)
        putil.set_spines(ax, left=False)

    # Save figure.
    title = 'Recording stability of ' + UA.Name
    putil.save_fig(fname, fig, title)