def reaction_times_second_step(sessions, fig_no = 1): 'Reaction times for second step pokes as function of common / rare transition.' sec_step_IDs = ut.get_IDs(sessions[0].IDs, ['right_active', 'left_active']) median_RTs_common = np.zeros(len(sessions)) median_RTs_rare = np.zeros(len(sessions)) for i,session in enumerate(sessions): event_times = ut.get_event_times(session.time_stamps, session.event_codes, session.IDs) left_active_times = event_times['left_active'] right_active_times = event_times['right_active'] left_reaction_times = _latencies(left_active_times, event_times['left_poke']) right_reaction_times = _latencies(right_active_times, event_times['right_poke']) ordered_reaction_times = np.hstack((left_reaction_times,right_reaction_times))\ [np.argsort(np.hstack((left_active_times,right_active_times)))] transitions = session.blocks['trial_trans_state'] == session.CTSO['transitions'] # common vs rare. median_RTs_common[i] = np.median(ordered_reaction_times[ transitions]) median_RTs_rare[i] = np.median(ordered_reaction_times[~transitions]) mean_RT_common = 1000 * np.mean(median_RTs_common) mean_RT_rare = 1000 * np.mean(median_RTs_rare) SEM_RT_common = 1000 * np.sqrt(np.var(median_RTs_common/len(sessions))) SEM_RT_rare = 1000 * np.sqrt(np.var(median_RTs_rare /len(sessions))) p.figure(fig_no) p.bar([1,2],[mean_RT_common, mean_RT_rare], yerr = [SEM_RT_common,SEM_RT_rare]) p.xlim(0.8,3) p.ylim(mean_RT_common * 0.8, mean_RT_rare * 1.1) p.xticks([1.4, 2.4], ['Common', 'Rare']) p.title('Second step reaction times') p.ylabel('Reaction time (ms)') print('Paired t-test P value: {}'.format(ttest_rel(median_RTs_common, median_RTs_rare)[1]))
def successful_delay_fraction(session): 'Evaluates fraction of trials on which animal witholds central poking during ITI' assert 'ITI_start' in session.IDs.keys(), 'Session does not have inter-trial interval' event_IDs = ut.get_IDs(session.IDs, ['low_poke','high_poke', 'trial_start', 'ITI_start']) ev_seq = [ev for ev in session.event_codes if ev in event_IDs] ev_seq.append(-1) # To avoid index out of range errors at next line. events_following_ITI_start = [ev_seq[i+1] for i, x in enumerate(ev_seq) if x == session.IDs['ITI_start']] return np.mean(np.array(events_following_ITI_start) == session.IDs['trial_start'])
def pokes_per_min(session, plot_pos = []): setup_axis(plot_pos) poke_IDs = ut.get_IDs(session.IDs, ['low_poke','high_poke', 'left_poke', 'right_poke']) poke_times = session.time_stamps[ut.array_contains(poke_IDs, session.event_codes)]/60 bin_edges = np.arange(0,np.ceil(poke_times.max())+1) pokes_per_min = np.histogram(poke_times, bin_edges)[0] p.plot(bin_edges[0:-1]+0.5,pokes_per_min) p.xlabel('Time (minutes)')
def poke_poke_corrlations(IDs, event_codes, plot_pos = []): 'Poke probability as function of previous poke.' poke_IDs = ut.get_IDs(IDs, ['low_poke','high_poke', 'left_poke', 'right_poke']) poke_sequence = event_codes[ut.array_contains(poke_IDs, event_codes)] poke_pairs = zip(poke_sequence[0:-1],poke_sequence[1::]) k = {IDs['high_poke']: 0,IDs['low_poke']: 1, IDs['left_poke']: 2,IDs['right_poke']: 3} poke_counts = np.zeros([4,4]) for poke, next_poke in poke_pairs: poke_counts[k[poke],k[next_poke]] += 1 poke_probs = poke_counts / np.tile(np.sum(poke_counts,1)[np.newaxis].T,(1,4)) if setup_axis(plot_pos): p.imshow(poke_probs,cmap=p.cm.copper,interpolation='nearest') p.colorbar() p.xticks([0,1,2,3],['High','Low','Left','Right']) p.yticks([0,1,2,3],['High','Low','Left','Right']) p.xlabel('Poke t + 1') p.ylabel('Poke t') else: return poke_probs
def log_IPI(session, plot_pos = []): 'Log inter-poke interval distribution.' setup_axis(plot_pos) poke_IDs = ut.get_IDs(session.IDs, ['low_poke','high_poke', 'left_poke', 'right_poke']) poke_times = session.time_stamps[ut.array_contains(poke_IDs, session.event_codes)] log_IPIs = np.log(poke_times[1::]-poke_times[0:-1]) poke_events = session.event_codes[ut.array_contains(poke_IDs, session.event_codes)] repeated_poke_log_IPIs = log_IPIs[poke_events[1::] == poke_events[0:-1]] bin_edges = np.arange(-1.7,7.6,0.1) log_IPI_hist = np.histogram(log_IPIs, bin_edges)[0] rep_poke_log_IPI_hist = np.histogram(repeated_poke_log_IPIs, bin_edges)[0] mode_IPI = np.exp(bin_edges[np.argmax(log_IPI_hist)]+0.05) if setup_axis(plot_pos): p.plot(bin_edges[0:-1]+0.05,log_IPI_hist) p.plot(bin_edges[0:-1]+0.05,rep_poke_log_IPI_hist,'r') p.xlim(bin_edges[0],bin_edges[-1]) p.xticks(np.log([0.25,1,4,16,64,256]),[0.25,1,4,16,64,256]) p.xlabel('Inter-poke interval (sec)') else: return (mode_IPI, log_IPI_hist, bin_edges[0:-1]+0.05)
def make_CTSO_representation(self): """ Create choice, transition, second_step, outcome representation of session used for stay probability analysis and various plotting functions. Algorithm works by keeping track of the state the task is in, updating this estimate when relevent events happen, and appending choices, tranistions and outcomes when these are detected. It is possible for events to appear to occur out of sequence, e.g a second link state entry occuring imediately after a trial start event, without an intervening poke. This can happen due to event queing in the framework that runs the task as follows: 1. Timer event occurs and is placed in que. 2. Poke occurs and is placed in que. 3. Timer event is processed, causing state transition. 4. Poke event is processed in new state. When this sequence of events occurs the poke appears in the event list before the state transition, but is processed in the state following the transition. The signature of this happening is a seemingly impossible series of state transitions preceded at a very small time interval by a poke event. """ choices = [] # True if high poke, flase if low poke. transitions = [] # True if high --> left or low --> right (A type), # flase if high --> right or low --> left (B type). second_steps = [] # True if left, false if right. outcomes = [] # True if rewarded, flase if no reward. event_list = [ "trial_start", "low_poke", "high_poke", "left_active", "right_active", "left_reward", "right_reward", ] state = "I" # C = choose, T = transition, O = outcome, I = inter-trial-interval. state_IDs = { "C": ut.get_IDs(self.IDs, ["low_poke", "high_poke"]), "T": ut.get_IDs(self.IDs, ["left_active", "right_active"]), "O": ut.get_IDs(self.IDs, ["left_reward", "right_reward", "trial_start"]), "I": ut.get_IDs(self.IDs, ["trial_start"]), } self.trial_start_inds = [] for i, ev in enumerate(self.event_codes): if ev in state_IDs[state]: # Relevent event has occured. if state == "C": choices.append(ev == self.IDs["high_poke"]) state = "T" elif state == "T": transitions.append(choices[-1] == (ev == self.IDs["left_active"])) second_steps.append(ev == self.IDs["left_active"]) state = "O" elif state == "O": outcomes.append((ev == self.IDs["left_reward"]) or (ev == self.IDs["right_reward"])) if ev == self.IDs["trial_start"]: state = "C" self.trial_start_inds.append(i) else: state = "I" elif state == "I": state = "C" self.trial_start_inds.append(i) elif ev == self.IDs["trial_start"]: # Trial start event occurred out of sequence, print error message but ignore event. print( "Out of sequence trial start, current state: {}, event #: {}, TS: {}".format( state, i, 1000 * self._raw_time_stamps[i] ) ) elif ev in ut.get_IDs(self.IDs, ["left_active", "right_active"]): # Second link state entry occured out of sequence. if (ignored_event in ut.get_IDs(self.IDs, ["low_poke", "high_poke"])) & (state == "C"): # Trial start was logged after central poke that triggered transition to second link state. choices.append(ignored_event == self.IDs["high_poke"]) transitions.append(choices[-1] == (ev == self.IDs["left_active"])) second_steps.append(ev == self.IDs["left_active"]) state = "O" else: print( "Out of sequence second link state, current state: {}, event #: {}, TS: {}".format( state, i, 1000 * self._raw_time_stamps[i] ) ) elif ev in ut.get_IDs(self.IDs, ["left_reward", "right_reward"]): # Reward occured out of sequence. print( "Out of sequence reward, current state: {}, event #: {}, TS: {}".format( state, i, 1000 * self._raw_time_stamps[i] ) ) else: ignored_event = ev ingnored_event_time = self.time_stamps[i] self.CTSO = { "choices": np.array(choices[0 : len(outcomes)], int), # Store as integer arrays. "transitions": np.array(transitions[0 : len(outcomes)], int), "second_steps": np.array(second_steps[0 : len(outcomes)], int), "outcomes": np.array(outcomes, int), } n_trial_starts = sum(self.event_codes == self.IDs["trial_start"]) assert ( n_trial_starts - 1 <= len(outcomes) <= n_trial_starts ), "Incorrect number of trials found by make_CTSO_representation." self.n_trials = len(outcomes)