예제 #1
0
def compute_biasshift(x):
    # print(x.describe())
    shift = x.loc[x['probabilityLeft'] == 80,
                  'bias'].item() - x.loc[x['probabilityLeft'] == 20,
                                         'bias'].item()

    xax = np.arange(-100, 100)
    y_80 = psy.erf_psycho_2gammas([
        x.loc[x['probabilityLeft'] == 80, 'bias'].item(),
        x.loc[x['probabilityLeft'] == 80, 'threshold'].item(),
        x.loc[x['probabilityLeft'] == 80, 'lapselow'].item(),
        x.loc[x['probabilityLeft'] == 80, 'lapsehigh'].item()
    ], xax)
    y_20 = psy.erf_psycho_2gammas([
        x.loc[x['probabilityLeft'] == 20, 'bias'].item(),
        x.loc[x['probabilityLeft'] == 20, 'threshold'].item(),
        x.loc[x['probabilityLeft'] == 20, 'lapselow'].item(),
        x.loc[x['probabilityLeft'] == 20, 'lapsehigh'].item()
    ], xax)

    yshift = 100 * (y_20[xax == 0] - y_80[xax == 0])
    yshift = 0.5 + (y_20[xax == 0] -
                    y_80[xax == 0]) / 2  # from Nick Roy, 23 April

    return yshift
예제 #2
0
def plot_psychometric(trials, ax, **kwargs):
    from ibl_pipeline.utils import psychofit as psy
    if trials['signed_contrast'].max() <= 1:
        trials['signed_contrast'] = trials['signed_contrast'] * 100

    stim_levels = np.sort(trials['signed_contrast'].unique())
    pars = fit_psychfunc(
        stim_levels,
        trials.groupby('signed_contrast').size(),
        trials.groupby('signed_contrast').mean()['right_choice'])

    # plot psychfunc
    sns.lineplot(x=np.arange(-27, 27),
                 y=psy.erf_psycho_2gammas(pars, np.arange(-27, 27)),
                 ax=ax,
                 **kwargs)

    # plot psychfunc: -100, +100
    sns.lineplot(x=np.arange(-36, -31),
                 y=psy.erf_psycho_2gammas(pars, np.arange(-103, -98)),
                 ax=ax,
                 **kwargs)
    sns.lineplot(x=np.arange(31, 36),
                 y=psy.erf_psycho_2gammas(pars, np.arange(98, 103)),
                 ax=ax,
                 **kwargs)

    # now break the x-axis
    trials['signed_contrast'].replace(-100, -35)
    trials['signed_contrast'].replace(100, 35)

    # plot datapoints with errorbars on top
    sns.lineplot(x=trials['signed_contrast'],
                 y=trials['right_choice'],
                 ax=ax,
                 **{
                     **{
                         'err_style': "bars",
                         'linewidth': 0,
                         'linestyle': 'None',
                         'mew': 0.5,
                         'marker': 'o',
                         'ci': 68
                     },
                     **kwargs
                 })

    ax.set(xticks=[-35, -25, -12.5, 0, 12.5, 25, 35],
           xlim=[-40, 40],
           ylim=[0, 1.02],
           yticks=[0, 0.25, 0.5, 0.75, 1],
           yticklabels=['0', '25', '50', '75', '100'],
           ylabel='Right choices',
           xlabel='Contrast (%)')
    ax.set_xticklabels(['-100', '-25', '-12.5', '0', '12.5', '25', '100'],
                       size='small')
    break_xaxis()
def pars2shift(pars, choicevar, outcomevar):
    pars2 = pd.DataFrame([])
    xvec = behav.signed_contrast.unique()
    for index, group in pars.groupby(['institution_code', 'subject_nickname', 'task',
                                      choicevar, outcomevar]):
        # expand
        yvec = psy.erf_psycho_2gammas([group.bias.item(),
                                       group.threshold.item(),
                                       group.lapselow.item(),
                                       group.lapsehigh.item()], xvec)
        group2 = group.loc[group.index.repeat(
            len(yvec))].reset_index(drop=True).copy()
        group2['signed_contrast'] = xvec
        group2['choice'] = 100 * yvec
        # add this
        pars2 = pars2.append(group2)

    # only pick psychometric functions that were fit on a reasonable number of trials...
    pars2 = pars2[(pars2.ntrials > 50) & (pars2.signed_contrast == 0)]

    # compute history-dependent bias shift
    pars3 = pd.pivot_table(pars2, values='choice',
                           index=['institution_code', 'subject_nickname',
                                  'task', outcomevar],
                           columns=[choicevar]).reset_index()
    pars3['bias_shift'] = pars3.right - pars3.left
    pars4 = pd.pivot_table(pars3, values='bias_shift',
                           index=['institution_code', 'subject_nickname', 'task'],
                           columns=[outcomevar]).reset_index()
    print(pars4.describe())
    return pars4
예제 #4
0
def pars2choicefract(group):
    group['choicefract'] = psy.erf_psycho_2gammas([
        group.bias.item(),
        group.threshold.item(),
        group.lapselow.item(),
        group.lapsehigh.item()
    ], 0) * 100
    return group
예제 #5
0
def compute_biasshift_postcorrect(x):

    xax = np.arange(-100, 100)
    x_right = x.loc[np.isclose(x['previous_choice'], 1)
                    & np.isclose(x['previous_outcome'], 1)]
    x_left = x.loc[np.isclose(x['previous_choice'], -1)
                   & np.isclose(x['previous_outcome'], 1)]

    y_right = psy.erf_psycho_2gammas([
        x_right['bias'].item(), x_right['threshold'].item(),
        x_right['lapselow'].item(), x_right['lapsehigh'].item()
    ], xax)
    y_left = psy.erf_psycho_2gammas([
        x_left['bias'].item(), x_left['threshold'].item(),
        x_left['lapselow'].item(), x_left['lapsehigh'].item()
    ], xax)

    shift_postcorrect = (y_right[xax == 0] - y_left[xax == 0])
    return shift_postcorrect
예제 #6
0
def compute_biasshift(x):

	# shift in the intercept parameter, along x-axis
	shift = x.loc[x['probabilityLeft'] == 80, 'bias'].item() - x.loc[x['probabilityLeft'] == 20, 'bias'].item()

	# also read out the y-shift, in choice probability
	xax = np.arange(-100, 100)
	y_80 = psy.erf_psycho_2gammas([x.loc[x['probabilityLeft'] == 80, 'bias'].item(), 
		x.loc[x['probabilityLeft'] == 80, 'threshold'].item(), 
		x.loc[x['probabilityLeft'] == 80, 'lapselow'].item(), 
		x.loc[x['probabilityLeft'] == 80, 'lapsehigh'].item()], xax)
	y_20 = psy.erf_psycho_2gammas([x.loc[x['probabilityLeft'] == 20, 'bias'].item(), 
		x.loc[x['probabilityLeft'] == 20, 'threshold'].item(), 
		x.loc[x['probabilityLeft'] == 20, 'lapselow'].item(), 
		x.loc[x['probabilityLeft'] == 20, 'lapsehigh'].item()], xax)
	print(y_20[xax == 0])
	print(y_80[xax == 0])
	
	yshift = 0.5 + (y_20[xax == 0] - y_80[xax == 0]) / 2 # from Nick Roy, 23 April

	return yshift
예제 #7
0
def plot_psychometric(df, color='black', ax=None, **kwargs):
    """
    Plots psychometric data for a given DataFrame of behavioural trials

    If the data contains more than six different contrasts (or > three per side)
    the data are fit with an erf function.  The x-axis is percent contrast and
    the y-axis is the proportion of 'rightward choices', i.e. trials where the
    subject turned the wheel clockwise to threshold.

    Example:
        df = alf.load_behaviour('2018-09-11_1_Mouse1', r'\\server\SubjectData')
        plot_psychometric(df)

    Args:
        df (DataFrame): DataFrame constructed from an ALF trials object.
        ax (Axes): Axes to plot to.  If None, a new figure is created.

    Returns:
        ax (Axes): The plot axes
    """

    if len(df['signedContrast'].unique()) > 4:
        df2 = df.groupby(['signedContrast']).agg({'choice':'count', 'choice2':'mean'}).reset_index()
        df2.rename(columns={"choice2": "fraction", "choice": "ntrials"}, inplace=True)

        pars, L = psy.mle_fit_psycho(df2.transpose().values, # extract the data from the df
                                     P_model='erf_psycho_2gammas',
                                     parstart=np.array([df2['signedContrast'].mean(), 20., 0.05, 0.05]),
                                     parmin=np.array([df2['signedContrast'].min(), 0., 0., 0.]),
                                     parmax=np.array([df2['signedContrast'].max(), 100., 1, 1]))
        sns.lineplot(np.arange(-100,100), psy.erf_psycho_2gammas( pars, np.arange(-100,100)), color=color, ax=ax)

    # plot datapoints on top
    sns.lineplot(x='signedContrast', y='choice2', err_style="bars", linewidth=0, linestyle='None', mew=0.5,
        marker='.', ci=68, data=df, color=color, ax=ax)

    # Reduce the clutter
    ax.set_xticks([-100, -50, 0, 50, 100])
    ax.set_xticklabels(['-100', '-50', '0', '50', '100'])
    ax.set_yticks([0, .5, 1])
    # Set the limits
    ax.set_xlim([-110, 110])
    ax.set_ylim([-0.03, 1.03])
    ax.set_xlabel('Contrast (%)')

    return ax
예제 #8
0
def plot_psychometric(x, y, subj, **kwargs):

    # summary stats - average psychfunc over observers
    df = pd.DataFrame({'signed_contrast': x, 'choice': y,
                       'choice2': y, 'subject_nickname': subj})
    df2 = df.groupby(['signed_contrast', 'subject_nickname']).agg(
        {'choice2': 'count', 'choice': 'mean'}).reset_index()
    df2.rename(columns={"choice2": "ntrials",
                        "choice": "fraction"}, inplace=True)
    df2 = df2.groupby(['signed_contrast']).mean().reset_index()
    df2 = df2[['signed_contrast', 'ntrials', 'fraction']]

    # only 'break' the x-axis and remove 50% contrast when 0% is present
    # print(df2.signed_contrast.unique())
    if 0. in df2.signed_contrast.values:
        brokenXaxis = True
    else:
        brokenXaxis = False

    # fit psychfunc
    pars, L = psy.mle_fit_psycho(df2.transpose().values,  # extract the data from the df
                                 P_model='erf_psycho_2gammas',
                                 parstart=np.array(
                                     [0, 20., 0.05, 0.05]),
                                 parmin=np.array(
                                     [df2['signed_contrast'].min(), 5, 0., 0.]),
                                 parmax=np.array([df2['signed_contrast'].max(), 40., 1, 1]))

    if brokenXaxis:
        # plot psychfunc
        g = sns.lineplot(np.arange(-29, 29),
                         psy.erf_psycho_2gammas(pars, np.arange(-29, 29)), **kwargs)

        # plot psychfunc: -100, +100
        sns.lineplot(np.arange(-37, -32),
                     psy.erf_psycho_2gammas(pars, np.arange(-103, -98)), **kwargs)
        sns.lineplot(np.arange(32, 37),
                     psy.erf_psycho_2gammas(pars, np.arange(98, 103)), **kwargs)

        # now break the x-axis
        # if 100 in df.signed_contrast.values and not 50 in
        # df.signed_contrast.values:
        df['signed_contrast'] = df['signed_contrast'].replace(-100, -35)
        df['signed_contrast'] = df['signed_contrast'].replace(100, 35)

    else:
        # plot psychfunc
        g = sns.lineplot(np.arange(-103, 103),
                         psy.erf_psycho_2gammas(pars, np.arange(-103, 103)), **kwargs)


    df3 = df.groupby(['signed_contrast', 'subject_nickname']).agg(
        {'choice2': 'count', 'choice': 'mean'}).reset_index()

    # plot datapoints with errorbars on top
    if df['subject_nickname'].nunique() > 1:
        sns.lineplot(df3['signed_contrast'], df3['choice'], err_style="bars",
                     linewidth=0, linestyle='None', mew=0.5,
                     marker='o', ci=68, **kwargs)

    if brokenXaxis:
        g.set_xticks([-35, -25, -12.5, 0, 12.5, 25, 35])
        g.set_xticklabels(['-100', '-25', '-12.5', '0', '12.5', '25', '100'],
                          size='small', rotation=60)
        g.set_xlim([-40, 40])
    else:
        g.set_xticks([-100, -50, 0, 50, 100])
        g.set_xticklabels(['-100', '-50', '0', '50', '100'],
                          size='small', rotation=60)
        g.set_xlim([-110, 110])

    g.set_ylim([0, 1.02])
    g.set_yticks([0, 0.25, 0.5, 0.75, 1])
    g.set_yticklabels(['0', '25', '50', '75', '100'])
def plot_from_spots(spotlist,
                    psychoSpotData,
                    spots,
                    color,
                    ax,
                    plotType='psycho',
                    bs=False):
    """
        Function to plot three psychometrics on a single plot, with the dots that they were 
        generated with. usually I'll use this with a group of left spots, a group of right spots
        and a group of control spots.

        Inputs:
        spotlists: an array containing the spots that you want to group together to plot the 
        psychometric for. a n by 2 numpy array that gives [[x1,y1],[x2,y2],[xn,yn]]
        psychoSpotData: a list of len(numSpots) each with a list lenght 4 containing 1, an array of
        signed contrasts, 2, a list of number of presentations for that contrast, 3, a list of 
        arrays containing a bool for if choice was CCW (list len num contrast, array len num
        presentations) 4, a list of the same form as above with the reaction times
        spots: a dataframe of length num spots, column 0: laserPosX, column 1: laserPosY, column3, 
        count
        color: the color for the line you want to plot, string eg 'b'
        ax: the matplotlib axis to plot onto
        plotType: defualt is psycho for plotting psychometric curves, other option is 'chrono'

    """
    if plotType == 'psycho':
        psycho = [[], [0 for i in range(len(psychoSpotData[0][1]))],
                  [np.array([])] * len(psychoSpotData[0][1])]
        controlSpotPsycho = [[], [
            0 for i in range(len(psychoSpotData[0][1]))
        ], [np.nan for i in range(len(psychoSpotData[0][1]))]]
        tempPsych = [np.array([])] * len(psychoSpotData[0][1])
        for i in range(len(spots)):
            spotX = spots.iloc[i, [0]][0]
            spotY = spots.iloc[i, [1]][0]
            for spot in range(len(spotlist)):
                if spotX == spotlist[spot][0] and spotY == spotlist[spot][1]:
                    psycho[0] = psychoSpotData[i][0]
                    psycho[1] = [
                        temp + j
                        for temp, j in zip(psychoSpotData[i][1], psycho[1])
                    ]
                    for contrast in range(len(psycho[0])):
                        con = int(contrast)
                        tempPsych[con] = np.append(tempPsych[con],
                                                   psychoSpotData[i][2][con])

        sems = []
        for c in range(len(tempPsych)):
            psycho[2][c] = np.nanmean(tempPsych[c])
            sems.append(stats.sem(tempPsych[c]))

        if bs:
            ## Bootstrap confidence intervals
            nboots = 10
            bootFits = pd.DataFrame(
                columns=['threshold', 'slope', 'gamma', 'lambda'],
                index=range(nboots))
            bootData = [[], [0 for i in range(len(psychoSpotData[0][1]))],
                        [np.array([])] * len(psychoSpotData[0][1])]
            bootData[0] = psycho[0]
            cnt = 0
            print('bootstrapping errorbars...', sep=' ', end='')
            for i in range(nboots):
                if not (cnt % 5):
                    print(int(cnt / nboots * 100),
                          sep=' ',
                          end='%,',
                          flush=True)
                for j in range(len(tempPsych)):
                    bootData[2][j] = np.random.choice(
                        tempPsych[j],
                        size=int(len(tempPsych[j]) / 1.25),
                        replace=True)
                    bootData[1][j] = len(bootData[2][j])
                    bootData[2][j] = np.mean(bootData[2][j])
                fitParams = []
                fitLikes = []
                for repeat in range(5):
                    parStart = np.array([
                        -5 + np.random.rand() * 10, 0 + np.random.rand() * 100,
                        0 + np.random.rand(), 0 + np.random.rand()
                    ])
                    pars, L = mle_fit_psycho(bootData,
                                             P_model='erf_psycho_2gammas',
                                             parstart=np.array([0, 50, .5,
                                                                .5]),
                                             parmin=np.array([-5, 0., 0., 0.]),
                                             parmax=np.array([5, 100., 1, 1]),
                                             nfits=2)

                    fitParams.append(pars)
                    fitLikes.append(L)
                cnt += 1
                bootFits.iloc[i] = fitParams[np.where(min(fitLikes))[0][0]]

            a = .05
            CIs = []
            for i in bootFits.columns:
                CIs.append([
                    np.percentile(bootFits[i], 100 - a / 2),
                    np.percentile(
                        bootFits[i],
                        a / 2,
                    )
                ])
        else:
            CIs = None

            ## plotting psychometrics for different cortical groups
        lines = []

        fitParams = []
        fitLikes = []
        for repeat in range(10):
            parStart = np.array([
                -5 + np.random.rand() * 10, 0 + np.random.rand() * 100,
                0 + np.random.rand(), 0 + np.random.rand()
            ])
            params, L = psychofit.mle_fit_psycho(
                psycho,
                P_model='erf_psycho_2gammas',
                parstart=parStart,
                parmin=np.array([-5, 0., 0., 0.]),
                parmax=np.array([5, 100., 1, 1]),
                nfits=25)
            fitParams.append(params)
            fitLikes.append(L)
            # find the best params (with the lowest neg likelihood)
        params = fitParams[np.where(min(fitLikes))[0][0]]

        spotFits.append(params)
        #plot the psychometrics
        fitx = np.linspace(-1, 1, 100)
        fity = psychofit.erf_psycho_2gammas(params, fitx)

        line = ax.plot(fitx, fity, color=color)
        lines.append(line)
        ax.errorbar(psycho[0],
                    np.array(psycho[2]),
                    yerr=sems,
                    color=color,
                    marker='.',
                    ms=4,
                    ls='')
        plt.ylim(-0.1, 1.1)
        plt.xlim(-1.1, 1.1)

    elif plotType == 'chrono':
        chrono = [[], [0 for i in range(len(psychoSpotData[0][1]))],
                  [np.array([])] * len(psychoSpotData[0][1])]
        tempChrono = [np.array([])] * len(psychoSpotData[0][1])
        for i in range(len(spots)):
            spotX = spots.iloc[i, [0]][0]
            spotY = spots.iloc[i, [1]][0]

            for spot in range(len(spotlist)):
                if spotX == spotlist[spot][0] and spotY == spotlist[spot][1]:
                    chrono[0] = psychoSpotData[i][0]
                    chrono[1] = [
                        temp + j
                        for temp, j in zip(psychoSpotData[i][1], chrono[1])
                    ]
                    for contrast in range(len(chrono[0])):
                        con = int(contrast)
                        tempChrono[con] = np.append(tempChrono[con],
                                                    psychoSpotData[i][3][con])
        sems = []
        for c in range(len(tempChrono)):
            chrono[2][c] = np.nanmedian(tempChrono[c])
            sems.append(stats.sem(tempChrono[c]))
        ax.errorbar(chrono[0],
                    np.array(chrono[2]),
                    yerr=sems,
                    color=color,
                    marker='.',
                    ms=4)
        ax.set_ylim(.15, .5)
        # the params I use here are RT at 0 contrast, 'RT bias' which is pairwise RT left- RT right, and
        # peakiness which is the ratio of max RT to the average of the two 100% RTs
        p2 = (chrono[2][0] - chrono[2][-1]) + (chrono[2][1] - chrono[2][-2] +
                                               (chrono[2][2] - chrono[2][-3]) +
                                               (chrono[2][3] - chrono[2][-4]))
        params = [
            chrono[2][4], p2,
            max(chrono[2]) / np.mean([chrono[2][0], chrono[2][-1]]), chrono[2]
        ]
        CIs = None
    else:
        raise Exception(
            "This is not a supported plot type, choose 'psycho' or 'chrono'")
    return params, CIs
예제 #10
0
def create_psych_curve_plot(sessions):
    data_mean = []
    data_errorbar = []
    data_fit = []

    for session in sessions.fetch('KEY'):
        contrasts, prob_right, prob_left, \
            threshold, bias, lapse_low, lapse_high, \
            n_trials, n_trials_right = \
            (sessions & session).fetch1(
                'signed_contrasts', 'prob_choose_right', 'prob_left',
                'threshold', 'bias', 'lapse_low', 'lapse_high',
                'n_trials_stim', 'n_trials_stim_right')

        pars = [bias, threshold, lapse_low, lapse_high]
        contrasts = contrasts * 100
        contrasts_fit = np.arange(-100, 100)
        prob_right_fit = psy.erf_psycho_2gammas(pars, contrasts_fit)
        ci = smp.proportion_confint(
            n_trials_right, n_trials, alpha=0.032,
            method='normal') - prob_right

        curve_color, error_color = get_color(prob_left, 0.3)

        behavior_data = go.Scatter(
            x=contrasts.tolist(),
            y=prob_right.tolist(),
            marker=dict(size=6,
                        color=curve_color,
                        line=dict(color='white', width=1)),
            mode='markers',
            name=f'p_left = {prob_left}, data with 68% CI')

        behavior_errorbar = go.Scatter(x=contrasts.tolist(),
                                       y=prob_right.tolist(),
                                       error_y=dict(type='data',
                                                    array=ci[0].tolist(),
                                                    arrayminus=np.negative(
                                                        ci[1]).tolist(),
                                                    visible=True,
                                                    color=error_color),
                                       marker=dict(size=6, ),
                                       mode='none',
                                       showlegend=False)

        behavior_fit = go.Scatter(x=contrasts_fit.tolist(),
                                  y=prob_right_fit.tolist(),
                                  name=f'p_left = {prob_left} model fits',
                                  marker=dict(color=curve_color))

        data_mean.append(behavior_data)
        data_errorbar.append(behavior_errorbar)
        data_fit.append(behavior_fit)

    layout = go.Layout(width=630,
                       height=350,
                       title=dict(text='Psychometric Curve', x=0.25, y=0.85),
                       xaxis=dict(title='Contrast (%)'),
                       yaxis=dict(title='Probability choosing right',
                                  range=[-0.05, 1.05]),
                       template=dict(layout=dict(plot_bgcolor="white")))

    data = data_errorbar
    for element in data_fit:
        data.append(element)

    for element in data_mean:
        data.append(element)

    return go.Figure(data=data, layout=layout)
예제 #11
0
def plot_psychometric(x, y, subj, **kwargs):

    # summary stats - average psychfunc over observers
    df = pd.DataFrame({
        'signed_contrast': x,
        'choice': y,
        'choice2': y,
        'subject_nickname': subj
    })
    df2 = df.groupby(['signed_contrast', 'subject_nickname']).agg({
        'choice2':
        'count',
        'choice':
        'mean'
    }).reset_index()
    df2.rename(columns={
        "choice2": "ntrials",
        "choice": "fraction"
    },
               inplace=True)
    df2 = df2.groupby(['signed_contrast']).mean().reset_index()
    df2 = df2[['signed_contrast', 'ntrials', 'fraction']]

    # fit psychfunc
    pars, L = psy.mle_fit_psycho(
        df2.transpose().values,  # extract the data from the df
        P_model='erf_psycho_2gammas',
        parstart=np.array([df2['signed_contrast'].mean(), 20., 0.05, 0.05]),
        parmin=np.array([df2['signed_contrast'].min(), 0., 0., 0.]),
        parmax=np.array([df2['signed_contrast'].max(), 100., 0.5, 0.5]))

    # plot psychfunc
    sns.lineplot(np.arange(-29, 29),
                 psy.erf_psycho_2gammas(pars, np.arange(-29, 29)), **kwargs)

    # plot psychfunc: -100
    sns.lineplot(np.arange(-37, -32),
                 psy.erf_psycho_2gammas(pars, np.arange(-103, -98)), **kwargs)
    sns.lineplot(np.arange(32, 37),
                 psy.erf_psycho_2gammas(pars, np.arange(98, 103)), **kwargs)

    # now break the x-axis
    # if 100 in df.signed_contrast.values and not 50 in df.signed_contrast.values:
    df['signed_contrast'] = df['signed_contrast'].replace(-100, -35)
    df['signed_contrast'] = df['signed_contrast'].replace(100, 35)

    df3 = df.groupby(['signed_contrast', 'subject_nickname']).agg({
        'choice2':
        'count',
        'choice':
        'mean'
    }).reset_index()

    # plot datapoints with errorbars on top
    g = sns.lineplot(df3['signed_contrast'],
                     df3['choice'],
                     err_style="bars",
                     linewidth=0,
                     linestyle='None',
                     mew=0.5,
                     marker='o',
                     ci=68,
                     **kwargs)
    g.set_yticks([0, 0.25, 0.5, 0.75, 1])

    # # ADD TEXT WITH THE PSYCHOMETRIC FUNCTION PARAMETERS
    # if len(df['subject_nickname'].unique()) == 1:

    # 	try:
    # 		# add text with parameters into the plot
    # 		if kwargs['label'] == '50':
    # 			ypos = 0.5
    # 			# ADD PSYCHOMETRIC FUNCTION PARAMS
    # 			plt.text(-35, ypos, r'$\mu\/ %.2f,\/ \sigma\/ %.2f,$'%(pars[0], pars[1]) + '\n' + r'$\gamma \/%.2f,\/ \lambda\/ %.2f$'%(pars[2], pars[3]),
    # 			fontweight='normal', fontsize=5, color=kwargs['color'])

    # 		elif kwargs['label'] == '20':
    # 			ypos = 0.3
    # 			# ADD PSYCHOMETRIC FUNCTION PARAMS
    # 			plt.text(-35, ypos, r'$\mu\/ %.2f,\/ \sigma\/ %.2f,$'%(pars[0], pars[1]) + '\n' + r'$\gamma \/%.2f,\/ \lambda\/ %.2f$'%(pars[2], pars[3]),
    # 			fontweight='normal', fontsize=5, color=kwargs['color'])

    # 		elif kwargs['label'] == '80':
    # 			ypos = 0.7
    # 			# ADD PSYCHOMETRIC FUNCTION PARAMS
    # 			plt.text(-35, ypos, r'$\mu\/ %.2f,\/ \sigma\/ %.2f,$'%(pars[0], pars[1]) + '\n' + r'$\gamma \/%.2f,\/ \lambda\/ %.2f$'%(pars[2], pars[3]),
    # 			fontweight='normal', fontsize=5, color=kwargs['color'])
    # 	except: # when there is no label
    # 		# pass
    # 		ypos = 0.5
    # 		# ADD PSYCHOMETRIC FUNCTION PARAMS
    # 		plt.text(-35, ypos, r'$\mu\/ %.2f,\/ \sigma\/ %.2f,$'%(pars[0], pars[1]) + '\n' + r'$\gamma \/%.2f,\/ \lambda\/ %.2f$'%(pars[2], pars[3]),
    # 		fontweight='normal', fontsize=8, color=kwargs['color'])
    # 		# plt.text(12, 0.1, '1 mouse', fontsize=10, color='k')

    # print the number of mice
    if df['subject_nickname'].nunique() == 1:
        plt.text(12, 0.1, '1 mouse', fontsize=10, color='k')
    else:
        plt.text(12,
                 0.1,
                 '%d mice' % (df['subject_nickname'].nunique()),
                 fontsize=10,
                 color='k')

    #if brokenXaxis:
    g.set_xticks([-35, -25, -12.5, 0, 12.5, 25, 35])
    g.set_xticklabels(['-100', '-25', '-12.5', '0', '12.5', '25', '100'],
                      size='small',
                      rotation=45)
    g.set_xlim([-40, 40])
    g.set_ylim([0, 1])
    g.set_yticks([0, 0.25, 0.5, 0.75, 1])
    g.set_yticklabels(['0', '25', '50', '75', '100'])
예제 #12
0
def model_psychometric_history(behav):
    select =  behav.copy()
    select['t-1'] = select['trial_feedback_type'].shift(periods=1).to_numpy()
    select.loc[select['choice'] == -1, 'choice'] = 0 
    select = select.iloc[1:,:]
    #select['t-1'].fillna(0,  inplace=True)
    select['t-1']  = select['t-1'].astype(int)
    
    plot_psychometric(select.loc[select['signed_contrast'],
                     select.loc[select['probabilityLeft'] ==i, 'signed_contrast'], palette = ['red', 'green'], 
                     ci = 68)

    sns.lineplot(data = select_50, hue = 't-1', x = select_50['signed_contrast'],
                     y = select_50['simulation_prob'], palette = ['red', 'green'], ci = 68)


## Functions

def run_glm(behav, example, correction = True,  bias = False, cross_validation = True):
    for i, nickname in enumerate(np.unique(behav['subject_nickname'])):
        if np.mod(i+1, 10) == 0:
            print('Loading data of subject %d of %d' % (i+1, len(
                    np.unique(behav['subject_nickname']))))
    
        # Get the trials of the sessions around criterion
        trials = behav.loc[behav['subject_nickname'] == nickname].copy()
        
        
        if bias == True:
            neutral_n = fit_psychfunc(behav[(behav['subject_nickname'] == nickname)
                                   & (behav['probabilityLeft'] == 50)])
            left_fit = fit_psychfunc(behav[(behav['subject_nickname'] == nickname)
                                           & (behav['probabilityLeft'] == 80)])
            right_fit = fit_psychfunc(behav[(behav['subject_nickname'] == nickname)
                                            & (behav['probabilityLeft'] == 20)])
            
            behav.loc[behav['subject_nickname'] == nickname, 'bias_n'] = \
                neutral_n.loc[0, 'bias']
            behav.loc[behav['subject_nickname'] == nickname, 'bias_r'] = \
                right_fit.loc[0, 'bias']
            behav.loc[behav['subject_nickname'] == nickname, 'bias_l'] = \
                left_fit.loc[0, 'bias']
    
        else:
            fit_df = dj2pandas(trials.copy())
            fit_result = fit_psychfunc(fit_df)
            behav.loc[behav['subject_nickname'] == nickname, 'threshold'] = \
                fit_result.loc[0, 'threshold']
        ## GLM
        #make separate datafrme 
        data = trials[['index', 'trial_feedback_type',
                       'signed_contrast', 'choice',
                           'probabilityLeft']].copy()
        
        #drop trials with odd probabilities of left
        data.drop(
            data['probabilityLeft'][~data['probabilityLeft'].isin([50,20,80])].index,
            inplace=True)
        
        
        # Rewardeded choices: 
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()), 'rchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == -1), 'rchoice']  = 0
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == 1), 'rchoice']  = -1
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == 1), 'rchoice']  = 1
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()) , 'rchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == -1), 'rchoice']  = 0
        
        # Unrewarded choices:
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()), 'uchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == -1), 'uchoice']  = -1 
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == 1), 'uchoice']  = 0 
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == 1), 'uchoice']  = 0 
        data.loc[(data['choice'] == 0) & 
                 (data['trial_feedback_type'].isnull()) , 'uchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == -1) , 'uchoice']  = 1
        
        # Apply correction
        if correction == True:
           data['rchoice+1'] = \
           data['rchoice'].shift(periods=-1).to_numpy()
           data['uchoice+1'] = \
           data['uchoice'].shift(periods=-1).to_numpy()
            
        # Shift rewarded and unrewarded predictors by one
        data.loc[:, ['rchoice', 'uchoice']] = \
            data[['rchoice', 'uchoice']].shift(periods=1).to_numpy()
            
    
        # Drop any nan trials
        data.dropna(inplace=True)
        
        # Make sensory predictors (no 0 predictor)
        contrasts = [ 25, 100,  12.5,   6.25]
        for i in contrasts:
            data.loc[(data['signed_contrast'].abs() == i), i] = \
                np.sign(data.loc[(data['signed_contrast'].abs() == i),
                                 'signed_contrast'].to_numpy())
            
            data_con =  data[i].copy()
            data[i] = data_con.fillna(0)
        
        # If contrast missing break
        for i in contrasts:
            if np.sum(data[i]) == 0:
                print('missing contrast')
                missing_contrast = True
            else:
                missing_contrast = False
        
        if missing_contrast == True:
            continue
        
        # Make block identity (across predictors right is positive, hence logic below)
        if bias == True:
            data.loc[(data['probabilityLeft'] == 50), 'block'] = 0
            data.loc[(data['probabilityLeft'] == 20), 'block'] = 1
            data.loc[(data['probabilityLeft'] == 80), 'block'] = -1
        
        # Make choice in between 0 and 1 -> 1 for right and 0 for left
        data.loc[data['choice'] == -1, 'choice'] = 0
        
        # Store index
        index = data['index'].copy()
        
        # Create predictor matrix
        endog = data['choice'].copy()
        exog = data.copy()
        exog.drop(columns=['trial_feedback_type', 
                       'signed_contrast', 'choice', 
                           'probabilityLeft'], inplace=True)
        exog = sm.add_constant(exog)
        
        if cross_validation == False:
            X_train = exog.copy()
            X_test = exog.copy()
            y_train = endog.copy()
            y_test = endog.copy()
            
        else:
            X_train = exog.iloc[:int(len(exog)*0.70),:].copy()
            X_test = exog.iloc[int(len(endog)*0.70):,:].copy()
            y_train = endog.iloc[:int(len(endog)*0.70)].copy()
            y_test = endog.iloc[int(len(endog)*0.70):].copy()
        
        # Store index
        
        index = X_test['index'].to_numpy()
        X_train.drop(columns=['index'], inplace=True)
        X_test.drop(columns=['index'], inplace=True)
        
        
        # Fit model
        try:
            logit_model = sm.Logit(y_train, X_train)
            result = logit_model.fit_regularized()
            # print(result.summary2())
            
            # Store model weights
            behav.loc[behav['subject_nickname'] == nickname, 'intercept'] = result.params['const'].copy()
            behav.loc[behav['subject_nickname'] == nickname, 'rchoice'] = result.params['rchoice'].copy()
            behav.loc[behav['subject_nickname'] == nickname, 'uchoice'] = result.params['uchoice'].copy()
            mask = result.params.index.get_level_values(0)
            behav.loc[behav['subject_nickname'] == nickname, '25'] = result.params[25].copy()
            behav.loc[behav['subject_nickname'] == nickname, '6'] = result.params.loc[mask == 6.25][0]
            behav.loc[behav['subject_nickname'] == nickname, '100'] = result.params[100].copy()
            behav.loc[behav['subject_nickname'] == nickname, '12'] = result.params.loc[mask == 12.5][0]
            
            if bias == True:
                behav.loc[behav['subject_nickname'] == nickname, 'block'] = result.params['block'].copy()
            
            if correction == True:
                behav.loc[behav['subject_nickname'] == nickname, 'rchoice+1'] = result.params['rchoice+1'].copy()
                behav.loc[behav['subject_nickname'] == nickname, 'uchoice+1'] = result.params['uchoice+1'].copy()
            # Probabilities on test data
            prob = result.predict(X_test).to_numpy()
            
            if nickname == example:
                example_model = result
            
            # Propagate to storing dataframe
            behav.loc[behav['index'].isin(index), 'simulation_prob'] = prob
        except:
            print('singular matrix')
    return behav, example_model


def data_2_X_test (behav, correction = True, bias = True):
        data = behav[['index','trial_feedback_type',
                       'signed_contrast', 'choice',
                           'probabilityLeft']].copy()
        
        #drop trials with odd probabilities of left
        data.drop(
            data['probabilityLeft'][~data['probabilityLeft'].isin([50,20,80])].index,
            inplace=True)
        
        
        # Rewardeded choices: 
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()), 'rchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == -1), 'rchoice']  = 0
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == 1), 'rchoice']  = -1
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == 1), 'rchoice']  = 1
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()) , 'rchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == -1), 'rchoice']  = 0
        
        # Unrewarded choices:
        data.loc[(data['choice'] == 0) &
                 (data['trial_feedback_type'].isnull()), 'uchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == -1), 'uchoice']  = -1 
        data.loc[(data['choice'] == -1) &
                 (data['trial_feedback_type'] == 1), 'uchoice']  = 0 
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == 1), 'uchoice']  = 0 
        data.loc[(data['choice'] == 0) & 
                 (data['trial_feedback_type'].isnull()) , 'uchoice']  = 0 # NoGo trials
        data.loc[(data['choice'] == 1) &
                 (data['trial_feedback_type'] == -1) , 'uchoice']  = 1
        
        # Apply correction
        if correction == True:
           data['rchoice+1'] = \
           data['rchoice'].shift(periods=-1).to_numpy()
           data['uchoice+1'] = \
           data['uchoice'].shift(periods=-1).to_numpy()
            
        # Shift rewarded and unrewarded predictors by one
        data.loc[:, ['rchoice', 'uchoice']] = \
            data[['rchoice', 'uchoice']].shift(periods=1).to_numpy()
            
    
        # Drop any nan trials
        data.dropna(inplace=True)
        
        # Make sensory predictors (no 0 predictor)
        contrasts = [ 25, 100,  12.5,   6.25]
        for i in contrasts:
            data.loc[(data['signed_contrast'].abs() == i), i] = \
                np.sign(data.loc[(data['signed_contrast'].abs() == i),
                                 'signed_contrast'].to_numpy())
            
            data_con =  data[i].copy()
            data[i] = data_con.fillna(0)
        
        # Make block identity (across predictors right is positive, hence logic below)
        if bias == True:
            data.loc[(data['probabilityLeft'] == 50), 'block'] = 0
            data.loc[(data['probabilityLeft'] == 20), 'block'] = 1
            data.loc[(data['probabilityLeft'] == 80), 'block'] = -1
        
        # Make choice in between 0 and 1 -> 1 for right and 0 for left
        data.loc[data['choice'] == -1, 'choice'] = 0
        
        index = data['index'].copy()

        # Create predictor matrix
        endog = data['choice'].copy()
        exog = data.copy()
        exog.drop(columns=['index', 'trial_feedback_type', 
                       'signed_contrast', 'choice', 
                           'probabilityLeft'], inplace=True)
        exog = sm.add_constant(exog)
        
        return exog, index


def plot_psychometric(x, y, col, point = False, mark = 'o', al =1):
    # summary stats - average psychfunc over observers
    df = pd.DataFrame({'signed_contrast': x, 'choice': y,
                       'choice2': y})
    df2 = df.groupby(['signed_contrast']).agg(
        {'choice2': 'count', 'choice': 'mean'}).reset_index()
    df2.rename(columns={"choice2": "ntrials",
                        "choice": "fraction"}, inplace=True)
    df2 = df2.groupby(['signed_contrast']).mean().reset_index()
    df2 = df2[['signed_contrast', 'ntrials', 'fraction']]

    # fit psychfunc
    pars, L = psy.mle_fit_psycho(df2.transpose().values,  # extract the data from the df
                                 P_model='erf_psycho_2gammas',
                                 parstart=np.array(
                                     [df2['signed_contrast'].mean(), 20., 0.05, 0.05]),
                                 parmin=np.array(
                                     [df2['signed_contrast'].min(), 5, 0., 0.]),
                                 parmax=np.array([df2['signed_contrast'].max(), 100., 1, 1]))

    # plot psychfunc
    g = sns.lineplot(np.arange(-29, 29),
                     psy.erf_psycho_2gammas(pars, np.arange(-29, 29)), color = col,  
                     alpha = al)

    # plot psychfunc: -100, +100
    sns.lineplot(np.arange(-37, -32),
                 psy.erf_psycho_2gammas(pars, np.arange(-103, -98)), color = col,
                 alpha = al)
    sns.lineplot(np.arange(32, 37),
                 psy.erf_psycho_2gammas(pars, np.arange(98, 103)), color = col,  
                 alpha = al)

    # now break the x-axis
    # if 100 in df.signed_contrast.values and not 50 in
    # df.signed_contrast.values:
    df['signed_contrast'] = df['signed_contrast'].replace(-100, -35)
    df['signed_contrast'] = df['signed_contrast'].replace(100, 35)
    
    if point == True:
        sns.lineplot(df['signed_contrast'], df['choice'], err_style="bars",
                         linewidth=0, linestyle='None', mew=0.5,
                         marker=mark, ci=68, color = col, alpha = al)

    g.set_xticks([-35, -25, -12.5, 0, 12.5, 25, 35])
    g.set_xticklabels(['-100', '-25', '-12.5', '0', '12.5', '25', '100'],
                      size='small', rotation=45)
    g.set_xlim([-40, 40])
    g.set_ylim([0, 1])
    g.set_yticks([0, 0.25, 0.5, 0.75, 1])
    g.set_yticklabels(['0', '25', '50', '75', '100'])
    
    
# FUNCTION UNDER DEVELOPMENT
def updating:
    select =  behav.copy()
    select['signed_contrast-1'] =  select['signed_contrast'].shift(periods=1).to_numpy()
    select['signed_contrast+1'] =  select['signed_contrast'].shift(periods=-1).to_numpy()
    select['t-1'] = select['trial_feedback_type'].shift(periods=1).to_numpy()
    select['t+1'] = select['trial_feedback_type'].shift(periods=-1).to_numpy()
    select = select.iloc[1:-1,:] # First and last trial will have nan for history
    select['t-1']  = select['t-1'].astype(int)
    select['simulation_prob'] = select['simulation_prob']*100
    #select = select.loc[select['signed_contrast-1'] >= 0]
    for mouse in select['subject_nickname'].unique():
        for c in select['signed_contrast-1'].unique():
            for r in select['t-1'].unique():
                sub_select = select.loc[(select['signed_contrast-1'] == c) &
                     (select['t-1'] == r) & (select['subject_nickname'] == mouse)]
                
                fit_result = fit_psychfunc(sub_select)
                select.loc[select['subject_nickname'] == nickname, 'updating'] = \
                fit_result['bias'][0]
        for c in select['signed_contrast+1'].unique():
            for r in select['t+1'].unique():
                sub_select = select.loc[(select['signed_contrast+1'] == c) &
                     (select['t+1'] == r) & (select['subject_nickname'] == mouse)]             
                fit_result = fit_psychfunc(sub_select)
                select.loc[select['subject_nickname'] == nickname, 'updating_correction'] = \
                fit_result['bias'][0]

    sns.lineplot(data = select, hue = 't-1', x = select['signed_contrast-1'],
                 y = select['simulation_prob'], ci = 68)
    
    sns.lineplot(data = select, hue = 't-1', x = select['signed_contrast-1'],
                 y = select[select['probabilityLeft'] == 80],'choice'] - 
                 select.loc[select['probabilityLeft'] == 20 ,'choice'])
                
예제 #13
0
def plot_psychometric(x,
                      y,
                      col,
                      point=False,
                      line=True,
                      mark='.',
                      al=1,
                      ax=None,
                      **kwargs):

    if not ax:
        ax = plt.sca(ax[0])

    # summary stats - average psychfunc over observers
    df = pd.DataFrame({'signed_contrast': x, 'choice': y, 'choice2': y})
    df2 = df.groupby(['signed_contrast']).agg({
        'choice2': 'count',
        'choice': 'mean'
    }).reset_index()
    df2.rename(columns={
        "choice2": "ntrials",
        "choice": "fraction"
    },
               inplace=True)
    df2 = df2.groupby(['signed_contrast']).mean().reset_index()
    df2 = df2[['signed_contrast', 'ntrials', 'fraction']]

    # fit psychfunc
    pars, L = psy.mle_fit_psycho(
        df2.transpose().values,  # extract the data from the df
        P_model='erf_psycho_2gammas',
        parstart=np.array([df2['signed_contrast'].mean(), 20., 0.05, 0.05]),
        parmin=np.array([df2['signed_contrast'].min(), 5, 0., 0.]),
        parmax=np.array([df2['signed_contrast'].max(), 100., 1, 1]))

    if line:
        # plot psychfunc
        sns.lineplot(np.arange(-29, 29),
                     psy.erf_psycho_2gammas(pars, np.arange(-29, 29)),
                     color=col,
                     alpha=al,
                     ax=ax)

        # plot psychfunc: -100, +100
        sns.lineplot(np.arange(-37, -32),
                     psy.erf_psycho_2gammas(pars, np.arange(-103, -98)),
                     color=col,
                     alpha=al,
                     ax=ax)
        sns.lineplot(np.arange(32, 37),
                     psy.erf_psycho_2gammas(pars, np.arange(98, 103)),
                     color=col,
                     alpha=al,
                     ax=ax)

    # now break the x-axis
    # if 100 in df.signed_contrast.values and not 50 in
    # df.signed_contrast.values:
    df['signed_contrast'] = df['signed_contrast'].replace(-100, -35)
    df['signed_contrast'] = df['signed_contrast'].replace(100, 35)

    # PLOT DATAPOINTS
    if point == True:
        sns.lineplot(df['signed_contrast'],
                     df['choice'],
                     err_style="bars",
                     linewidth=0,
                     linestyle='None',
                     mew=0.5,
                     marker=mark,
                     ci=95,
                     color=col,
                     alpha=al,
                     markersize=3,
                     ax=ax)

    ax.set_xticks([-35, -25, -12.5, 0, 12.5, 25, 35])
    ax.set_xticklabels(['-100', ' ', ' ', '0', ' ', ' ', '100'],
                       size='small',
                       rotation=45)
    ax.set_xlim([-40, 40])
    ax.set_ylim([0, 1])
    ax.set_yticks([0, 0.25, 0.5, 0.75, 1])
    ax.set_yticklabels(['0', ' ', '50', ' ', '100'])
예제 #14
0
                                        parmin=np.array([-5, 0., 0., 0.]),
                                        parmax=np.array([5, 100., 1, 1]),
                                        nfits=50)
            fitParams.append(params)
            fitLikes.append(L)
        # find the best params (with the lowest neg likelihood)
        params = fitParams[np.where(min(fitLikes))[0][0]]
        spotBias[i][subIdx] = params[0]
        spotSlope[i][subIdx] = params[1]
        spotLapseLow[i][subIdx] = params[2]
        spotLapseHigh[i][subIdx] = params[3]

        spotFits.append(params)
        #plot the psychometrics
        fitx = np.linspace(-1, 1, 100)
        fity = psychofit.erf_psycho_2gammas(params, fitx)

        line = axs[0,0].plot(fitx, fity, lineColors[plotCount])
        lines.append(line)
        axs[0,0].plot(psychoPlot[0], np.array(psychoPlot[2]), dotColors[plotCount])
        plotCount+=1
    ## Formatting the psychometric figure    
    LvisLine = mpl.lines.Line2D([],[],color='blue',marker='.',label='L Off')
    RvisLine = mpl.lines.Line2D([],[],color='red',marker='.',label='R Off')
    cLine = mpl.lines.Line2D([],[],color='green',marker='.',label='Control Spots')
    ax.legend(handles=[LvisLine,RvisLine,cLine],loc='upper left')
    ax.set_title('Visual Cortex')
    ax.set_ylabel('Proportion CW')
    if len(np.unique(subject['subject'])) == 1:
        fig.suptitle(np.unique(subject['subject'])[0])
    else:
# FOR EACH ANIMAL + for each lab (in 'lab color')
# ================================================================== #

print('fitting psychometric functions...')
pars = behav.groupby(
    ['institution_code', 'subject_nickname',
     'probabilityLeft']).apply(fit_psychfunc).reset_index()
# now read these out at the presented levels of signed contrast
behav2 = pd.DataFrame([])
xvec = behav.signed_contrast.unique()
for index, group in pars.groupby(
    ['institution_code', 'subject_nickname', 'probabilityLeft']):
    # expand
    yvec = psy.erf_psycho_2gammas([
        group.bias.item(),
        group.threshold.item(),
        group.lapselow.item(),
        group.lapsehigh.item()
    ], xvec)
    group2 = group.loc[group.index.repeat(
        len(yvec))].reset_index(drop=True).copy()
    group2['signed_contrast'] = xvec
    group2['choice'] = 100 * yvec

    # add this
    behav2 = behav2.append(group2)

# now subtract these to compute a bias shift
behav3 = pd.pivot_table(
    behav2,
    values='choice',
    index=['institution_code', 'subject_nickname', 'signed_contrast'],
예제 #16
0
def plot_psych_block(psy_df, block_variable, blocks):
    """Plots psychometric using ibl_psychometric
    INPUT:  Dataframe where index = trial and block variable = hue
    block_variable =   name of block struct column (e.g rewprobabilityLeft)
    blocks =  blovks that I want plotted (np.array) (e.g np.array([1, 0.7]))
    OUTPUT:  Average of all sessions, Average of Last three sessions, Last 5 sessions"""

    #First get fits for each block
    #Set frame for plots
    block_summary, axes = plt.subplots(1, 2, sharex=True)
    block_summary.set_figheight(7)
    block_summary.set_figwidth(15)
    plt.sca(axes[0])
    colors = ['blue', 'green']
    sns.set()
    #First get fits for each block
    for j, i in enumerate(blocks):
        psy_df_block = psy_df.loc[psy_df[block_variable] == i]
        pars, L = ibl_psychometric(psy_df_block)

        sns.lineplot(np.arange(-100, 100),
                     psy.erf_psycho_2gammas(pars, np.arange(-100, 100)),
                     color=colors[j])
        sns.lineplot(x='signed_contrasts',
                     y='right_choices',
                     err_style="bars",
                     linewidth=0,
                     linestyle='None',
                     mew=0.5,
                     marker='.',
                     color=colors[j],
                     ci=68,
                     data=psy_df_block)
        #Get sns.lineplot for raw data for each contrast per session
    axes[0].set_xlabel('Signed contrast (%)')
    axes[0].set_ylabel('% Right')
    axes[0].set_title('All sessions')
    #plot average last three session
    dates = sorted(psy_df['ses'].unique())
    psy_df_last3 = psy_df.loc[(psy_df['ses'] == dates[-1]) |
                              (psy_df['ses'] == dates[-2]) |
                              (psy_df['ses'] == dates[-3])]
    plt.sca(axes[1])
    for j, i in enumerate(blocks):
        psy_df_block = psy_df_last3.loc[psy_df_last3[block_variable] == i]
        pars, L = ibl_psychometric(psy_df_block)
        sns.lineplot(np.arange(-100, 100),
                     psy.erf_psycho_2gammas(pars, np.arange(-100, 100)),
                     color=colors[j])
        sns.lineplot(x='signed_contrasts',
                     y='right_choices',
                     err_style="bars",
                     linewidth=0,
                     linestyle='None',
                     mew=0.5,
                     marker='.',
                     color=colors[j],
                     ci=68,
                     data=psy_df_block)
    axes[1].set_xlabel('Signed contrast (%)')
    axes[1].set_title('Last 3 sessions')
    axes[1].set_ylabel('')
    #Now plot last 5 sessions
    plots = len(dates)
    rows = int(np.ceil(plots / 3))
    cols = int(np.ceil(plots / rows))
    all_sessions = plt.figure(figsize=(12, 10))
    sns.set()
    for j, date in enumerate(dates):
        ax = all_sessions.add_subplot(rows, cols, 1 + j)
        ax.set_title(date)
        ax.label_outer()

        for l, i in enumerate(blocks):
            psy_df_block = psy_df.loc[psy_df[block_variable] == i]
            psy_df_block_date = psy_df_block.loc[psy_df_block['ses'] == date]
            pars, L = ibl_psychometric(psy_df_block_date, ax)
            sns.lineplot(np.arange(-100, 100),
                         psy.erf_psycho_2gammas(pars, np.arange(-100, 100)),
                         color=colors[l])
            sns.lineplot(x='signed_contrasts',
                         y='right_choices',
                         err_style="bars",
                         linewidth=0,
                         linestyle='None',
                         mew=0.5,
                         marker='.',
                         color=colors[l],
                         ci=68,
                         data=psy_df_block_date)
            ax.set_label("block %s" % i)
            ax.set_xlabel('Signed contrast (%)')
            ax.set_ylabel('Right choices (%)')
    blue_patch = mpatches.Patch(color='blue',
                                label='P(rew|Left): 1 P(rew|Right): 0.7')
    orange_patch = mpatches.Patch(color='green',
                                  label='P(rew|Left): 0.7 P(rew|Right): 1')
    plt.legend(handles=[blue_patch, orange_patch], loc='lower right')
    ax.set_xlabel('Signed contrast (%)')

    return block_summary, all_sessions
예제 #17
0
def plot_psychos_from_spots(spotlists, psychoSpotData, spots, labels):
    """
        Function to plot three psychometrics on a single plot, with the dots that they were 
        generated with. usually I'll use this with a group of left spots, a group of right spots
        and a group of control spots.

        Inputs:
        spotlists: a list of length 3 that has the spots 

    """
    Psycho1 = [[],[0 for i in range(len(psychoSpotData[0][1]))],[np.nan for i in range(len(psychoSpotData[0][1]))]]
    Psycho2 = [[],[0 for i in range(len(psychoSpotData[0][1]))],[np.nan for i in range(len(psychoSpotData[0][1]))]]
    controlSpotPsycho = [[],[0 for i in range(len(psychoSpotData[0][1]))],[np.nan for i in range(len(psychoSpotData[0][1]))]]

    for i in range(len(spots)):
        spotX = spots.iloc[i, [0]][0]
        spotY = spots.iloc[i, [1]][0]
        for leftSpots in range(len(visLeftSpots)):
            if spotX == visLeftSpots[leftSpots][0] and spotY == visLeftSpots[leftSpots][1]:
                Psycho1[0] = psychoSpotData[i][0]
                Psycho1[1] = [i+j for i,j in zip(psychoSpotData[i][1],Psycho1[1])]
                Psycho1[2] = [np.nanmean([i,j]) for i,j in zip(psychoSpotData[i][2],Psycho1[2])]
        for rightSpots in range(len(visRightSpots)):
            if spotX == visRightSpots[rightSpots][0] and spotY == visRightSpots[rightSpots][1]:
                Psycho2[0] = psychoSpotData[i][0]
                Psycho2[1] = [i+j for i,j in zip(psychoSpotData[i][1],Psycho2[1])]
                Psycho2[2] = [np.nanmean([i,j]) for i,j in zip(psychoSpotData[i][2],Psycho2[2])]
        for ii in controlSpots:
            if spotX == spots.iloc[ii][0] and spotY == spots.iloc[ii][1]:
                controlSpotPsycho[0] = psychoSpotData[ii][0]
                controlSpotPsycho[1] = [i+j for i,j in zip(psychoSpotData[ii][1],controlSpotPsycho[1])]
                controlSpotPsycho[2] = [np.nanmean([i,j]) for i,j in zip(psychoSpotData[ii][2],controlSpotPsycho[2])] 
                       
        


        ## plotting psychometrics for different cortical groups
    lines = []
    print('Fitting psychometrics, {}/{} Done'.format(subIdx,len(data)))
    fig = plt.figure()
    dotColors = ['.b','.r','.g']
    lineColors = ['-b','-r','-g']
    plotCount = 0
    for psychoPlot in [Psycho1, Psycho2, controlSpotPsycho]:
        fitParams = []
        fitLikes = []
        for repeat in range(10):
            params, L = psychofit.mle_fit_psycho(psychoPlot,
                                        P_model='erf_psycho_2gammas',
                                        parstart=np.array([0,20,.05,.05]),
                                        parmin=np.array([-5, 0., 0., 0.]),
                                        parmax=np.array([5, 100., 1, 1]),
                                        nfits=50)
            fitParams.append(params)
            fitLikes.append(L)
        # find the best params (with the lowest neg likelihood)
        params = fitParams[np.where(min(fitLikes))[0][0]]
        spotBias[i][subIdx] = params[0]
        spotSlope[i][subIdx] = params[1]
        spotLapseLow[i][subIdx] = params[2]
        spotLapseHigh[i][subIdx] = params[3]

        spotFits.append(params)
        #plot the psychometrics
        fitx = np.linspace(-1, 1, 100)
        fity = psychofit.erf_psycho_2gammas(params, fitx)

        line = plt.plot(fitx, fity, lineColors[plotCount])
        lines.append(line)
        plt.plot(psychoPlot[0], np.array(psychoPlot[2]), dotColors[plotCount])
        plotCount+=1
    ## Formatting the psychometric figure    
    LvisLine = mpl.lines.Line2D([],[],color='blue',marker='.',label=labels[0])
    RvisLine = mpl.lines.Line2D([],[],color='red',marker='.',label=labels[1])
    cLine = mpl.lines.Line2D([],[],color='green',marker='.',label=labels[2])
    plt.legend(handles=[LvisLine,RvisLine,cLine])