def psychometric_function(trialsfile, plot=None, threshold=False, **kwargs): """ Compute and plot the sychometric function. """ # Load trials trials, ntrials = load_trials(trialsfile) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- choice_by_coh = {} ntot = 0 ncorrect = 0 for trial in trials: info = trial['info'] # Signed coherence coh = info['in_out'] * info['coh'] # Choice choice = get_choice(trial, threshold) if choice is None: continue if coh != 0: ntot += 1 if isinstance(choice, tuple): choice, _ = choice choice_by_coh.setdefault(coh, []).append(choice) # Correct if coh != 0 and choice == info['choice']: ncorrect += 1 # Report overall performance pcorrect = 100 * ncorrect / ntot print("[ {}.psychometric_function ] {}/{} = {:.2f}% correct.".format( THIS, ncorrect, ntot, pcorrect)) cohs = np.sort(np.array(choice_by_coh.keys())) p0 = np.zeros(len(cohs)) for i, coh in enumerate(cohs): choices = np.array(choice_by_coh[coh]) p0[i] = 1 - np.sum(choices) / len(choices) scaled_cohs = SCALE * cohs #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plot is not None: # Data prop = { 'ms': kwargs.get('ms', 6), 'mfc': kwargs.get('mfc', '0.2'), 'mew': kwargs.get('mew', 0), 'zorder': 10 } plot.plot(scaled_cohs, 100 * p0, 'o', **prop) # Fit prop = { 'color': kwargs.get('mfc', '0.2'), 'lw': kwargs.get('lw', 1), 'zorder': 5 } try: popt, func = fittools.fit_psychometric(scaled_cohs, p0) fit_cohs = np.linspace(min(scaled_cohs), max(scaled_cohs), 201) fit_p0 = func(fit_cohs, **popt) plot.plot(fit_cohs, 100 * fit_p0, **prop) except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(scaled_cohs, 100 * p0, **prop) plot.ylim(0, 100) plot.yticks([0, 25, 50, 75, 100]) plot.lim('x', scaled_cohs)
def psychometric_function(trialsfile, plots=None, **kwargs): """ Psychometric function. """ # Load trials trials, ntrials = load_trials(trialsfile) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- results = {cond: {} for cond in ['mm', 'mc', 'cm', 'cc']} ncorrect = 0 for trial in trials: info = trial['info'] coh_m = info['left_right_m'] * info['coh_m'] coh_c = info['left_right_c'] * info['coh_c'] choice = get_choice(trial) if choice == info['choice']: ncorrect += 1 if info['context'] == 'm': results['mm'].setdefault(coh_m, []).append(choice) results['mc'].setdefault(coh_c, []).append(choice) else: results['cm'].setdefault(coh_m, []).append(choice) results['cc'].setdefault(coh_c, []).append(choice) print("[ {}.psychometric_function ] {:.2f}% correct.".format( THIS, 100 * ncorrect / ntrials)) for cond in results: choice_by_coh = results[cond] cohs = np.sort(np.array(choice_by_coh.keys())) p0 = np.zeros(len(cohs)) for i, coh in enumerate(cohs): choices = np.array(choice_by_coh[coh]) p0[i] = 1 - np.sum(choices) / len(choices) scaled_cohs = SCALE * cohs results[cond] = (scaled_cohs, p0) #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plots is not None: ms = kwargs.get('ms', 5) color_m = '0.2' color_c = Figure.colors('darkblue') for cond, result in results.items(): # Context if cond[0] == 'm': color = color_m label = 'Motion context' else: color = color_c label = 'Color context' # Stimulus if cond[1] == 'm': plot = plots['m'] else: plot = plots['c'] # Result scaled_cohs, p0 = result # Data points plot.plot(scaled_cohs, 100 * p0, 'o', ms=ms, mew=0, mfc=color, zorder=10) # Fit try: popt, func = fittools.fit_psychometric(scaled_cohs, p0) fit_cohs = np.linspace(min(scaled_cohs), max(scaled_cohs), 201) fit_p0 = func(fit_cohs, **popt) plot.plot(fit_cohs, 100 * fit_p0, color=color, lw=1, zorder=5, label=label) except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(scaled_cohs, 100 * p0, color=color, lw=1, zorder=5, label=label) plot.lim('x', scaled_cohs) plot.ylim(0, 100) #------------------------------------------------------------------------------------- return results
def psychometric_function(trialsfile, plot=None, **kwargs): """ Compute and plot the sychometric function. """ # Load trials with open(trialsfile) as f: trials = pickle.load(f) ntrials = len(trials) # Get modalities mods = list(set([trial['info']['modality'] for trial in trials])) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- results = {mod: {} for mod in mods} ncorrect_by_mod = {mod: 0 for mod in mods} ntrials_by_mod = {mod: 0 for mod in mods} for trial in trials: # Condition info = trial['info'] mod = info['modality'] freq = info['freq'] ntrials_by_mod[mod] += 1 # Choice choice = get_choice(trial) results[mod].setdefault(freq, []).append(choice) # Correct if choice == info['choice']: ncorrect_by_mod[mod] += 1 # Report overall performance pcorrect_by_mod = {mod: 100*ncorrect_by_mod[mod]/ntrials_by_mod[mod] for mod in mods} print("[ {}.psychometric_function ]".format(THIS)) print(" v {:.2f}% correct.".format(pcorrect_by_mod['v'])) print(" a {:.2f}% correct.".format(pcorrect_by_mod['a'])) print(" va {:.2f}% correct.".format(pcorrect_by_mod['va'])) # Psychometric function for mod in mods: choice_by_freq = results[mod] freqs = np.sort(np.array(choice_by_freq.keys())) p0 = np.zeros(len(freqs)) for i, freq in enumerate(freqs): choices = np.array(choice_by_freq[freq]) p0[i] = 1 - np.sum(choices)/len(choices) results[mod] = (freqs, p0) #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plot is not None: sigmas = {} for mod in ['v', 'a', 'va']: freqs, p0 = results[mod] # Data prop = {'ms': kwargs.get('ms', 6), 'mfc': kwargs.get('mfc', colors[mod]), 'mew': kwargs.get('mew', 0), 'zorder': 10} plot.plot(freqs, 100*p0, 'o', **prop) if mod == 'v': label = 'Visual' elif mod == 'a': label = 'Auditory' elif mod == 'va': label = 'Multisensory' else: raise ValueError(" [ {}.psychometric_function ] Unknown modality.". format(THIS)) # Fit prop = {'color': kwargs.get('mfc', colors[mod]), 'lw': kwargs.get('lw', 1), 'label': label, 'zorder': 5} try: popt, func = fittools.fit_psychometric(freqs, p0) fit_freqs = np.linspace(min(freqs), max(freqs), 201) fit_p0 = func(fit_freqs, **popt) plot.plot(fit_freqs, 100*fit_p0, **prop) sigmas[mod] = popt['sigma'] except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(freqs, 100*p0, **prop) plot.ylim(0, 100) plot.yticks([0, 25, 50, 75, 100]) plot.lim('x', freqs) # Is it optimal? print("") print(" Optimality test") print(" ---------------") for mod in ['v', 'a', 'va']: print(" sigma_{:<2} = {:.6f}".format(mod, sigmas[mod])) print(" 1/sigma_v**2 + 1/sigma_a**2 = {:.6f}" .format(1/sigmas['v']**2 + 1/sigmas['a']**2)) print(" 1/sigma_va**2 = {:.6f}".format(1/sigmas['va']**2))
def psychometric_function(trialsfile, plot=None, **kwargs): """ Compute and plot the sychometric function. """ # Load trials with open(trialsfile) as f: trials = pickle.load(f) ntrials = len(trials) # Get modalities mods = list(set([trial['info']['modality'] for trial in trials])) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- results = {mod: {} for mod in mods} ncorrect_by_mod = {mod: 0 for mod in mods} ntrials_by_mod = {mod: 0 for mod in mods} for trial in trials: # Condition info = trial['info'] mod = info['modality'] freq = info['freq'] ntrials_by_mod[mod] += 1 # Choice choice = get_choice(trial) results[mod].setdefault(freq, []).append(choice) # Correct if choice == info['choice']: ncorrect_by_mod[mod] += 1 # Report overall performance pcorrect_by_mod = { mod: 100 * ncorrect_by_mod[mod] / ntrials_by_mod[mod] for mod in mods } print("[ {}.psychometric_function ]".format(THIS)) print(" v {:.2f}% correct.".format(pcorrect_by_mod['v'])) print(" a {:.2f}% correct.".format(pcorrect_by_mod['a'])) print(" va {:.2f}% correct.".format(pcorrect_by_mod['va'])) # Psychometric function for mod in mods: choice_by_freq = results[mod] freqs = np.sort(np.array(choice_by_freq.keys())) p0 = np.zeros(len(freqs)) for i, freq in enumerate(freqs): choices = np.array(choice_by_freq[freq]) p0[i] = 1 - np.sum(choices) / len(choices) results[mod] = (freqs, p0) #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plot is not None: sigmas = {} for mod in ['v', 'a', 'va']: freqs, p0 = results[mod] # Data prop = { 'ms': kwargs.get('ms', 6), 'mfc': kwargs.get('mfc', colors[mod]), 'mew': kwargs.get('mew', 0), 'zorder': 10 } plot.plot(freqs, 100 * p0, 'o', **prop) if mod == 'v': label = 'Visual' elif mod == 'a': label = 'Auditory' elif mod == 'va': label = 'Multisensory' else: raise ValueError( " [ {}.psychometric_function ] Unknown modality.".format( THIS)) # Fit prop = { 'color': kwargs.get('mfc', colors[mod]), 'lw': kwargs.get('lw', 1), 'label': label, 'zorder': 5 } try: popt, func = fittools.fit_psychometric(freqs, p0) fit_freqs = np.linspace(min(freqs), max(freqs), 201) fit_p0 = func(fit_freqs, **popt) plot.plot(fit_freqs, 100 * fit_p0, **prop) sigmas[mod] = popt['sigma'] except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(freqs, 100 * p0, **prop) plot.ylim(0, 100) plot.yticks([0, 25, 50, 75, 100]) plot.lim('x', freqs) # Is it optimal? print("") print(" Optimality test") print(" ---------------") for mod in ['v', 'a', 'va']: print(" sigma_{:<2} = {:.6f}".format(mod, sigmas[mod])) print(" 1/sigma_v**2 + 1/sigma_a**2 = {:.6f}".format( 1 / sigmas['v']**2 + 1 / sigmas['a']**2)) print(" 1/sigma_va**2 = {:.6f}".format(1 / sigmas['va']**2))
def psychometric_function(trialsfile, plot=None, threshold=False, **kwargs): """ Compute and plot the sychometric function. """ # Load trials trials, ntrials = load_trials(trialsfile) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- choice_by_coh = {} ntot = 0 ncorrect = 0 for trial in trials: info = trial['info'] # Signed coherence coh = info['in_out']*info['coh'] # Choice choice = get_choice(trial, threshold) if choice is None: continue if coh != 0: ntot += 1 if isinstance(choice, tuple): choice, _ = choice choice_by_coh.setdefault(coh, []).append(choice) # Correct if coh != 0 and choice == info['choice']: ncorrect += 1 # Report overall performance pcorrect = 100*ncorrect/ntot print("[ {}.psychometric_function ] {}/{} = {:.2f}% correct." .format(THIS, ncorrect, ntot, pcorrect)) cohs = np.sort(np.array(choice_by_coh.keys())) p0 = np.zeros(len(cohs)) for i, coh in enumerate(cohs): choices = np.array(choice_by_coh[coh]) p0[i] = 1 - np.sum(choices)/len(choices) scaled_cohs = SCALE*cohs #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plot is not None: # Data prop = {'ms': kwargs.get('ms', 6), 'mfc': kwargs.get('mfc', '0.2'), 'mew': kwargs.get('mew', 0), 'zorder': 10} plot.plot(scaled_cohs, 100*p0, 'o', **prop) # Fit prop = {'color': kwargs.get('mfc', '0.2'), 'lw': kwargs.get('lw', 1), 'zorder': 5} try: popt, func = fittools.fit_psychometric(scaled_cohs, p0) fit_cohs = np.linspace(min(scaled_cohs), max(scaled_cohs), 201) fit_p0 = func(fit_cohs, **popt) plot.plot(fit_cohs, 100*fit_p0, **prop) except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(scaled_cohs, 100*p0, **prop) plot.ylim(0, 100) plot.yticks([0, 25, 50, 75, 100]) plot.lim('x', scaled_cohs)
def psychometric_function(trialsfile, plots=None, **kwargs): """ Psychometric function. """ # Load trials trials, ntrials = load_trials(trialsfile) #------------------------------------------------------------------------------------- # Compute psychometric function #------------------------------------------------------------------------------------- results = {cond: {} for cond in ['mm', 'mc', 'cm', 'cc']} ncorrect = 0 for trial in trials: info = trial['info'] coh_m = info['left_right_m']*info['coh_m'] coh_c = info['left_right_c']*info['coh_c'] choice = get_choice(trial) if choice == info['choice']: ncorrect += 1 if info['context'] == 'm': results['mm'].setdefault(coh_m, []).append(choice) results['mc'].setdefault(coh_c, []).append(choice) else: results['cm'].setdefault(coh_m, []).append(choice) results['cc'].setdefault(coh_c, []).append(choice) print("[ {}.psychometric_function ] {:.2f}% correct." .format(THIS, 100*ncorrect/ntrials)) for cond in results: choice_by_coh = results[cond] cohs = np.sort(np.array(choice_by_coh.keys())) p0 = np.zeros(len(cohs)) for i, coh in enumerate(cohs): choices = np.array(choice_by_coh[coh]) p0[i] = 1 - np.sum(choices)/len(choices) scaled_cohs = SCALE*cohs results[cond] = (scaled_cohs, p0) #------------------------------------------------------------------------------------- # Plot #------------------------------------------------------------------------------------- if plots is not None: ms = kwargs.get('ms', 5) color_m = '0.2' color_c = Figure.colors('darkblue') for cond, result in results.items(): # Context if cond[0] == 'm': color = color_m label = 'Motion context' else: color = color_c label = 'Color context' # Stimulus if cond[1] == 'm': plot = plots['m'] else: plot = plots['c'] # Result scaled_cohs, p0 = result # Data points plot.plot(scaled_cohs, 100*p0, 'o', ms=ms, mew=0, mfc=color, zorder=10) # Fit try: popt, func = fittools.fit_psychometric(scaled_cohs, p0) fit_cohs = np.linspace(min(scaled_cohs), max(scaled_cohs), 201) fit_p0 = func(fit_cohs, **popt) plot.plot(fit_cohs, 100*fit_p0, color=color, lw=1, zorder=5, label=label) except RuntimeError: print("[ {}.psychometric_function ]".format(THIS) + " Unable to fit, drawing a line through the points.") plot.plot(scaled_cohs, 100*p0, color=color, lw=1, zorder=5, label=label) plot.lim('x', scaled_cohs) plot.ylim(0, 100) #------------------------------------------------------------------------------------- return results