def plot_pair_examples(df, vthresh=5, sthresh=3, plot_dir=None):


    def select_cases(ntrial, ca, npair):

        if (ntrial==0) and (ca== 'CA1') and (npair==9):
            return 'kld', 1
        elif (ntrial==7) and (ca== 'CA1') and (npair==22):
            return 'kld', 0

        elif (ntrial==123) and (ca== 'CA1') and (npair==0):  # 628
            return 'eg', 14
        elif (ntrial==9) and (ca== 'CA1') and (npair==1):  # 140
            return 'eg', 4
        elif (ntrial==56) and (ca== 'CA1') and (npair==1):  # 334
            return 'eg', 8
        elif (ntrial==73) and (ca== 'CA1') and (npair==2):  # 394
            return 'eg', 12
        elif (ntrial==17) and (ca== 'CA2') and (npair==4):  # 256
            return 'eg', 0
        elif (ntrial==18) and (ca== 'CA2') and (npair==4):  # 263
            return 'eg', 6
        elif (ntrial==26) and (ca== 'CA3') and (npair==1):  # 299
            return 'eg', 10
        elif (ntrial==21) and (ca== 'CA3') and (npair==2):  # 283
            return 'eg', 2
        else:
            return None, None

    all_ntrials = [0, 7, 123, 9, 56, 73, 17, 18, 26, 21]


    # Paired spikes
    figw_pairedsp = total_figw*0.8
    figh_pairedsp = figw_pairedsp/5


    # Pair eg
    figw_paireg = total_figw*0.8
    figh_paireg = figw_paireg/4 * 1.1
    fig_paireg = plt.figure(figsize=(figw_paireg, figh_paireg))
    ax_paireg = np.array([
        fig_paireg.add_subplot(2, 8, 1), fig_paireg.add_subplot(2, 8, 2, polar=True),
         fig_paireg.add_subplot(2, 8, 3), fig_paireg.add_subplot(2, 8, 4, polar=True),
         fig_paireg.add_subplot(2, 8, 5), fig_paireg.add_subplot(2, 8, 6, polar=True),
         fig_paireg.add_subplot(2, 8, 7), fig_paireg.add_subplot(2, 8, 8, polar=True),
         fig_paireg.add_subplot(2, 8, 9), fig_paireg.add_subplot(2, 8, 10, polar=True),
         fig_paireg.add_subplot(2, 8, 11), fig_paireg.add_subplot(2, 8, 12, polar=True),
         fig_paireg.add_subplot(2, 8, 13), fig_paireg.add_subplot(2, 8, 14, polar=True),
         fig_paireg.add_subplot(2, 8, 15), fig_paireg.add_subplot(2, 8, 16, polar=True),
    ])

    # KLD
    figw_kld = total_figw*0.9/2  # leave 0.2 for colorbar in fig 5
    figh_kld = total_figw*0.9/4
    fig_kld, ax_kld = plt.subplots(2, 4, figsize=(figw_kld, figh_kld), subplot_kw={'polar':True})


    num_trials = df.shape[0]
    aedges = np.linspace(-np.pi, np.pi, 36)
    aedm = midedges(aedges)
    abind = aedges[1] - aedges[0]
    sp_binwidth = 5
    precess_filter = PrecessionFilter()
    for ntrial in range(num_trials):
        if ntrial not in all_ntrials:
            continue
        wave = df.loc[ntrial, 'wave']
        precesser = PrecessionProcesser(sthresh=sthresh, vthresh=vthresh, wave=wave)


        for ca in ['CA%d' % (i + 1) for i in range(3)]:

            # Get data
            pair_df = df.loc[ntrial, ca + 'pairs']
            field_df = df.loc[ntrial, ca + 'fields']
            indata = df.loc[ntrial, ca + 'indata']
            if (indata.shape[0] < 1) & (pair_df.shape[0] < 1) & (field_df.shape[0] < 1):
                continue

            tunner = IndataProcessor(indata, vthresh=vthresh, smooth=True)
            interpolater_angle = interp1d(tunner.t, tunner.angle)
            interpolater_x = interp1d(tunner.t, tunner.x)
            interpolater_y = interp1d(tunner.t, tunner.y)
            all_maxt, all_mint = tunner.t.max(), tunner.t.min()
            trange = (all_maxt, all_mint)
            dt = tunner.t[1] - tunner.t[0]
            precesser.set_trange(trange)

            ##  Loop for pairs
            num_pairs = pair_df.shape[0]
            for npair in range(num_pairs):

                case, case_axid = select_cases(ntrial, ca, npair)
                if case is None:
                    continue

                print('trial %d, %s, pair %d, case=%s' % (ntrial, ca, npair, case))

                # find within-mask indexes
                field_ids = pair_df.loc[npair, 'fi'] - 1  # minus 1 to convert to python index
                mask1 = field_df.loc[field_ids[0], 'mask']
                mask2 = field_df.loc[field_ids[1], 'mask']

                # field's boundaries
                xyval1 = field_df.loc[field_ids[0], 'xyval']
                xyval2 = field_df.loc[field_ids[1], 'xyval']

                # Find overlap
                pf1 = field_df.loc[field_ids[0], 'pf']
                pf2 = field_df.loc[field_ids[1], 'pf']
                _, ks_dist, _ = dist_overlap(pf1['map'], pf2['map'], mask1, mask2)

                # Field's center coordinates
                maskedmap1, maskedmap2 = pf1['map'] * mask1, pf2['map'] * mask2
                cooridx1 = np.unravel_index(maskedmap1.argmax(), maskedmap1.shape)
                cooridx2 = np.unravel_index(maskedmap2.argmax(), maskedmap2.shape)
                fcoor1 = np.array([pf1['X'][cooridx1[0], cooridx1[1]], pf1['Y'][cooridx1[0], cooridx1[1]]])
                fcoor2 = np.array([pf2['X'][cooridx2[0], cooridx2[1]], pf2['Y'][cooridx2[0], cooridx2[1]]])


                # get single fields' statistics
                passdf1 = field_df.loc[field_ids[0], 'passes']
                passdf2 = field_df.loc[field_ids[1], 'passes']

                (x1list, y1list, t1list, angle1list), tsp1list = append_info_from_passes(passdf1, vthresh, sthresh,
                                                                                         trange)
                (x2list, y2list, t2list, angle2list), tsp2list = append_info_from_passes(passdf2, vthresh, sthresh,
                                                                                         trange)


                if (len(t1list) < 1) or (len(t2list) < 1) or (len(tsp1list) < 1) or (len(tsp2list) < 1):
                    continue

                x1, x2 = np.concatenate(x1list), np.concatenate(x2list)
                y1, y2 = np.concatenate(y1list), np.concatenate(y2list)
                hd1, hd2 = np.concatenate(angle1list), np.concatenate(angle2list)
                pos1, pos2 = np.stack([x1, y1]).T, np.stack([x2, y2]).T

                tsp1, tsp2 = np.concatenate(tsp1list), np.concatenate(tsp2list)
                xsp1, xsp2 = interpolater_x(tsp1), interpolater_x(tsp2)
                ysp1, ysp2 = interpolater_y(tsp1), interpolater_y(tsp2)
                possp1, possp2 = np.stack([xsp1, ysp1]).T, np.stack([xsp2, ysp2]).T
                hdsp1, hdsp2 = interpolater_angle(tsp1), interpolater_angle(tsp2)
                nspks1, nspks2 = tsp1.shape[0], tsp2.shape[0]


                # Directionality
                biner1 = DirectionerBining(aedges, hd1)
                fangle1, fR1, (spbins1, occbins1, normprob1) = biner1.get_directionality(hdsp1)
                mlmer1 = DirectionerMLM(pos1, hd1, dt=dt, sp_binwidth=sp_binwidth, a_binwidth=abind)
                fangle1_mlm, fR1_mlm, normprob1_mlm = mlmer1.get_directionality(possp1, hdsp1)
                normprob1_mlm[np.isnan(normprob1_mlm)] = 0
                biner2 = DirectionerBining(aedges, hd2)
                fangle2, fR2, (spbins2, occbins2, normprob2) = biner2.get_directionality(hdsp2)
                mlmer2 = DirectionerMLM(pos2, hd2, dt=dt, sp_binwidth=sp_binwidth, a_binwidth=abind)
                fangle2_mlm, fR2_mlm, normprob2_mlm = mlmer2.get_directionality(possp2, hdsp2)
                normprob2_mlm[np.isnan(normprob2_mlm)] = 0

                # Pass-based phaselag, extrinsic/intrinsic
                phase_finder = ThetaEstimator(0.005, 0.3, [5, 12])
                AB_tsp1_list, BA_tsp1_list = [], []
                AB_tsp2_list, BA_tsp2_list = [], []
                nspikes_AB_list, nspikes_BA_list = [], []
                duration_AB_list, duration_BA_list = [], []
                t_all = []
                passangles_all, x_all, y_all = [], [], []
                paired_tsp_list = []

                # Precession per pair
                neuro_keys_dict1 = dict(tsp='tsp1', spikev='spike1v', spikex='spike1x', spikey='spike1y',
                                        spikeangle='spike1angle')
                neuro_keys_dict2 = dict(tsp='tsp2', spikev='spike2v', spikex='spike2x', spikey='spike2y',
                                        spikeangle='spike2angle')

                pass_dict_keys = precesser._gen_precess_infokeys()
                pass_dict1 = precesser.gen_precess_dict(tag='1')
                pass_dict2 = precesser.gen_precess_dict(tag='2')
                pass_dictp = {**pass_dict1, **pass_dict2, **{'direction':[]}}


                pairedpasses = pair_df.loc[npair, 'pairedpasses']
                num_passes = pairedpasses.shape[0]



                for npass in range(num_passes):

                    # Get spikes
                    tsp1, tsp2, vsp1, vsp2 = pairedpasses.loc[npass, ['tsp1', 'tsp2', 'spike1v', 'spike2v']]
                    x, y, pass_angles, v = pairedpasses.loc[npass, ['x', 'y', 'angle', 'v']]

                    # Straightness
                    straightrank = compute_straightness(pass_angles)
                    if straightrank < sthresh:
                        continue

                    # Find direction
                    infield1, infield2, t = pairedpasses.loc[npass, ['infield1', 'infield2', 't']]
                    loc, direction = ThetaEstimator.find_direction(infield1, infield2)
                    duration = t.max() - t.min()

                    # Speed threshold
                    passmask = v > vthresh
                    spmask1, spmask2 = vsp1 > vthresh, vsp2 > vthresh
                    xinv, yinv, pass_angles_inv, tinv = x[passmask], y[passmask], pass_angles[passmask], t[passmask]
                    tsp1_inv, tsp2_inv = tsp1[spmask1], tsp2[spmask2]

                    # Find paired spikes
                    pairidx1, pairidx2 = find_pair_times(tsp1_inv, tsp2_inv)
                    paired_tsp1, paired_tsp2 = tsp1_inv[pairidx1], tsp2_inv[pairidx2]
                    if (paired_tsp1.shape[0] < 1) and (paired_tsp2.shape[0] < 1):
                        continue
                    paired_tsp_eachpass = np.concatenate([paired_tsp1, paired_tsp2])
                    paired_tsp_list.append(paired_tsp_eachpass)

                    # Get pass info
                    passangles_all.append(pass_angles_inv)
                    x_all.append(xinv)
                    y_all.append(yinv)
                    t_all.append(tinv)

                    if direction == 'A->B':
                        AB_tsp1_list.append(tsp1_inv)
                        AB_tsp2_list.append(tsp2_inv)
                        nspikes_AB_list.append(tsp1_inv.shape[0] + tsp2_inv.shape[0])
                        duration_AB_list.append(duration)

                    elif direction == 'B->A':
                        BA_tsp1_list.append(tsp1_inv)
                        BA_tsp2_list.append(tsp2_inv)
                        nspikes_BA_list.append(tsp1_inv.shape[0] + tsp2_inv.shape[0])
                        duration_BA_list.append(duration)

                    if (direction == 'A->B') or (direction == 'B->A'):
                        precess1 = precesser._get_precession(pairedpasses, npass, neuro_keys_dict1)
                        precess2 = precesser._get_precession(pairedpasses, npass, neuro_keys_dict2)
                        if (precess1 is None) or (precess2 is None):
                            continue
                        else:
                            pass_dictp = precesser.append_pass_dict(pass_dictp, precess1, tag='1')
                            pass_dictp = precesser.append_pass_dict(pass_dictp, precess2, tag='2')
                            pass_dictp['direction'].append(direction)



                    ############## Plot paired spikes examples ##############
                    if (ntrial==26) and (ca=='CA3') and (npair==1) and (npass==10):

                        if (tsp1_inv.shape[0] != 0) or (tsp2_inv.shape[0] != 0):
                            mintsp_plt = np.min(np.concatenate([tsp1_inv, tsp2_inv]))
                            tsp1_inv = tsp1_inv - mintsp_plt
                            tsp2_inv = tsp2_inv - mintsp_plt
                            tmp_idx1, tmp_idx2 = find_pair_times(tsp1_inv, tsp2_inv)
                            pairedsp1, pairedsp2 = tsp1_inv[tmp_idx1], tsp2_inv[tmp_idx2]

                            fig_pairsp, ax_pairsp = plt.subplots(figsize=(figw_pairedsp, figh_pairedsp))
                            ax_pairsp.eventplot(tsp1_inv, color='k', lineoffsets=0, linelengths=1, linewidths=0.75)
                            ax_pairsp.eventplot(tsp2_inv, color='k', lineoffsets=1, linelengths=1, linewidths=0.75)
                            ax_pairsp.eventplot(pairedsp1, color='darkorange', lineoffsets=0, linelengths=1, linewidths=0.75)
                            ax_pairsp.eventplot(pairedsp2, color='darkorange', lineoffsets=1, linelengths=1, linewidths=0.75)
                            ax_pairsp.set_yticks([0, 1])
                            ax_pairsp.set_yticklabels(['Field A', 'Field B'])
                            ax_pairsp.set_ylim(-0.7, 1.7)
                            ax_pairsp.tick_params(labelsize=ticksize)
                            ax_pairsp.set_xlabel('t (s)', fontsize=fontsize)
                            ax_pairsp.xaxis.set_label_coords(1, -0.075)
                            ax_pairsp.spines['left'].set_visible(False)
                            ax_pairsp.spines['right'].set_visible(False)
                            ax_pairsp.spines['top'].set_visible(False)

                            fig_pairsp.tight_layout()
                            fig_pairsp.savefig(os.path.join(plot_dir, 'example_pairedspikes.%s' % (figext)), dpi=dpi)
                            # fig_pairsp.savefig(os.path.join(plot_dir, 'examples_pairspikes', 'trial-%d_%s_pair-%d_pass-%d.%s' % (ntrial, ca, npair, npass, figext)), dpi=dpi)


                # Paired spikes
                if (len(paired_tsp_list) == 0) or (len(passangles_all) == 0):
                    continue
                hd_pair = np.concatenate(passangles_all)
                x_pair, y_pair = np.concatenate(x_all), np.concatenate(y_all)
                pos_pair = np.stack([x_pair, y_pair]).T

                paired_tsp = np.concatenate(paired_tsp_list)
                paired_tsp = paired_tsp[(paired_tsp <= all_maxt) & (paired_tsp >= all_mint)]
                if paired_tsp.shape[0] < 1:
                    continue
                num_spikes_pair = paired_tsp.shape[0]

                hdsp_pair = interpolater_angle(paired_tsp)
                xsp_pair = interpolater_x(paired_tsp)
                ysp_pair = interpolater_y(paired_tsp)
                possp_pair = np.stack([xsp_pair, ysp_pair]).T

                # Pair Directionality
                biner_pair = DirectionerBining(aedges, hd_pair)
                fanglep, fRp, (spbinsp, occbinsp, normprobp) = biner_pair.get_directionality(hdsp_pair)
                mlmer_pair = DirectionerMLM(pos_pair, hd_pair, dt, sp_binwidth, abind)
                fanglep_mlm, fRp_mlm, normprobp_mlm = mlmer_pair.get_directionality(possp_pair, hdsp_pair)
                normprobp_mlm[np.isnan(normprobp_mlm)] = 0

                # KLD
                kld_mlm = calc_kld(normprob1_mlm, normprob2_mlm, normprobp_mlm)

                ############## Plot pair examples ##############
                if case == 'eg':
                    ax_paireg[case_axid].plot(tunner.x, tunner.y, c='0.8', linewidth=0.75)
                    ax_paireg[case_axid].plot(xyval1[:, 0], xyval1[:, 1], c='k', linewidth=1)
                    ax_paireg[case_axid].plot(xyval2[:, 0], xyval2[:, 1], c='k', linewidth=1)

                    ax_paireg[case_axid].axis('off')
                    xp, yp = circular_density_1d(aedm, 20 * np.pi, 60, (-np.pi, np.pi), w=normprobp_mlm)
                    ax_paireg[case_axid+1] = directionality_polar_plot(ax_paireg[case_axid+1], xp, yp, fanglep_mlm, linewidth=0.75)

                    ax_paireg[case_axid].text(0.6, -0.05, '%0.2f' % (ks_dist), fontsize=legendsize, c='k', transform=ax_paireg[case_axid].transAxes)
                    ax_paireg[case_axid+1].text(0.6, -0.05, '%0.2f' % (fRp_mlm), fontsize=legendsize, c='k', transform=ax_paireg[case_axid+1].transAxes)

                ############## Plot KLD examples ##############
                if case == 'kld':
                    x1, y1 = circular_density_1d(aedm, 20 * np.pi, 60, (-np.pi, np.pi), w=normprob1_mlm)
                    x2, y2 = circular_density_1d(aedm, 20 * np.pi, 60, (-np.pi, np.pi), w=normprob2_mlm)
                    xp, yp = circular_density_1d(aedm, 20 * np.pi, 60, (-np.pi, np.pi), w=normprobp_mlm)

                    indep_prob = normprob1_mlm * normprob2_mlm
                    indep_prob = indep_prob / np.sum(indep_prob)
                    indep_angle = circmean(aedm, w=indep_prob, d=abind)
                    xindep, yindep = circular_density_1d(aedm, 20 * np.pi, 60, (-np.pi, np.pi), w=indep_prob)

                    kld_linewidth = 0.75
                    ax_kld[case_axid, 0] = directionality_polar_plot(ax_kld[case_axid, 0], x1, y1, fangle1_mlm, linewidth=kld_linewidth)
                    ax_kld[case_axid, 1] = directionality_polar_plot(ax_kld[case_axid, 1], x2, y2, fangle2_mlm, linewidth=kld_linewidth)
                    ax_kld[case_axid, 2] = directionality_polar_plot(ax_kld[case_axid, 2], xindep, yindep, indep_angle, linewidth=kld_linewidth)
                    ax_kld[case_axid, 3] = directionality_polar_plot(ax_kld[case_axid, 3], xp, yp, fanglep_mlm, linewidth=kld_linewidth)


                    kldtext_x, kldtext_y = 0, -0.2
                    ax_kld[case_axid, 3].text(kldtext_x, kldtext_y, 'KLD=%0.2f' % (kld_mlm), fontsize=legendsize, transform=ax_kld[case_axid, 3].transAxes)
Ejemplo n.º 2
0
def plot_prefer_nonprefer(ax, prefer_pdf, nonprefer_pdf):
    '''

    Parameters
    ----------
    ax: ndarray
        Numpy array of axes objects with shape (6, ).
        ax[0] - Fraction of negative slope
        ax[1] - Prefer's precession
        ax[2] - Nonprefer's precession
        ax[3] - Difference in onsets for Prefer and Nonprefer
        ax[4] - Difference in slopes for Prefer and Nonprefer
        ax[5] - Difference in phases for Prefer and Nonprefer

    prefer_pdf: dataframe
        Pandas dataframe containing prefered passes (including non-precessing)
    nonprefer_pdf: dataframe
        Pandas dataframe containing nonprefered passes (including non-precessing)

    Returns
    -------
    '''
    pre_c = dict(prefer='r', nonprefer='b')
    prefer_allslope = prefer_pdf['slope'].to_numpy()
    nonprefer_allslope = nonprefer_pdf['slope'].to_numpy()
    prefer_slope = prefer_pdf[
        prefer_pdf['precess_exist']]['slope'].to_numpy() * np.pi
    nonprefer_slope = nonprefer_pdf[
        nonprefer_pdf['precess_exist']]['slope'].to_numpy() * np.pi
    prefer_onset = prefer_pdf[prefer_pdf['precess_exist']]['onset'].to_numpy()
    nonprefer_onset = nonprefer_pdf[
        nonprefer_pdf['precess_exist']]['onset'].to_numpy()
    prefer_dsp = np.concatenate(
        prefer_pdf[prefer_pdf['precess_exist']]['dsp'].to_list())
    nonprefer_dsp = np.concatenate(
        nonprefer_pdf[nonprefer_pdf['precess_exist']]['dsp'].to_list())
    prefer_phasesp = np.concatenate(
        prefer_pdf[prefer_pdf['precess_exist']]['phasesp'].to_list())
    nonprefer_phasesp = np.concatenate(
        nonprefer_pdf[nonprefer_pdf['precess_exist']]['phasesp'].to_list())

    # Precession fraction
    prefer_neg_n, prefer_pos_n = (prefer_allslope < 0).sum(), (prefer_allslope
                                                               > 0).sum()
    nonprefer_neg_n, nonprefer_pos_n = (nonprefer_allslope < 0).sum(), (
        nonprefer_allslope > 0).sum()
    table_arr = np.array([[prefer_neg_n, prefer_pos_n],
                          [nonprefer_neg_n, nonprefer_pos_n]])
    table_df = pd.DataFrame(table_arr,
                            columns=['-ve', '+ve'],
                            index=['Prefer', 'Nonprefer'])
    p_frac = fisherexact(table_arr)
    prefer_frac = prefer_neg_n / (prefer_pos_n + prefer_neg_n)
    nonprefer_frac = nonprefer_neg_n / (nonprefer_pos_n + nonprefer_neg_n)
    bar_w, bar_x, bar_y = 0.5, np.array([0, 1]), np.array(
        [prefer_frac, nonprefer_frac])
    ax[0].bar(bar_x, bar_y, width=bar_w)
    ax[0].errorbar(x=bar_x.mean(), y=0.8, xerr=1, c='k', capsize=2.5)
    ax[0].text(x=0, y=0.85, s='p%s' % (p2str(p_frac)), fontsize=legendsize)
    ax[0].set_xticks([0, 1])
    ax[0].set_xticklabels(['Prefer', 'Nonprefer'])
    ax[0].tick_params(labelsize=fontsize)

    # Prefer precession
    xdum = np.linspace(0, 1, 10)
    mean_phasesp = circmean(prefer_phasesp)
    regress = rcc(prefer_dsp, prefer_phasesp)
    ydum = regress['phi0'] + xdum * 2 * np.pi * regress['aopt']
    ax[1].scatter(prefer_dsp, prefer_phasesp, marker='.', c='gray', s=1)
    ax[1].scatter(prefer_dsp,
                  prefer_phasesp + 2 * np.pi,
                  marker='.',
                  c='gray',
                  s=1)
    ax[1].plot(xdum, ydum, c='k')
    ax[1].plot(xdum, ydum + 2 * np.pi, c='k')
    ax[1].plot(xdum, ydum + 2 * np.pi, c='k')
    ax[1].axhline(mean_phasesp, xmin=0, xmax=0.1, color='r')
    ax[1].set_ylim(-np.pi, 3 * np.pi)
    ax[1].set_xlim(0, 1)

    # Non-Prefer precession
    xdum = np.linspace(0, 1, 10)
    mean_phasesp = circmean(nonprefer_phasesp)
    regress = rcc(nonprefer_dsp, nonprefer_phasesp)
    ydum = regress['phi0'] + xdum * 2 * np.pi * regress['aopt']
    ax[2].scatter(nonprefer_dsp, nonprefer_phasesp, marker='.', c='gray', s=1)
    ax[2].scatter(nonprefer_dsp,
                  nonprefer_phasesp + 2 * np.pi,
                  marker='.',
                  c='gray',
                  s=1)
    ax[2].plot(xdum, ydum, c='k')
    ax[2].plot(xdum, ydum + 2 * np.pi, c='k')
    ax[2].plot(xdum, ydum + 2 * np.pi, c='k')
    ax[2].axhline(mean_phasesp, xmin=0, xmax=0.1, color='r')
    ax[2].set_ylim(-np.pi, 3 * np.pi)
    ax[2].set_xlim(0, 1)

    # Onset vs Slope
    p_onset, _ = watson_williams(prefer_onset, nonprefer_onset)
    _, p_slope = ranksums(prefer_slope, nonprefer_slope)
    ax[3].scatter(prefer_slope,
                  prefer_onset,
                  marker='o',
                  c=pre_c['prefer'],
                  label='prefer')
    ax[3].scatter(nonprefer_slope,
                  nonprefer_onset,
                  marker='x',
                  c=pre_c['nonprefer'],
                  label='nonprefer')
    ax[3].set_xlabel('Precession slope (rad)')
    ax[3].set_ylabel('Precession onset (rad)')
    customlegend(ax[3], fontsize=legendsize)

    # # Onset
    # p_onset, _ = watson_williams(prefer_onset, nonprefer_onset)
    # onset_bins = np.linspace(0, 2*np.pi, 20)
    # prefer_onsetbins, _ = np.histogram(prefer_onset, bins=onset_bins)
    # nonprefer_onsetbins, _ = np.histogram(nonprefer_onset, bins=onset_bins)
    # ax[3].step(onset_bins[:-1], prefer_onsetbins/prefer_onsetbins.sum(), where='pre', c=pre_c['prefer'], label='prefer')
    # ax[3].step(onset_bins[:-1], nonprefer_onsetbins/nonprefer_onsetbins.sum(), where='pre', c=pre_c['nonprefer'], label='nonprefer')
    # ax[3].annotate('Watson-William\np%s'%(p2str(p_onset)), xy=(0.6, 0.6), xycoords='axes fraction')
    # ax[3].set_xlabel('Precession onset (rad)')
    # customlegend(ax[3], fontsize=legendsize)
    #
    # # Slope
    # _, p_slope = ranksums(prefer_slope, nonprefer_slope)
    # slope_bins = np.linspace(-2*np.pi, 0, 20)
    # prefer_slopebins, _ = np.histogram(prefer_slope, bins=slope_bins)
    # nonprefer_slopebins, _ = np.histogram(nonprefer_slope, bins=slope_bins)
    # ax[4].step(slope_bins[:-1], prefer_slopebins/prefer_slopebins.sum(), where='pre', c=pre_c['prefer'], label='prefer')
    # ax[4].step(slope_bins[:-1], nonprefer_slopebins/nonprefer_slopebins.sum(), where='pre', c=pre_c['nonprefer'], label='nonprefer')
    # ax[4].annotate('Ranksums\np%s'%(p2str(p_slope)), xy=(0.6, 0.6), xycoords='axes fraction')
    # ax[4].set_xlabel('Precession slope (rad)')
    # customlegend(ax[4], fontsize=legendsize)

    # Spike phase
    prefer_phasesp_mean, nonprefer_phasesp_mean = circmean(
        prefer_phasesp), circmean(nonprefer_phasesp)
    p_phasesp, _ = watson_williams(prefer_phasesp, nonprefer_phasesp)
    phasesp_bins = np.linspace(-np.pi, np.pi, 20)
    prefer_phasespbins, _ = np.histogram(prefer_phasesp, bins=phasesp_bins)
    nonprefer_phasespbins, _ = np.histogram(nonprefer_phasesp,
                                            bins=phasesp_bins)
    norm_preferphasebins = prefer_phasespbins / prefer_phasespbins.sum()
    norm_nonpreferphasebins = nonprefer_phasespbins / nonprefer_phasespbins.sum(
    )
    maxl = max(norm_preferphasebins.max(), norm_nonpreferphasebins.max())
    ax[4].step(midedges(phasesp_bins),
               norm_preferphasebins,
               color='r',
               label='prefer')
    ax[4].step(midedges(phasesp_bins),
               norm_nonpreferphasebins,
               color='b',
               label='nonprefer')
    ax[4].scatter(prefer_phasesp_mean, maxl * 1.1, color='r', marker='|', s=64)
    ax[4].scatter(nonprefer_phasesp_mean,
                  maxl * 1.1,
                  color='b',
                  marker='|',
                  s=64)
    ax[4].annotate('Watson-William\np%s' % (p2str(p_phasesp)),
                   xy=(0.6, 0.2),
                   xycoords='axes fraction')
    ax[4].set_xlabel('Precession spike phase')
    customlegend(ax[4], fontsize=legendsize)

    return ax
def plot_placefield_examples(rawdf, save_dir=None):

    example_dir = join(save_dir, 'example_fields2')
    os.makedirs(example_dir)

    field_figl = total_figw / 8
    field_linew = 0.75
    field_ms = 1
    warnings.filterwarnings("ignore")

    # Parameters
    vthresh = 5
    sthresh = 3
    num_trials = rawdf.shape[0]
    aedges = np.linspace(-np.pi, np.pi, 36)
    aedm = midedges(aedges)
    abind = aedges[1] - aedges[0]
    sp_binwidth = 5
    precess_filter = PrecessionFilter()

    # Plot color wheel
    fig_ch, ax_ch = color_wheel('hsv', (field_figl, field_figl))
    fig_ch.savefig(os.path.join(save_dir, 'colorwheel.%s' % (figext)),
                   transparent=True,
                   dpi=dpi)

    # Selected Examples
    example_list = [
        'CA1-field16',
        'CA2-field11',
        'CA3-field378',  # Precession
        'CA1-field151',
        'CA1-field222',
        'CA1-field389',
        'CA1-field400',
        'CA1-field409',
        'CA2-field28',
        'CA2-field47',
        'CA3-field75'
    ]
    fieldid = dict(CA1=0, CA2=0, CA3=0)
    fieldid_skip = dict(CA1=0, CA2=0, CA3=0)

    for ntrial in range(num_trials):

        wave = rawdf.loc[ntrial, 'wave']
        precesser = PrecessionProcesser(wave=wave)
        for ca in ['CA%d' % i for i in range(1, 4)]:

            # Get data
            field_df = rawdf.loc[ntrial, ca + 'fields']
            indata = rawdf.loc[ntrial, ca + 'indata']
            if indata.shape[0] < 1:
                continue
            trajx, trajy = indata['x'].to_numpy(), indata['y'].to_numpy()
            num_fields = field_df.shape[0]
            tunner = IndataProcessor(indata,
                                     vthresh=5,
                                     sthresh=3,
                                     minpasstime=0.4,
                                     smooth=None)
            interpolater_angle = interp1d(tunner.t, tunner.angle)
            interpolater_x = interp1d(tunner.t, tunner.x)
            interpolater_y = interp1d(tunner.t, tunner.y)
            all_maxt, all_mint = tunner.t.max(), tunner.t.min()
            trange = (all_maxt, all_mint)
            dt = tunner.t[1] - tunner.t[0]
            precesser.set_trange(trange)
            for nfield in range(num_fields):
                if ('%s-field%d' % (ca, fieldid[ca])) not in example_list:
                    fieldid[ca] += 1
                    continue
                print('Plotting fields: Trial %d/%d %s field %d/%d' %
                      (ntrial, num_trials, ca, nfield, num_fields))

                # Get field spikes
                xytsp, xyval = field_df.loc[nfield, ['xytsp', 'xyval']]
                tsp, xsp, ysp = xytsp['tsp'], xytsp['xsp'], xytsp['ysp']
                pf = field_df.loc[nfield, 'pf']

                # Get spike angles
                insession = np.where((tsp < all_maxt) & (tsp > all_mint))[0]
                tspins, xspins, yspins = tsp[insession], xsp[insession], ysp[
                    insession]
                anglespins = interpolater_angle(tspins)

                # Directionality
                passdf = field_df.loc[nfield, 'passes']
                (xl, yl, tl,
                 hdl), tspl = append_info_from_passes(passdf, vthresh, sthresh,
                                                      trange)
                if (len(tspl) < 1) or (len(tl) < 1):
                    # fieldid[ca] += 1
                    fieldid_skip[ca] += 1
                    continue

                x = np.concatenate(xl)
                y = np.concatenate(yl)
                pos = np.stack([x, y]).T
                hd = np.concatenate(hdl)
                tsp = np.concatenate(tspl)
                xsp, ysp = interpolater_x(tsp), interpolater_y(tsp)
                possp = np.stack([xsp, ysp]).T
                hdsp = interpolater_angle(tsp)

                # Directionality
                biner = DirectionerBining(aedges, hd)
                fieldangle, fieldR, (spike_bins, occ_bins,
                                     _) = biner.get_directionality(hdsp)
                mlmer = DirectionerMLM(pos, hd, dt, sp_binwidth, abind)
                fieldangle, fieldR, norm_prob = mlmer.get_directionality(
                    possp, hdsp)
                norm_prob[np.isnan(norm_prob)] = 0

                # # (Plot) Place field Example
                fig2 = plt.figure(figsize=(field_figl * 2, field_figl))
                peak_rate = pf['map'].max()
                ax_field2 = fig2.add_subplot(1, 2, 1)
                ax_field2.plot(trajx, trajy, c='0.8', linewidth=0.25)
                ax_field2.plot(xyval[:, 0],
                               xyval[:, 1],
                               c='k',
                               zorder=3,
                               linewidth=field_linew)
                ax_field2.scatter(xspins,
                                  yspins,
                                  c=anglespins,
                                  marker='.',
                                  cmap='hsv',
                                  s=field_ms,
                                  zorder=2.5)
                ax_field2.axis('off')

                x_new, y_new = circular_density_1d(aedm,
                                                   30 * np.pi,
                                                   100, (-np.pi, np.pi),
                                                   w=norm_prob)
                l = y_new.max()
                ax_polar = fig2.add_axes([0.33, 0.3, 0.6, 0.6], polar=True)
                ax_polar.plot(x_new,
                              y_new,
                              c='0.3',
                              linewidth=field_linew,
                              zorder=2.1)
                ax_polar.plot([x_new[-1], x_new[0]], [y_new[-1], y_new[0]],
                              c='0.3',
                              linewidth=field_linew,
                              zorder=2.1)
                # ax_polar.plot([fieldangle, fieldangle], [0, l], c='k', linewidth=field_linew)
                ax_polar.annotate("",
                                  xy=(fieldangle, l),
                                  xytext=(0, 0),
                                  color='k',
                                  zorder=3,
                                  arrowprops=dict(arrowstyle="->"))
                ax_polar.annotate(r'$\theta_{rate}$',
                                  xy=(fieldangle, l),
                                  fontsize=legendsize)
                ax_polar.spines['polar'].set_visible(False)
                ax_polar.set_xticks([0, np.pi / 2, np.pi, 3 * np.pi / 2])
                ax_polar.set_yticks([])
                ax_polar.set_yticklabels([])
                ax_polar.set_xticklabels([])

                basey = -0.3
                ax_polar.annotate('%0.2f' % (peak_rate),
                                  xy=(0.75, 0.05),
                                  color='k',
                                  zorder=3,
                                  fontsize=legendsize,
                                  xycoords='figure fraction')
                ax_polar.annotate('%0.2f' % (fieldR),
                                  xy=(0.75, 0.175),
                                  color='k',
                                  zorder=3,
                                  fontsize=legendsize,
                                  xycoords='figure fraction')
                # ax_polar.text(0.5, basey, '%0.2f' % (peak_rate), fontsize=legendsize, transform=ax_polar.transAxes)
                # ax_polar.text(0.5, basey + 0.25, '%0.2f' % (fieldR), fontsize=legendsize, transform=ax_polar.transAxes)

                fig2.tight_layout()
                fig2.savefig(os.path.join(example_dir, '%s-field%d.png' %
                                          (ca, fieldid[ca])),
                             dpi=dpi)
                fig2.savefig(os.path.join(example_dir, '%s-field%d.eps' %
                                          (ca, fieldid[ca])),
                             dpi=dpi)
                plt.close()

                fieldid[ca] += 1
Ejemplo n.º 4
0
    def plot_both_slope_offset(self):

        density_figsize = (figl+0.5, figl*2)
        slice_figsize = (figl+0.5, figl*2)

        selected_adiff = np.linspace(0, np.pi, 6)  # 20
        adiff_ticks = [0, np.pi / 2, np.pi]
        adiff_ticksl = ['0', '$\pi$', '$2\pi$']
        adiff_label = r'$|d(\theta_{pass}, \theta_{precess})|$'

        offset_label = 'Onset phase (rad)'
        offset_slicerange = (0, 2*np.pi)
        offset_bound = (0, 2 * np.pi)
        offset_xticks = [0, np.pi, 2*np.pi]
        offset_xticksl = ['0', '$\pi$', '$2\pi$']
        offset_slicegap = 0.017  # 0.007

        slope_label = 'Slope ' + '$(rad)$'
        slope_slicerange = (-2 * np.pi, 0)
        slope_bound = (-2 * np.pi, 0)
        slope_xticks = [-2 * np.pi, -np.pi, 0]
        slope_xticksl = ['$-2\pi$', '$-\pi$', '0']
        slope_slicegap = 0.01  # 0.007

        adiff_edges = np.linspace(0, np.pi, 500)
        offset_edges = np.linspace(offset_bound[0], offset_bound[1], 500)
        slope_edges = np.linspace(slope_bound[0], slope_bound[1], 500)

        fig_density, ax_density = plt.subplots(2, 1, figsize=density_figsize, sharex='col', sharey='row')
        fig_slices, ax_slices = plt.subplots(2, 1, figsize=slice_figsize, sharex='row', sharey='row')

        anglediff, pass_nspikes = self.stack_anglediff(self.singlefield_df, precess_ref=True)
        anglediff = np.abs(anglediff)
        slope = self.stack_key(self.singlefield_df, 'rcc_m')
        slope = slope * 2 * np.pi
        offset = self.stack_key(self.singlefield_df, 'rcc_c')

        # Expand sample according to spikes
        anglediff_spikes = repeat_arr(anglediff, pass_nspikes)

        # 1D spike hisotgram
        spikes_bins, spikes_edges = np.histogram(anglediff_spikes, bins=adiff_edges)

        # 2D slope/offset histogram
        offset_bins, offset_xedges, offset_yedges = np.histogram2d(anglediff, offset,
                                                                   bins=(adiff_edges, offset_edges))
        slope_bins, slope_xedges, slope_yedges = np.histogram2d(anglediff, slope,
                                                                bins=(adiff_edges, slope_edges))

        offset_normbins = self.norm_div(offset_bins, spikes_bins)
        slope_normbins = self.norm_div(slope_bins, spikes_bins)

        # Unbinning
        offset_xedm, offset_yedm = midedges(offset_xedges), midedges(offset_yedges)
        slope_xedm, slope_yedm = midedges(slope_xedges), midedges(slope_yedges)
        offset_adiff, offset_norm = unfold_binning_2d(offset_normbins, offset_xedm, offset_yedm)
        slope_adiff, slope_norm = unfold_binning_2d(slope_normbins, slope_xedm, slope_yedm)

        # Linear-circular regression
        regress = rcc(offset_adiff, offset_norm)
        offset_m, offset_c, offset_rho, offset_p = regress['aopt'], regress['phi0'], regress['rho'], regress['p']
        regress = rcc(slope_adiff, slope_norm)
        slope_m, slope_c, slope_rho, slope_p = regress['aopt'], regress['phi0'], regress['rho'], regress['p']
        slope_c = slope_c - 2 * np.pi

        # Density

        offset_xx, offset_yy, offset_zz = linear_circular_gauss_density(offset_adiff, offset_norm,
                                                                        cir_kappa=4 * np.pi, lin_std=0.2, xbins=50,
                                                                        ybins=50, xbound=(0, np.pi),
                                                                        ybound=offset_bound)
        slope_xx, slope_yy, slope_zz = linear_circular_gauss_density(slope_adiff, slope_norm,
                                                                     cir_kappa=4 * np.pi, lin_std=0.2, xbins=50,
                                                                     ybins=50, xbound=(0, np.pi),
                                                                     ybound=slope_bound)
        # ax_density[0].pcolormesh(offset_xx, offset_yy, offset_zz)

        # Plot offset density
        cmap = 'Blues'
        ax_density[0].hist2d(offset_adiff, offset_norm,
                             bins=(np.linspace(0, np.pi, 36), np.linspace(0, 2 * np.pi, 36)), density=True,
                             cmap=cmap)
        regressed = (offset_c + offset_xedm * offset_m)
        ax_density[0].plot(offset_xedm, regressed, c='k')
        ax_density[0].text(np.pi/3, regressed.max() + 0.5, 'p%s'%p2str(offset_p), fontsize=legendsize)
        ax_density[0].set_xticks(adiff_ticks)
        ax_density[0].set_xticklabels(adiff_ticksl)
        ax_density[0].set_yticks(offset_xticks)
        ax_density[0].set_yticklabels(offset_xticksl)
        ax_density[0].tick_params(labelsize=ticksize, direction='inout')
        ax_density[0].set_ylabel(offset_label, fontsize=fontsize)

        # Plot slope density
        ax_density[1].hist2d(slope_adiff, slope_norm,
                             bins=(np.linspace(0, np.pi, 36), np.linspace(-2 * np.pi, 0, 36)), density=True,
                             cmap=cmap)
        regressed = (slope_c + slope_xedm * slope_m)
        # ax_density[1].pcolormesh(slope_xx, slope_yy, slope_zz)
        ax_density[1].plot(slope_xedm, regressed, c='k')
        ax_density[1].text(np.pi/3, regressed.max() + 0.5, 'p%s'%p2str(slope_p), fontsize=legendsize)
        ax_density[1].set_xticks(adiff_ticks)
        ax_density[1].set_xticklabels(adiff_ticksl)
        ax_density[1].set_yticks(slope_xticks)
        ax_density[1].set_yticklabels(slope_xticksl)
        ax_density[1].tick_params(labelsize=ticksize, direction='inout')
        ax_density[1].set_xlabel(adiff_label, fontsize=fontsize)
        ax_density[1].set_ylabel(slope_label, fontsize=fontsize)

        ax_slices[0], _ = plot_marginal_slices(ax_slices[0], offset_xx, offset_yy, offset_zz,
                                               selected_adiff,
                                               offset_slicerange, offset_slicegap)
        ax_slices[0].set_xticks(offset_xticks)
        ax_slices[0].set_xticklabels(offset_xticksl)
        ax_slices[0].set_xlabel(offset_label, fontsize=fontsize)
        ax_slices[0].tick_params(labelsize=ticksize, direction='inout')

        ax_slices[1], _ = plot_marginal_slices(ax_slices[1], slope_xx, slope_yy, slope_zz,
                                               selected_adiff, slope_slicerange, slope_slicegap)

        ax_slices[1].set_xticks(slope_xticks)
        ax_slices[1].set_xticklabels(slope_xticksl)
        ax_slices[1].tick_params(labelsize=ticksize, direction='inout')
        ax_slices[1].set_xlabel(slope_label, fontsize=fontsize)


        # Colorbar
        sm = plt.cm.ScalarMappable(cmap=cm.brg,
                                   norm=plt.Normalize(vmin=selected_adiff.min(), vmax=selected_adiff.max()))
        fig_colorbar = plt.figure(figsize=slice_figsize)
        fig_colorbar.subplots_adjust(right=0.8)
        cbar_ax = fig_colorbar.add_axes([0.7, 0.15, 0.03, 0.7])
        cb = fig_colorbar.colorbar(sm, cax=cbar_ax)
        cb.set_ticks(adiff_ticks)
        cb.set_ticklabels(adiff_ticksl)
        cb.set_label(adiff_label, fontsize=fontsize, rotation=90)




        for ax in ax_slices.flatten():
            ax.axes.get_yaxis().set_visible(False)
            ax.spines["top"].set_visible(False)
            ax.spines["right"].set_visible(False)
            ax.spines["left"].set_visible(False)


        # Others
        fig_density.tight_layout()
        fig_density.savefig(join(self.plot_dir, 'Networks_density.png'), dpi=300)
        fig_slices.tight_layout()
        fig_slices.savefig(join(self.plot_dir, 'Networks_slices.png'), dpi=300)
        # fig_colorbar.tight_layout()
        fig_colorbar.savefig(join(self.plot_dir, 'Networks_adiff_colorbar.png'), dpi=300)
        return None
Ejemplo n.º 5
0
    def plot_field_bestprecession(self):

        fig_R, ax_R = plt.subplots(figsize=(figl, figl))

        fig_2Dscatter, ax_2Dscatter = plt.subplots(figsize=(figl, figl), sharey=True)

        fig_pishift = plt.figure(figsize=(figl*2, figl))
        ax_pishift = np.array(
            [fig_pishift.add_subplot(1, 2, i+1, polar=True) for i in range(2)]
        )

        fid = 0

        data = {'field': [], 'precess': [], 'precess_low':[], 'R':[], 'shufp':[]}

        # Re-organize & filter
        for i in range(self.singlefield_df.shape[0]):

            precess_info = self.singlefield_df.loc[i, 'precess_info']
            if precess_info is None:
                continue
            fieldangle_mlm, precess_angle = self.singlefield_df.loc[i, ['fieldangle_mlm', 'precess_angle']]
            precess_angle_low = self.singlefield_df.loc[i, 'precess_angle_low']
            data['field'].append(fieldangle_mlm)
            data['precess'].append(precess_angle)
            data['precess_low'].append(precess_angle_low)
            data['R'].append(precess_info['R'])
            data['shufp'].append(precess_info['pval'])


            fid += 1



        # Plot Scatter: field vs precess angles
        ax_2Dscatter.scatter(data['field'], data['precess'], alpha=0.2, s=8, c='gray')
        ax_2Dscatter.plot([0, np.pi], [np.pi, 2 * np.pi], c='k')
        ax_2Dscatter.plot([np.pi, 2 * np.pi], [0, np.pi], c='k')
        ax_2Dscatter.set_xlabel(r'$\theta_{rate}$', fontsize=fontsize)
        ax_2Dscatter.set_xticks([0, np.pi, 2 * np.pi])
        ax_2Dscatter.set_xticklabels(['$0$', '$\pi$', '$2\pi$'])
        ax_2Dscatter.set_yticks([0, np.pi, 2 * np.pi])
        ax_2Dscatter.set_yticklabels(['$0$', '$\pi$', '$2\pi$'])
        ax_2Dscatter.tick_params(labelsize=ticksize, direction='inout')
        ax_2Dscatter.set_ylabel(r'$\theta_{Precess}$', fontsize=fontsize)
        fig_2Dscatter.tight_layout()
        fig_2Dscatter.savefig(join(self.plot_dir, 'Networks_field_precess_2Dscatter.png'), dpi=300)


        # Plot Histogram: d(precess, rate)
        fieldangles = np.array(data['field'])
        precessangles = np.array(data['precess'])
        nanmask = (~np.isnan(fieldangles)) & (~np.isnan(precessangles))
        adiff = cdiff(precessangles[nanmask], fieldangles[nanmask])

        bins, edges = np.histogram(adiff, bins=np.linspace(-np.pi, np.pi, 36))
        bins_norm = bins / np.sum(bins)
        l = bins_norm.max()
        ax_pishift[0].bar(midedges(edges), bins_norm, width=edges[1] - edges[0],
                          alpha=0.5, color='gray')

        mean_angle = circmean(adiff)
        mean_angle = np.mod(mean_angle + np.pi, 2 * np.pi) - np.pi
        ax_pishift[0].plot([mean_angle, mean_angle], [0, l], c='k', linestyle='dashed')
        ax_pishift[0].plot([0, 0], [0, l], c='k')
        ax_pishift[0].scatter(0, 0, s=16, c='gray')
        ax_pishift[0].text(0.18, l * 0.4, r'$\theta_{rate}$', fontsize=fontsize+2)
        ax_pishift[0].spines['polar'].set_visible(False)
        ax_pishift[0].set_yticklabels([])
        ax_pishift[0].set_xticklabels([])
        ax_pishift[0].grid(False)
        ax_pishift[0].set_ylabel('All passes', fontsize=fontsize)
        # ax_pishift[0].yaxis.labelpad = 5

        v_pval, v_stat = vtest(adiff, mu=np.pi)
        ax_pishift[0].text(x=0.01, y=0.95, s='p%s'%(p2str(v_pval)), fontsize=legendsize,
                           transform=ax_pishift[0].transAxes)

        # Plot Histogram: d(precess_low, rate)
        fieldangles = np.array(data['field'])
        precessangles_low = np.array(data['precess_low'])
        nanmask = (~np.isnan(fieldangles)) & (~np.isnan(precessangles_low))
        adiff = cdiff(precessangles_low[nanmask], fieldangles[nanmask])
        bins, edges = np.histogram(adiff, bins=np.linspace(-np.pi, np.pi, 36))
        bins_norm = bins / np.sum(bins)
        l = bins_norm.max()
        ax_pishift[1].bar(midedges(edges), bins_norm, width=edges[1] - edges[0],
                          alpha=0.5, color='gray')
        mean_angle = circmean(adiff)
        mean_angle = np.mod(mean_angle + np.pi, 2 * np.pi) - np.pi
        ax_pishift[1].plot([mean_angle, mean_angle], [0, l], c='k', linestyle='dashed')
        ax_pishift[1].plot([0, 0], [0, l], c='k')
        ax_pishift[1].scatter(0, 0, s=16, c='gray')
        ax_pishift[1].text(0.18, l * 0.4, r'$\theta_{rate}$', fontsize=fontsize+2)

        ax_pishift[1].spines['polar'].set_visible(False)
        ax_pishift[1].set_yticklabels([])
        ax_pishift[1].set_xticklabels([])
        ax_pishift[1].grid(False)
        ax_pishift[1].set_ylabel('Low-spike passes', fontsize=fontsize)


        v_pval, v_stat = vtest(adiff, mu=np.pi)
        ax_pishift[1].text(x=0.01, y=0.95, s='p%s'%(p2str(v_pval)), fontsize=legendsize,
                           transform=ax_pishift[1].transAxes)
        fig_pishift.tight_layout()
        fig_pishift.savefig(join(self.plot_dir, 'Networks_field_precess_pishift.png'), dpi=300)




        # Plot R
        all_R = np.array(data['R'])
        rbins, redges = np.histogram(all_R, bins=50)
        rbinsnorm = np.cumsum(rbins) / rbins.sum()
        ax_R.plot(midedges(redges), rbinsnorm)

        ax_R.set_xlabel('R', fontsize=fontsize)
        ax_R.set_ylabel('Cumulative density', fontsize=fontsize)
        ax_R.tick_params(axis='both', which='major', labelsize=fontsize, direction='inout')
        ax_R.set_yticks([0, 0.5, 1])
        fig_R.tight_layout()
        fig_R.savefig(join(self.plot_dir, 'Networks_field_precess_R.png'), dpi=300)
Ejemplo n.º 6
0
    def plot_overall_bestprecession(self):
        print('Plot overall best precession')
        fig_basic, ax_basic = plt.subplots(figsize=(figl+0.1, figl), sharex=True, sharey=True)

        precess_adiff = []
        precess_nspikes = []
        nonprecess_adiff = []
        nonprecess_nspikes = []
        for i in range(self.singlefield_df.shape[0]):
            refangle = self.singlefield_df.loc[i, 'fieldangle_mlm']
            allprecess_df = self.singlefield_df.loc[i, 'precess_df']
            precess_df = allprecess_df[allprecess_df['precess_exist']]
            nonprecess_df = allprecess_df[~allprecess_df['precess_exist']]
            precess_counts = precess_df.shape[0]
            nonprecess_counts = nonprecess_df.shape[0]
            if precess_counts > 0:
                precess_adiff.append(cdiff(precess_df['spike_angle'].to_numpy(), refangle))
                precess_nspikes.append(precess_df['pass_nspikes'].to_numpy())
            if nonprecess_counts > 0:
                nonprecess_adiff.append(cdiff(nonprecess_df['spike_angle'].to_numpy(), refangle))
                nonprecess_nspikes.append(nonprecess_df['pass_nspikes'].to_numpy())


        # Density of Fraction, Spikes and Ratio
        precess_adiff = np.abs(np.concatenate(precess_adiff))
        nonprecess_adiff = np.concatenate(nonprecess_adiff)
        precess_nspikes = np.abs(np.concatenate(precess_nspikes))
        nonprecess_nspikes = np.concatenate(nonprecess_nspikes)
        adiff_spikes_p = repeat_arr(precess_adiff, precess_nspikes)
        adiff_spikes_np = repeat_arr(nonprecess_adiff, nonprecess_nspikes)


        adiff_bins = np.linspace(0, np.pi, 41)
        adm = midedges(adiff_bins)
        precess_bins, _ = np.histogram(precess_adiff, bins=adiff_bins)
        nonprecess_bins, _ = np.histogram(nonprecess_adiff, bins=adiff_bins)
        fraction_bins = precess_bins/(precess_bins + nonprecess_bins)
        spike_bins_p, _ = np.histogram(adiff_spikes_p, bins=adiff_bins)
        spike_bins_np, _ = np.histogram(adiff_spikes_np, bins=adiff_bins)
        spike_bins = spike_bins_p + spike_bins_np
        norm_bins = (fraction_bins / spike_bins)

        precess_allcount, nonprecess_allcount = precess_bins.sum(), nonprecess_bins.sum()

        rho, pval = spearmanr(adm, norm_bins)
        pm, pc, pr, ppval, _ = linregress(adm, norm_bins/ norm_bins.sum())
        xdum = np.linspace(adm.min(), adm.max(), 10)
        ax_basic.step(adm, fraction_bins / fraction_bins.sum(), color='darkblue', alpha=0.7, linewidth=1, label='Precession')
        ax_basic.step(adm, spike_bins / spike_bins.sum(), color='darkorange', alpha=0.7, linewidth=1, label='Spike')
        ax_basic.step(adm, norm_bins / norm_bins.sum(), color='darkgreen', alpha=0.7, linewidth=1, label='Ratio')

        customlegend(ax_basic, fontsize=legendsize-1)

        ax_basic.set_xticks([0, np.pi / 2, np.pi])
        ax_basic.set_xticklabels(['0', '$\pi/2$', '$\pi$'])
        # ax_basic.set_yticks([0, 0.04])
        ax_basic.tick_params(axis='both', which='major', labelsize=ticksize, direction='in')
        # ax_basic.set_ylim(0, 0.045)

        ax_basic.set_ylabel('Normalized counts', fontsize=fontsize)
        ax_basic.set_xlabel(self.angle_title, fontsize=fontsize)

        plt.tight_layout()
        plt.savefig(join(self.plot_dir, 'Networks_overall_bestprecession.png'), dpi=300)
Ejemplo n.º 7
0
def plot_both_slope_offset_Romani(simdf, ax):
    def norm_div(target_hist, divider_hist):
        target_hist_norm = target_hist / divider_hist.reshape(-1, 1)
        target_hist_norm[np.isnan(target_hist_norm)] = 0
        target_hist_norm[np.isinf(target_hist_norm)] = 0
        target_hist_norm = target_hist_norm / np.sum(
            target_hist_norm) * np.sum(target_hist)
        return target_hist_norm

    nap_thresh = 1
    selected_adiff = np.linspace(0, np.pi, 6)  # 20
    offset_bound = (0, 2 * np.pi)
    slope_bound = (-2 * np.pi, 0)
    adiff_edges = np.linspace(0, np.pi, 100)
    offset_edges = np.linspace(offset_bound[0], offset_bound[1], 100)
    slope_edges = np.linspace(slope_bound[0], slope_bound[1], 100)

    stat_fn = 'fig8_SIM_slopeoffset.txt'
    stat_record(stat_fn, True, 'Average Phase precession')

    # Construct pass df
    refangle_key = 'rate_angle'
    passdf_dict = {
        'anglediff': [],
        'slope': [],
        'onset': [],
        'pass_nspikes': []
    }
    spikedf_dict = {'anglediff': [], 'phasesp': []}
    dftmp = simdf[(~simdf[refangle_key].isna())
                  & (simdf['numpass_at_precess'] >= nap_thresh)].reset_index()

    for i in range(dftmp.shape[0]):
        allprecess_df = dftmp.loc[i, 'precess_df']
        precessdf = allprecess_df[allprecess_df['precess_exist']].reset_index(
            drop=True)
        numprecess = precessdf.shape[0]
        if numprecess < 1:
            continue
        ref_angle = dftmp.loc[i, refangle_key]
        anglediff_tmp = cdiff(precessdf['mean_anglesp'].to_numpy(), ref_angle)
        phasesp_tmp = np.concatenate(precessdf['phasesp'].to_list())

        passdf_dict['anglediff'].extend(anglediff_tmp)
        passdf_dict['slope'].extend(precessdf['rcc_m'])
        passdf_dict['onset'].extend(precessdf['rcc_c'])
        passdf_dict['pass_nspikes'].extend(precessdf['pass_nspikes'])

        spikedf_dict['anglediff'].extend(
            repeat_arr(anglediff_tmp,
                       precessdf['pass_nspikes'].to_numpy().astype(int)))
        spikedf_dict['phasesp'].extend(phasesp_tmp)
    passdf = pd.DataFrame(passdf_dict)
    passdf['slope_piunit'] = passdf['slope'] * 2 * np.pi
    spikedf = pd.DataFrame(spikedf_dict)

    absadiff_pass = np.abs(passdf['anglediff'].to_numpy())
    offset = passdf['onset'].to_numpy()
    slope = passdf['slope_piunit'].to_numpy()

    absadiff_spike = np.abs(spikedf['anglediff'].to_numpy())
    phase_spike = spikedf['phasesp'].to_numpy()

    # 1D spike hisotgram
    spikes_bins, spikes_edges = np.histogram(absadiff_spike, bins=adiff_edges)

    # 2D slope/offset histogram
    offset_bins, offset_xedges, offset_yedges = np.histogram2d(
        absadiff_pass, offset, bins=(adiff_edges, offset_edges))
    slope_bins, slope_xedges, slope_yedges = np.histogram2d(absadiff_pass,
                                                            slope,
                                                            bins=(adiff_edges,
                                                                  slope_edges))
    offset_xedm, offset_yedm = midedges(offset_xedges), midedges(offset_yedges)
    slope_xedm, slope_yedm = midedges(slope_xedges), midedges(slope_yedges)
    offset_normbins = norm_div(offset_bins, spikes_bins)
    slope_normbins = norm_div(slope_bins, spikes_bins)

    # Unbinning
    offset_adiff, offset_norm = unfold_binning_2d(offset_normbins, offset_xedm,
                                                  offset_yedm)
    slope_adiff, slope_norm = unfold_binning_2d(slope_normbins, slope_xedm,
                                                slope_yedm)

    # Linear-circular regression
    regress = rcc(offset_adiff, offset_norm)
    offset_m, offset_c, offset_rho, offset_p = regress['aopt'], regress[
        'phi0'], regress['rho'], regress['p']
    regress = rcc(slope_adiff, slope_norm)
    slope_m, slope_c, slope_rho, slope_p = regress['aopt'], regress[
        'phi0'], regress['rho'], regress['p']
    slope_c = slope_c - 2 * np.pi
    stat_record(
        stat_fn, False, 'LC_Regression Onset-adiff $r_{(%d)}=%0.3f, p=%s$' %
        (offset_bins.sum(), offset_rho, p2str(offset_p)))
    stat_record(
        stat_fn, False, 'LC_Regression Slope-adiff $r_{(%d)}=%0.3f, p=%s$' %
        (slope_bins.sum(), slope_rho, p2str(slope_p)))

    # # Plot average precession curves
    low_mask = absadiff_pass < (np.pi / 6)
    high_mask = absadiff_pass > (np.pi - np.pi / 6)
    slopes_high_all, offsets_high_all = slope[high_mask], offset[high_mask]
    slopes_low_all, offsets_low_all = slope[low_mask], offset[low_mask]

    pval_slope, _, slope_descrips, slopetxt = my_kruskal_2samp(
        slopes_low_all, slopes_high_all, 'low-$|d|$', 'high-$|d|$')
    (mdn_slopel, lqr_slopel, hqr_slopel), (mdn_slopeh, lqr_slopeh,
                                           hqr_slopeh) = slope_descrips

    pval_offset, _, offset_descrips, offsettxt = my_ww_2samp(
        offsets_low_all, offsets_high_all, 'low-$|d|$', 'high-$|d|$')
    (cmean_offsetl, sem_offsetl), (cmean_offseth,
                                   sem_offseth) = offset_descrips

    xdum = np.linspace(0, 1, 10)
    high_agg_ydum = mdn_slopeh * xdum + cmean_offseth
    low_agg_ydum = mdn_slopel * xdum + cmean_offsetl
    slopel_valstr = r'low-$|d|=%0.2f$' % (mdn_slopel)
    slopeh_valstr = r'high-$|d|=%0.2f$' % (mdn_slopeh)
    offsetl_valstr = r'low-$|d|=%0.2f$' % (cmean_offsetl)
    offseth_valstr = r'high-$|d|=%0.2f$' % (cmean_offseth)
    stat_record(stat_fn, False, '===== Average precession curves ====')
    stat_record(stat_fn, False,
                'Slope, %s, %s, %s' % (slopel_valstr, slopeh_valstr, slopetxt))
    stat_record(
        stat_fn, False,
        'Onset, %s, %s, %s' % (offsetl_valstr, offseth_valstr, offsettxt))

    ax[0].plot(xdum, high_agg_ydum, c='lime', label='$|d|>5\pi/6$')
    ax[0].plot(xdum, low_agg_ydum, c='darkblue', label='$|d|<\pi/6$')

    ax[0].annotate('$p_s$' + '=%s' % (p2str(pval_slope)),
                   xy=(0.015, 0.2 + 0.03),
                   xycoords='axes fraction',
                   fontsize=legendsize)
    ax[0].annotate('$p_o$' + '=%s' % (p2str(pval_offset)),
                   xy=(0.015, 0.035 + 0.03),
                   xycoords='axes fraction',
                   fontsize=legendsize)
    ax[0].spines["top"].set_visible(False)
    ax[0].spines["right"].set_visible(False)
    ax[0].set_xticks([0, 1])
    ax[0].set_xlim(0, 1)
    ax[0].set_ylim(-np.pi - 1, np.pi + 0.3)
    ax[0].set_yticks([-np.pi, 0, np.pi])
    ax[0].set_yticklabels(['$-\pi$', '0', '$\pi$'])
    ax[0].tick_params(labelsize=ticksize)
    ax[0].set_xlabel('Position')
    customlegend(ax[0],
                 fontsize=legendsize,
                 loc='lower left',
                 handlelength=0.5,
                 bbox_to_anchor=(0.1, 0.7))
    ax[0].set_ylabel('Phase (rad)', fontsize=fontsize)

    # # Spike phases
    low_mask_sp = absadiff_spike < (np.pi / 6)
    high_mask_sp = absadiff_spike > (np.pi - np.pi / 6)
    phasesph = phase_spike[high_mask_sp]
    phasespl = phase_spike[low_mask_sp]
    fstat, k_pval = circ_ktest(phasesph, phasespl)
    p_ww, _, _, p_wwtxt = my_ww_2samp(phasesph, phasespl, r'$high-|d|$',
                                      r'$low-|d|$')
    mean_phasesph = circmean(phasesph)
    mean_phasespl = circmean(phasespl)
    nh, _, _ = ax[1].hist(phasesph,
                          bins=36,
                          density=True,
                          histtype='step',
                          color='lime')
    nl, _, _ = ax[1].hist(phasespl,
                          bins=36,
                          density=True,
                          histtype='step',
                          color='darkblue')
    ml = max(nh.max(), nl.max())
    ax[1].scatter(mean_phasesph,
                  ml * 1.1,
                  marker='|',
                  color='lime',
                  linewidth=0.75)
    ax[1].scatter(mean_phasespl,
                  ml * 1.1,
                  marker='|',
                  color='darkblue',
                  linewidth=0.75)
    ax[1].annotate(r'$p$=%s' % (p2str(p_ww)),
                   xy=(0.3, 0.1),
                   xycoords='axes fraction',
                   fontsize=legendsize)
    ax[1].set_xlim(-np.pi, np.pi)
    ax[1].set_xticks([-np.pi, 0, np.pi])
    ax[1].set_xticklabels(['$-\pi$', '0', '$\pi$'])
    ax[1].set_yticks([])
    ax[1].tick_params(labelsize=ticksize)
    ax[1].spines["top"].set_visible(False)
    ax[1].spines["right"].set_visible(False)
    ax[1].spines["left"].set_visible(False)
    ax[1].set_xlabel('Phase (rad)', fontsize=fontsize)
    ax[1].set_ylabel('Relative\nfrequency', fontsize=fontsize)

    stat_record(stat_fn, False,
                'SIM, difference of mean spike phases, %s' % (p_wwtxt))
    stat_record(stat_fn, False,
                r'SIM, difference of concentration Bartlett\'s test $F_{(%d, %d)}=%0.2f, p=%s$' % \
                (phasesph.shape[0], phasespl.shape[0], fstat, p2str(k_pval)))
Ejemplo n.º 8
0
def plot_field_bestprecession_Romani(simdf, ax):

    print('Plot field best precession')
    stat_fn = 'fig8_SIM_field_precess.txt'
    stat_record(stat_fn, True)
    nap_thresh = 1

    # Stack data
    numpass_mask = simdf['numpass_at_precess'].to_numpy() >= nap_thresh
    numpass_low_mask = simdf['numpass_at_precess_low'].to_numpy() >= nap_thresh
    precess_adiff = []
    precess_nspikes = []
    all_adiff = []
    all_slopes = []

    # Density of Fraction, Spikes and Ratio
    df_this = simdf[numpass_mask
                    & (~simdf['rate_angle'].isna())].reset_index(drop=True)
    for i in range(df_this.shape[0]):
        numpass_at_precess = df_this.loc[i, 'numpass_at_precess']
        if numpass_at_precess < nap_thresh:
            continue
        refangle = df_this.loc[i, 'rate_angle']
        allprecess_df = df_this.loc[i, 'precess_df']
        if allprecess_df.shape[0] < 1:
            continue
        precess_df = allprecess_df[allprecess_df['precess_exist']]
        precess_counts = precess_df.shape[0]
        if precess_counts > 0:
            precess_adiff.append(
                cdiff(precess_df['mean_anglesp'].to_numpy(), refangle))
            precess_nspikes.append(precess_df['pass_nspikes'].to_numpy())
        if allprecess_df.shape[0] > 0:
            all_adiff.append(
                cdiff(allprecess_df['mean_anglesp'].to_numpy(), refangle))
            all_slopes.append(allprecess_df['rcc_m'].to_numpy())
    precess_adiff = np.abs(np.concatenate(precess_adiff))
    precess_nspikes = np.abs(np.concatenate(precess_nspikes))
    adiff_spikes_p = repeat_arr(precess_adiff, precess_nspikes.astype(int))
    adiff_bins = np.linspace(0, np.pi, 45)
    adm = midedges(adiff_bins)
    precess_bins, _ = np.histogram(precess_adiff, bins=adiff_bins)
    spike_bins_p, _ = np.histogram(adiff_spikes_p, bins=adiff_bins)
    spike_bins = spike_bins_p
    norm_bins = (precess_bins / spike_bins)
    norm_bins[np.isnan(norm_bins)] = 0
    norm_bins[np.isinf(norm_bins)] = 0
    precess_allcount = precess_bins.sum()
    rho, pval = spearmanr(adm, norm_bins)
    pm, pc, pr, ppval, _ = linregress(adm, norm_bins / norm_bins.sum())
    xdum = np.linspace(adm.min(), adm.max(), 10)
    linew_ax0 = 0.6
    ax[0].step(adm,
               precess_bins / precess_bins.sum(),
               color='navy',
               linewidth=linew_ax0,
               label='Precession')
    ax[0].step(adm,
               spike_bins / spike_bins.sum(),
               color='orange',
               linewidth=linew_ax0,
               label='Spike')
    ax[0].step(adm,
               norm_bins / norm_bins.sum(),
               color='green',
               linewidth=linew_ax0,
               label='Ratio')
    ax[0].plot(xdum, xdum * pm + pc, color='green', linewidth=linew_ax0)
    ax[0].set_xticks([0, np.pi / 2, np.pi])
    ax[0].set_xticklabels(['0', '$\pi/2$', '$\pi$'])
    # ax[0].set_ylim([0.01, 0.06])
    ax[0].set_yticks([0, 0.1])
    ax[0].tick_params(labelsize=ticksize)
    ax[0].spines["top"].set_visible(False)
    ax[0].spines["right"].set_visible(False)
    ax[0].set_xlabel(r'$|d(\theta_{pass}, \theta_{rate})|$' + ' (rad)',
                     fontsize=fontsize)
    ax[0].set_ylabel('Relative count', fontsize=fontsize, labelpad=5)
    customlegend(ax[0],
                 fontsize=legendsize,
                 bbox_to_anchor=[0, 0.5],
                 loc='lower left')
    ax[0].annotate('p=%s' % (p2str(pval)),
                   xy=(0.4, 0.5),
                   xycoords='axes fraction',
                   fontsize=legendsize,
                   color='green')
    stat_record(
        stat_fn, False,
        r"SIM Spearman's correlation: $r_{s(%d)}=%0.2f, p=%s$ " %
        (precess_allcount, rho, p2str(pval)))

    # Plot Rate angles vs Precess angles

    nprecessmask = simdf['precess_df'].apply(
        lambda x: x['precess_exist'].sum()) > 1
    numpass_mask = numpass_mask[nprecessmask]
    numpass_low_mask = numpass_low_mask[nprecessmask]
    simdf2 = simdf[nprecessmask].reset_index(drop=True)
    rateangles = simdf2['rate_angle'].to_numpy()
    precessangles = simdf2['precess_angle'].to_numpy()
    precessangles_low = simdf2['precess_angle_low'].to_numpy()

    ax[1].scatter(rateangles[numpass_mask],
                  precessangles[numpass_mask],
                  marker='.',
                  c='gray',
                  s=2)
    ax[1].plot([0, np.pi], [np.pi, 2 * np.pi], c='k')
    ax[1].plot([np.pi, 2 * np.pi], [0, np.pi], c='k')
    ax[1].set_xlabel(r'$\theta_{rate}$', fontsize=fontsize)
    ax[1].set_xticks([0, np.pi, 2 * np.pi])
    ax[1].set_xticklabels(['$0$', '$\pi$', '$2\pi$'], fontsize=fontsize)
    ax[1].set_yticks([0, np.pi, 2 * np.pi])
    ax[1].set_yticklabels(['$0$', '$\pi$', '$2\pi$'], fontsize=fontsize)
    ax[1].spines["top"].set_visible(False)
    ax[1].spines["right"].set_visible(False)
    ax[1].set_ylabel(r'$\theta_{Precess}$', fontsize=fontsize)

    # Plot Histogram: d(precess, rate)
    mask = (~np.isnan(rateangles)) & (~np.isnan(precessangles) & numpass_mask)
    adiff = cdiff(precessangles[mask], rateangles[mask])
    bins, edges = np.histogram(adiff, bins=np.linspace(-np.pi, np.pi, 36))
    bins_norm = bins / np.sum(bins)
    l = bins_norm.max()
    ax[2].bar(midedges(edges),
              bins_norm,
              width=edges[1] - edges[0],
              zorder=0,
              color='gray')
    linewidth = 1
    mean_angle = shiftcyc_full2half(circmean(adiff))
    ax[2].annotate("",
                   xy=(mean_angle, l),
                   xytext=(0, 0),
                   color='k',
                   zorder=3,
                   arrowprops=dict(arrowstyle="->"))
    ax[2].plot([0, 0], [0, l], c='k', linewidth=linewidth, zorder=3)
    ax[2].scatter(0, 0, s=16, c='gray')
    ax[2].spines['polar'].set_visible(False)
    ax[2].set_xticks([0, np.pi / 2, np.pi, 3 * np.pi / 2])
    ax[2].set_yticks([0, l / 2])
    ax[2].set_yticklabels([])
    ax[2].set_xticklabels([])
    v_pval, v_stat = vtest(adiff, mu=np.pi)
    ax[2].annotate('p=%s' % (p2str(v_pval)),
                   xy=(0.25, 0.95),
                   xycoords='axes fraction',
                   fontsize=legendsize)
    ax[2].annotate(r'$\theta_{rate}$',
                   xy=(0.95, 0.525),
                   xycoords='axes fraction',
                   fontsize=fontsize + 1)
    stat_record(
        stat_fn, False, r'SIM, d(precess, rate), $V_{(%d)}=%0.2f, p=%s$' %
        (bins.sum(), v_stat, p2str(v_pval)))
    ax[2].set_ylabel('All\npasses', fontsize=fontsize)

    # Plot Histogram: d(precess_low, rate)
    mask_low = (~np.isnan(rateangles)) & (~np.isnan(precessangles_low)
                                          & numpass_low_mask)
    adiff = cdiff(precessangles_low[mask_low], rateangles[mask_low])
    bins, edges = np.histogram(adiff, bins=np.linspace(-np.pi, np.pi, 36))
    bins_norm = bins / np.sum(bins)
    l = bins_norm.max()
    ax[3].bar(midedges(edges),
              bins_norm,
              width=edges[1] - edges[0],
              color='gray',
              zorder=0)
    mean_angle = shiftcyc_full2half(circmean(adiff))
    ax[3].annotate("",
                   xy=(mean_angle, l),
                   xytext=(0, 0),
                   color='k',
                   zorder=3,
                   arrowprops=dict(arrowstyle="->"))
    ax[3].plot([0, 0], [0, l], c='k', linewidth=linewidth, zorder=3)
    ax[3].scatter(0, 0, s=16, c='gray')
    ax[3].spines['polar'].set_visible(False)
    ax[3].set_xticks([0, np.pi / 2, np.pi, 3 * np.pi / 2])
    ax[3].set_yticks([0, l / 2])
    ax[3].set_yticklabels([])
    ax[3].set_xticklabels([])
    v_pval, v_stat = vtest(adiff, mu=np.pi)
    ax[3].annotate('p=%s' % (p2str(v_pval)),
                   xy=(0.25, 0.95),
                   xycoords='axes fraction',
                   fontsize=legendsize)
    ax[3].annotate(r'$\theta_{rate}$',
                   xy=(0.95, 0.525),
                   xycoords='axes fraction',
                   fontsize=fontsize + 1)
    stat_record(
        stat_fn, False, r'SIM, d(precess_low, rate), $V_{(%d)}=%0.2f, p=%s$' %
        (bins.sum(), v_stat, p2str(v_pval)))
    ax[3].set_ylabel('Low-spike\npasses', fontsize=fontsize)