def compute_choice_grasp_dur(LogDf, SessionDf): " FIXME - LAST CHOICE GRASP DUR IS NEVER COMPUTED SINCE THERE IS NO TRIAL AVAILABLE" # Trials spanning from choice available to end of ITI TrialSpans = bhv.get_spans_from_names(LogDf, "CHOICE_STATE", "TRIAL_AVAILABLE_STATE") TrialDfs = [] for i, row in TrialSpans.iterrows(): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) # Compute grasp_dur for every trial grasp_dur = pd.Series() for TrialDf in TrialDfs: if has_choice(TrialDf).values: left_reach_spansDf = bhv.get_spans_from_names(TrialDf, 'REACH_LEFT_ON', 'REACH_LEFT_OFF') right_reach_spansDf = bhv.get_spans_from_names(TrialDf, 'REACH_RIGHT_ON', 'REACH_RIGHT_OFF') merge_spansDf = pd.concat([left_reach_spansDf, right_reach_spansDf]).reset_index(drop = True) choice_time = bhv.get_events_from_name(TrialDf, 'CHOICE_EVENT')['t'].values[0] # Which reach triggered the choice? The one which corresponding spansDf contains choice_time for row in merge_spansDf.iterrows(): if (row[1]['t_on'] < choice_time < row[1]['t_off']): grasp_dur = grasp_dur.append(pd.Series(row[1]['dt'])) else: grasp_dur = grasp_dur.append(pd.Series(np.NaN)) # FIXME Adding last trial manually grasp_dur = grasp_dur.append(pd.Series(np.NaN)) SessionDf['grasp_dur'] = grasp_dur.reset_index(drop = True) return SessionDf
def plot_trajectories_with_marker(LogDf, SessionDf, labelsDf, align_event, pre, post, animal_id, axes=None): " Plots trajectories from align event until choice with marker" if axes is None: _, axes = plt.subplots() ts_align = LogDf.loc[LogDf['name'] == align_event, 't'].values[0] left_paw, right_paw = [], [] for t_align in ts_align: lDf = bhv.time_slice(labelsDf, t_align - pre, t_align + post) #left_paw.append(lDf['x'].values) #right_paw.append(lDf['y'].values) #Fx = np.array(Fx).T #Fy = np.array(Fy).T return axes
def get_SessionDf(LogDf, metrics, trial_entry_event="TRIAL_AVAILABLE_STATE", trial_exit_event="ITI_STATE"): TrialSpans = bhv.get_spans_from_names(LogDf, trial_entry_event, trial_exit_event) TrialDfs = [] for i, row in tqdm(TrialSpans.iterrows(),position=0, leave=True): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) SessionDf = bhv.parse_trials(TrialDfs, metrics) return SessionDf, TrialDfs
def reaches_during_delay_across_sess(animal_fd_path, tasks_names, init_day_idx): SessionsDf = utils.get_sessions(animal_fd_path) animal_meta = pd.read_csv(animal_fd_path / 'animal_meta.csv') # Filter sessions to the ones of the task we want to see FilteredSessionsDf = pd.concat( [SessionsDf.groupby('task').get_group(name) for name in tasks_names]) log_paths = [ Path(path) / 'arduino_log.txt' for path in FilteredSessionsDf['path'] ] fig, axes = plt.subplots(ncols=2, figsize=[6, 4], sharey=True, sharex=True) colors = sns.color_palette(palette='turbo', n_colors=len(log_paths)) for j, log_path in enumerate(log_paths[init_day_idx:]): LogDf = bhv.get_LogDf_from_path(log_path) # ADD SINGLE GO_CUE_EVENT LogDf = bhv.add_go_cue_LogDf(LogDf) TrialSpans = bhv.get_spans_from_names(LogDf, "TRIAL_ENTRY_STATE", "ITI_STATE") TrialDfs = [] for i, row in tqdm(TrialSpans.iterrows(), position=0, leave=True): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) metrics = (met.get_start, met.get_stop, met.get_correct_side, met.get_outcome, met.get_interval_category, met.get_chosen_side, met.has_reach_left, met.has_reach_right) SessionDf = bhv.parse_trials(TrialDfs, metrics) CDF_of_reaches_during_delay(SessionDf, TrialDfs, axes=axes, color=colors[j], alpha=0.75, label='day ' + str(j + 1)) fig.suptitle('CDF of first reach split on trial type \n' + animal_meta['value'][5] + '-' + animal_meta['value'][0]) axes[0].set_ylabel('Fraction of trials') axes[0].legend(frameon=False, fontsize='x-small') fig.tight_layout() return axes
def plot_reaches_window_aligned_on_event(LogDf, align_event, pre, post, bin_width, axes=None): " Plots the reaches around a [-pre,post] window aligned to an event " if axes is None: fig, axes = plt.subplots() no_bins = round((post + pre) / bin_width) t_aligns = LogDf[LogDf['name'] == align_event]['t'] left_reaches, right_reaches = np.empty([1, 0]), np.empty([1, 0]) for t_align in t_aligns: sliceDf = bhv.time_slice(LogDf, t_align - pre, t_align + post) left_reaches = np.append( left_reaches, bhv.get_events_from_name(sliceDf, 'REACH_LEFT_ON').values - np.array(t_align)) right_reaches = np.append( right_reaches, bhv.get_events_from_name(sliceDf, 'REACH_RIGHT_ON').values - np.array(t_align)) # Fancy plotting axes.hist(left_reaches, bins=no_bins, range=(-pre, post), alpha=0.5, label='Left reaches') axes.hist(right_reaches, bins=no_bins, range=(-pre, post), alpha=0.5, label='Right reaches') plt.setp(axes, xticks=np.arange(-pre, post + 1, 1000), xticklabels=np.arange(-pre / 1000, post / 1000 + 0.1, 1)) axes.axvline(x=0, c='black') axes.set_xlabel('Time (s)') axes.set_ylabel('No. Reaches') axes.set_title(str(align_event)) axes.legend() return axes
def plot_all_trajectories(TrialDfs, ax=None): for i, TrialDf in enumerate(TrialDfs): if TrialDf.shape[0] > 0: t_on = TrialDf.iloc[0]['t'] t_off = TrialDf.iloc[-1]['t'] # trial by trial colors bp_cols = {} cmaps = dict(zip(bodyparts,['viridis','magma'])) for bp in bodyparts: c = sns.color_palette(cmaps[bp],as_cmap=True)(sp.rand()) bp_cols[bp] = c # marker for the start frame_ix = Sync.convert(t_on, 'arduino', 'dlc').round().astype('int') dlc.plot_bodyparts(bodyparts, DlcDf, frame_ix, colors=bp_cols, axes=ax, markersize=5) # the trajectory DlcDfSlice = bhv.time_slice(DlcDf, t_on, t_off) dlc.plot_trajectories(DlcDfSlice, bodyparts, colors=bp_cols, axes=ax, lw=0.75, alpha=0.5, p=0.8)
def get_LC_slice_aligned_on_event(LoadCellDf, TrialDfs, align_event, pre, post): " Returns NUMPY ND.ARRAY of all trials aligned to an event in a window defined by [align-pre, align+post]" X, Y = [], [] for TrialDf in TrialDfs: t_align = TrialDf.loc[TrialDf['name'] == align_event, 't'].values[0] LCDf = bhv.time_slice(LoadCellDf, t_align - pre, t_align + post) # slice around reference event # Store X.append(LCDf['x'].values) Y.append(LCDf['y'].values) # Turn into numpy arrays X = np.array(X, dtype=object).T Y = np.array(Y, dtype=object).T return X, Y
def get_dist_aligned_on_event(DlcDf, TrialDfs, align_event, pre, post, func, f_arg1, f_arg2): """ Returns dist for func and args for all trials aligned to an event in a window defined by [align-pre, align+post] NOTE: we are returning NP nd.arrays so we use advanced slicing, meaning [row, col] instead of [row][col] """ dist = [] for TrialDf in TrialDfs: # Get time point of align_event t_align = TrialDf.loc[TrialDf['name'] == align_event, 't'].values[0] # Slice DlcDf and compute distance according to input func and args Dlc_TrialDf = bhv.time_slice(DlcDf, t_align - pre, t_align + post) dist.append(func(Dlc_TrialDf, f_arg1, f_arg2, filter=True)) # Fix the fact that some arrays have different lengths (due to frame rate fluctuations) dist = truncate_pad_vector(dist) return dist
def get_dist_between_events(DlcDf, TrialDfs, first_event, second_event, func, f_arg1, f_arg2, pad_with=None): """ Returns Fx/Fy/Fmag NUMPY ND.ARRAY with dimensions (trials, max_array_len) for all trials NOTE: we are returning NP nd.arrays so we use advanced slicing, meaning [row, col] instead of [row][col] func anf f_arg1/2 are names for a more general implementation yet to test where one can get any function between two events (does not have to be distance despite the function name) """ dist = [] for i, TrialDf in enumerate(TrialDfs): if not TrialDf.empty: if first_event == 'first': # From start of trial time_1st = float(TrialDf['t'].iloc[0]) else: time_1st = float(TrialDf[TrialDf.name == first_event]['t']) if second_event == 'last': # Until end of trial time_2nd = float(TrialDf['t'].iloc[-1]) else: time_2nd = float(TrialDf[TrialDf.name == second_event]['t']) # Slice DlcDf and compute distance according to input func and args Dlc_TrialDf = bhv.time_slice(DlcDf, time_1st, time_2nd) dist.append(func(Dlc_TrialDf, f_arg1, f_arg2, filter=True)) # Make sure we have numpy arrays with same length, pad/truncate with given input pad_with dist = bhv.truncate_pad_vector(dist, pad_with) return dist
def plot_reaches_between_events(SessionDf, LogDf, TrialDfs, event_1, event_2, bin_width): " Plots the reaches during between two events split by trial side and outcome " hist_range = (0, 2500) trial_sides = ['left', 'right'] outcomes = ['correct', 'incorrect'] fig, axes = plt.subplots(nrows=len(outcomes), ncols=len(trial_sides), figsize=[6, 4], sharex=True, sharey=True) kwargs = dict(bins=(round(hist_range[1] / bin_width)), range=hist_range, alpha=0.5, edgecolor='none') # For each side and outcome for i, trial_side in enumerate(trial_sides): for j, outcome in enumerate(outcomes): # Filter trials (continues if there are no trials to pool from) try: TrialDfs_filt = filter_trials_by( SessionDf, TrialDfs, dict(correct_side=trial_side, outcome=outcome)) except: continue # For each trial get the left and right reaches during delay period left_reaches, right_reaches = [], [] for TrialDf in TrialDfs_filt: t_event_1 = TrialDf[TrialDf['name'] == event_1].iloc[-1]['t'] if 'GO_CUE_LEFT_EVENT' in TrialDf['name'].values: t_event_2 = TrialDf.groupby('name').get_group( "GO_CUE_LEFT_EVENT").iloc[-1]['t'] elif 'GO_CUE_RIGHT_EVENT' in TrialDf['name'].values: t_event_2 = TrialDf.groupby('name').get_group( "GO_CUE_RIGHT_EVENT").iloc[-1]['t'] # Slice trials between events sliceDf = bhv.time_slice(LogDf, t_event_1, t_event_2) left_reaches.append( bhv.get_events_from_name(sliceDf, 'REACH_LEFT_ON').values - t_event_1) right_reaches.append( bhv.get_events_from_name(sliceDf, 'REACH_RIGHT_ON').values - t_event_1) flat_left_reaches = [ item for sublist in left_reaches for item in sublist ] flat_right_reaches = [ item for sublist in right_reaches for item in sublist ] ax = axes[j, i] ax.hist(np.array(flat_left_reaches), **kwargs, label='reach left') ax.hist(np.array(flat_right_reaches), **kwargs, label='reach right') ax.legend(loc='upper right', frameon=False, fontsize=8, handletextpad=0.3, handlelength=0.5) # Formatting axes[0, 0].set_title('short trials') axes[0, 1].set_title('long trials') axes[0, 0].set_ylabel('correct') axes[1, 0].set_ylabel('incorrect') fig.suptitle('Hist of reaches between ' + str(event_1) + ' and ' + str(event_2)) fig.tight_layout() return axes
LogDf['t'] = Sync.convert(LogDf['t'].values,'arduino','loadcell') # %% median removal for loadcelldata # %% median correction samples = 10000 # 10s buffer: harp samples at 1khz, arduino at 100hz, LC controller has 1000 samples in buffer LoadCellDf['x'] = LoadCellDf['x'] - LoadCellDf['x'].rolling(samples).median() LoadCellDf['y'] = LoadCellDf['y'] - LoadCellDf['y'].rolling(samples).median() # %% Spans = bhv.get_spans_from_names(LogDf, "REWARD_RIGHT_VALVE_ON", "REWARD_RIGHT_VALVE_OFF") N = 2000 Data = sp.zeros((N,27,2)) for i, row in Spans.iterrows(): t_on = row["t_on"] t_off = t_on + N data = bhv.time_slice(LoadCellDf, t_on, t_off) Data[:,i,:] = data.values[:,1:] # %% fs = sp.arange(60,310,10) Data = Data[:,-fs.shape[0]:,:] # %% fig, axes = plt.subplots() for i in range(fs.shape[0]): plt.plot(Data[:,i,0]) # %% from scipy.signal import periodogram import seaborn as sns colors = sns.color_palette('viridis',n_colors=25)
def plot_overview_simple(LogDf, align_event, pre, post, how='bars', axes=None): "Plots trials together with reach spans" if axes is None: fig, axes = plt.subplots() # Key Events and Spans key_list = [ 'REACH_LEFT_ON', 'REACH_RIGHT_ON', 'PRESENT_INTERVAL_STATE', 'GO_CUE_SHORT_EVENT', 'GO_CUE_LONG_EVENT' ] colors = sns.color_palette('hls', n_colors=len(key_list)) cdict = dict(zip(key_list, colors)) t_ref = bhv.get_events_from_name(LogDf, align_event).values for i, t in enumerate(t_ref): Df = bhv.time_slice(LogDf, t - pre, t + post, 't') for name in cdict: # plot events if name.endswith("_EVENT") or name.endswith("_STATE"): event_name = name times = bhv.get_events_from_name(Df, name).values - t if how == 'dots': axes.plot(times, [i] * len(times), '.', color=cdict[event_name], alpha=0.75) # a bar if how == 'bars': for time in times: axes.plot([time, time], [i - 0.5, i + 0.5], lw=2, color=cdict[event_name], alpha=0.75) # a bar # plot spans if name.endswith("_ON"): span_name = name.split("_ON")[0] on_name = span_name + '_ON' off_name = span_name + '_OFF' SpansDf = bhv.get_spans_from_names(Df, on_name, off_name) if 'REACH' in span_name: SpansDf = SpansDf[ SpansDf['dt'] > 10] # remove reaches whose length is less than 10ms for j, row_s in SpansDf.iterrows(): time = row_s['t_on'] - t dur = row_s['dt'] rect = plt.Rectangle((time, i - 0.5), dur, 1, facecolor=cdict[on_name], linewidth=1) axes.add_patch(rect) for key in cdict.keys(): axes.plot([0], [0], color=cdict[key], label=key, lw=4) # Formatting axes.legend(loc="center", bbox_to_anchor=(0.5, -0.2), prop={'size': len(key_list)}, ncol=len(key_list), frameon=False) axes.set_title('Trials aligned to ' + str(align_event)) plt.setp(axes, xticks=np.arange(-pre, post + 1, 500), xticklabels=np.arange(-pre / 1000, post / 1000 + 0.1, 0.5)) axes.set_ylim([0, len(t_ref)]) axes.invert_yaxis() # Needs to be after set_ylim axes.set_xlabel('Time (ms)') axes.set_ylabel('Trial No.') fig.tight_layout() return axes
def make_annotated_video(Vid, t_on, t_off, LogDf, DlcDf, fps=20, save=None): LogDfSlice = bhv.time_slice(LogDf, t_on, t_off) DlcDfSlice = bhv.time_slice(DlcDf, t_on, t_off) # what events to display display_events = list(LogDfSlice.name.unique()) # display_events = ['GO_CUE_SHORT_EVENT', 'GO_CUE_LONG_EVENT', 'CHOICE_CORRECT_EVENT', 'CHOICE_INCORRECT_EVENT', 'REWARD_LEFT_EVENT','REWARD_RIGHT_EVENT', 'REACH_LEFT_ON', 'REACH_LEFT_OFF', 'REACH_RIGHT_ON', 'REACH_RIGHT_OFF'] if sp.nan in display_events: display_events.remove(np.nan) frame_on = DlcDfSlice.index[0] frame_off = DlcDfSlice.index[-1] ix = list(range(frame_on, frame_off)) # plotting fig, ax = plt.subplots() ax.axis('off') if save is not None: import matplotlib as mpl # from matplotlib.animation import FFMpegWriter as AniWriter # Writer = AniWriter(fps=20, bitrate=7500, codec="h264", extra_args=['-pix_fmt','yuv420p']) # Writer = AniWriter(fps=20, bitrate=10000, codec="h264") from matplotlib.animation import FFMpegFileWriter as AniWriter Writer = AniWriter(fps=fps, codec="h264", bitrate=-1) mpl.rcParams['animation.ffmpeg_path'] = "/usr/bin/ffmpeg" # image ax.set_aspect('equal') frame = dlc.get_frame(Vid, ix[0]) im = ax.imshow(frame, cmap='gray') # body parts bp_left = [bp for bp in bodyparts if bp.endswith('L')] bp_right = [bp for bp in bodyparts if bp.endswith('R')] c_l = sns.color_palette('viridis', n_colors=len(bp_left)) c_r = sns.color_palette('magma', n_colors=len(bp_right)) bp_cols = dict(zip(bp_left+bp_right,c_l+c_r)) bp_markers = [] for i, bp in enumerate(bodyparts): marker, = ax.plot([],[], 'o', color=bp_cols[bp], markersize=10) bp_markers.append(marker) # traces from matplotlib.collections import LineCollection n_segments = 10 trace_len = 3 lws = sp.linspace(0,5,n_segments) bp_traces = [] for i, bp in enumerate(bodyparts): segments = [] for j in range(n_segments): segment = sp.zeros((trace_len,2)) segments.append(segment) lc = LineCollection(sp.array(segments),linewidths=lws,color=bp_cols[bp], alpha=0.75) bp_traces.append(lc) ax.add_artist(lc) p = 0.0 # frame text inactive_color = 'white' frame_counter = ax.text(5, frame.shape[0]-25, '', color=inactive_color) time_counter = ax.text(5, frame.shape[0]-5, '', color=inactive_color) # event text annotations # color setup c = sns.color_palette('husl', n_colors=len(display_events)) event_colors = dict(zip(display_events,c)) event_display_dur = 50 # ms event_texts = [] event_times = [] for i, event in enumerate(display_events): # times try: times = LogDfSlice.groupby('name').get_group(event)['t'].values except KeyError: times = [np.nan] event_times.append(times) # plot # bg_text = ax.text(10, i*20 + 20, event, color='black', fontweight='heavy', fontsize=6) text = ax.text(10, i*20 + 20, event, color=inactive_color, fontweight='heavy', fontsize=6) event_texts.append(text) fig.tight_layout() # the animation function def update(i): Frame = dlc.get_frame(Vid,i) im.set_data(Frame) # frame counter frame_counter.set_text("frame: %i - %i/%i" % (i, ix.index(i),len(ix))) t_abs = Sync.convert(i,'dlc','arduino') / 1000 m = Sync.pairs[('dlc','arduino')][0] t_rel = (ix.index(i) * m) / 1000 time_counter.set_text("time: %.2f - %.2f/%.2f" % (t_abs, t_rel,len(ix)*m/1000)) # body parts for j, bp in enumerate(bodyparts): data = DlcDfSlice[bp].loc[i] if data['likelihood'] > p: bp_markers[j].set_data(data['x'], data['y']) else: bp_markers[j].set_data(sp.nan, sp.nan) # trace for j, bp in enumerate(bodyparts): i0 = i - n_segments*trace_len data = DlcDfSlice[bp].loc[i0:i] data.loc[data['likelihood'] < p] = sp.nan data = data[['x','y']].values[::-1,:] segments = bp_traces[j].get_segments() for k in range(n_segments): try: segments[-k] = data[k*trace_len-5:(k+1)*trace_len+5,:] except: pass bp_traces[j].set_segments(segments) for j, event in enumerate(display_events): t = Sync.convert(i, 'dlc', 'arduino') if sp.any(sp.logical_and(t > event_times[j], t < event_times[j] + event_display_dur)): event_texts[j].set_color(event_colors[event]) else: event_texts[j].set_color(inactive_color) return (im, frame_counter, time_counter) + tuple(bp_markers) + tuple(bp_traces) + tuple(event_texts) ani = FuncAnimation(fig, update, frames=ix, blit=True, interval=1) if save is not None: utils.printer("saving video to %s" % save, 'msg') ani.save(save, writer=Writer) plt.close(fig)
def plot_no_init_attempts(LoadCellDf, TrialDfs, log_path, peaks_coincidence, hist_crop, axes=None): if axes is None: fig = plt.figure(figsize=(6, 4)) # Load thresh from bonsai settings bonsai_settings_path = log_path.parent / "learn_to_choose_v2/Bonsai/interface_variables.ini" with open(bonsai_settings_path, 'r') as fH: lines = fH.readlines() init_tresh = int(''.join(x for x in lines[1] if x.isdigit())) sub_tresh = 0.66 * init_tresh # About two thirds the original attempts = [] for TrialDf in TrialDfs: # Slice when trial is available but not initiated Df = bhv.event_slice(TrialDf, "TRIAL_AVAILABLE_EVENT", "TRIAL_ENTRY_EVENT") if not Df.empty: LCDf = bhv.time_slice(LoadCellDf, Df.iloc[0]['t'], Df.iloc[-1]['t']) X = LCDf['x'].values Y = LCDf['y'].values # sub thresh pulling peaks X_peaks, _ = sp.signal.find_peaks(X, height=sub_tresh, width=50) # 50 ms Y_peaks, _ = sp.signal.find_peaks(Y, height=sub_tresh, width=50) # Computes distance between all X_peaks and all Y_peaks dist = np.abs(X_peaks[:, np.newaxis] - Y_peaks) # If its empty if len(dist) == 0: attempts.append(0) else: min_dist = np.min(dist, axis=0) # If time difference between peaks is lower than 50 ms, they coincide in time no_attempts = min_dist[np.where( min_dist < peaks_coincidence)].shape[0] attempts.append(no_attempts) # Instant initiation else: attempts.append(0) # Plotting settings left, width = 0.1, 0.65 bottom, height = 0.1, 0.65 spacing = 0.005 rect_scatter = [left, bottom, width, height] rect_histy = [left + width + spacing, bottom, 0.2, height] ax = fig.add_axes(rect_scatter) ax_histy = fig.add_axes(rect_histy, sharey=ax) # Formatting ax.scatter(np.arange(len(TrialDfs)), attempts, s=2) ax.set_ylim([-1, hist_crop]) ax.set_ylabel('No of init attempts') ax.set_xlabel('Trial No.') ax_histy.hist(attempts, bins=np.arange(hist_crop) - 0.5, range=(0, hist_crop), density=True, orientation='horizontal') ax_histy.tick_params(axis="y", labelleft=False) ax_histy.set_xlabel('Perc. of trials (%)') ax_histy.set_xticks([0, 0.25, 0.5, 0.75, 1]) ax_histy.set_xticklabels([0, 25, 50, 75, 100]) ax_histy.set_xlim([0, 1]) ax_histy.set_ylim([-1, hist_crop]) ax.set_title('Number attempts before trial init') return ax
Df = bhv.event_slice(TrialDf, 'TRIAL_ENTRY_EVENT', 'ITI_STATE') t_on = Df.iloc[0]['t'] t_off = Df.iloc[-1]['t'] # %% static image with trajectory between t_on and t_off bp_cols = make_bodypart_colors(bodyparts) fig, axes = plt.subplots() frame_ix = Sync.convert(t_on, 'arduino', 'dlc') frame = dlc.get_frame(Vid, frame_ix) dlc.plot_frame(frame, axes=axes) dlc.plot_bodyparts(bodyparts, DlcDf, frame_ix, colors=bp_cols, axes=axes) # trajectory DlcDfSlice = bhv.time_slice(DlcDf, t_on, t_off) dlc.plot_trajectories(DlcDfSlice, bodyparts, axes=axes, colors=bp_cols, lw=1, p=0.99) # %% plot all of the selected trial type # SDf = bhv.groupby_dict(SessionDf, dict(outcome='correct', correct_side='right', paw_resting=False)) # trial selection SDf = bhv.groupby_dict(SessionDf, dict(has_choice=True, correct_side='left', outcome='correct')) # plot some random frame fig, axes = plt.subplots() frame_ix = 1000 frame = dlc.get_frame(Vid, frame_ix) dlc.plot_frame(frame, axes=axes)
# Filter sessions to the ones of the task we want to see task_name = ['learn_to_choose_v2'] FilteredSessionsDf = pd.concat([SessionsDf.groupby('task').get_group(name) for name in task_name]) log_paths = [Path(path)/'arduino_log.txt' for path in FilteredSessionsDf['path']] for k,log_path in enumerate(tqdm(log_paths[:no_sessions_to_analyze], position=0, leave=True, desc=animal)): LogDf = bhv.get_LogDf_from_path(log_path) # Getting metrics TrialSpans = bhv.get_spans_from_names(LogDf, "TRIAL_ENTRY_STATE", "ITI_STATE") TrialDfs = [] for i, row in TrialSpans.iterrows(): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) metrics = ( met.get_start, met.get_stop, met.get_correct_side, met.get_outcome, met.get_chosen_side, met.has_choice, met.rew_collected) SessionDf = bhv.parse_trials(TrialDfs, metrics) # Session metrics n_rews_collected[j,k] = SessionDf['rew_collect'].sum() n_anticipatory[j,k] = SessionDf['has_choice'].sum() no_trials[j,k] = len(SessionDf) session_length [j,k] = (LogDf['t'].iloc[-1]-LogDf['t'].iloc[0])/(1000*60) # convert msec. -> sec.-> min. # %% """ .########..##........#######..########..######.
# Detection rectangle w = 30 # box size rect = dlc_utils.box2rect(SL_coords, w) R = dlc_utils.Rectangle(*dlc_utils.rect2cart(rect),lw=1,facecolor='none',edgecolor='r') axes.add_patch(R) # Obtain all reaches within rectangle, convert from frame to time bp = 'PR' SpansDf = dlc_utils.in_box_span(DlcDf, bp, rect, min_dur=1) SpansDf = pd.DataFrame(Sync.convert(SpansDf.values,'dlc','arduino'), columns=SpansDf.columns) # Plot all reaches to given side df = DlcDf[bp] for i, row in tqdm(SpansDf.iterrows()): t_on = row['t_on'] df = bhv.time_slice(DlcDf,t_on-avg_mvmt_time,t_on+500)[bp] ix = df.likelihood > p df = df.loc[ix] axes.plot(df.x,df.y,lw=1, alpha=0.85) axes.set_title('Reach trajectories for right_spout with ' + str(bp)) plt.savefig(plot_dir / ('reaches_for_right_spout_with_' + str(bp) + '.png'), dpi=600) # %% distance / speed over time fig, axes = plt.subplots(nrows=2,sharex=True) bps = ['PR','PL'] line_kwargs = dict(lw=1,alpha=0.8) for i, bp in enumerate(bps):
def plot_forces_on_init(session_folder, save=None): LogDf = bhv.get_LogDf_from_path(session_folder / "arduino_log.txt") ### LoadCell Data LoadCellDf = bhv.parse_bonsai_LoadCellData(session_folder / 'bonsai_LoadCellData.csv') # Syncer from Utils import sync lc_sync_event = sync.parse_harp_sync(session_folder / 'bonsai_harp_sync.csv', trig_len=100, ttol=5) arduino_sync_event = sync.get_arduino_sync(session_folder / 'arduino_log.txt') Sync = sync.Syncer() Sync.data['arduino'] = arduino_sync_event['t'].values Sync.data['loadcell'] = lc_sync_event['t'].values Sync.sync('arduino','loadcell') LogDf['t_orig'] = LogDf['t'] LogDf['t'] = Sync.convert(LogDf['t'].values, 'arduino', 'loadcell') # preprocessing samples = 10000 # 10s buffer: harp samples at 1khz, arduino at 100hz, LC controller has 1000 samples in buffer LoadCellDf['x'] = LoadCellDf['x'] - LoadCellDf['x'].rolling(samples).mean() LoadCellDf['y'] = LoadCellDf['y'] - LoadCellDf['y'].rolling(samples).mean() # plot forces times = LogDf.groupby('name').get_group('TRIAL_ENTRY_EVENT')['t'].values pre, post = -1000, 1000 fig, axes = plt.subplots(nrows=2,sharex=True,sharey=False) x_avgs = [] y_avgs = [] for i,t in enumerate(tqdm(times)): Df = bhv.time_slice(LoadCellDf, t+pre, t+post, reset_index=False) # these colors need to be thorougly checked axes[0].plot(Df['t'].values - t, Df['x']) axes[1].plot(Df['t'].values - t, Df['y']) x_avgs.append(Df['x'].values) y_avgs.append(Df['y'].values) x_avgs = np.average(np.array(x_avgs),axis=0) y_avgs = np.average(np.array(y_avgs),axis=0) tvec = np.linspace(pre,post,x_avgs.shape[0]) axes[0].plot(tvec, x_avgs, color='k',lw=2) axes[1].plot(tvec, y_avgs, color='k',lw=2) kws = dict(linestyle=':',lw=1, alpha=0.8, color='k') for ax in axes: ax.axhline(-500, **kws) ax.axvline(0, **kws) # deco Session = utils.Session(session_folder) Animal = utils.Animal(session_folder.parent) title = ' - '.join([Animal.display(), Session.date, 'day: %s'% Session.day]) for ax in axes: ax.set_ylim(-2500,2500) ax.set_ylabel('Force [au]') axes[1].set_xlabel('time (ms)') sns.despine(fig) fig.suptitle(title) fig.tight_layout() fig.subplots_adjust(top=0.9) if save is not None: os.makedirs(session_folder / 'plots', exist_ok=True) plt.savefig(save, dpi=600) plt.close(fig)
t_on = Df.iloc[0]['t'] t_off = Df.iloc[-1]['t'] # %% static image with trajectory between t_on and t_off bp_cols = make_bodypart_colors(bodyparts) fig, axes = plt.subplots() frame_ix = Sync.convert(t_on, 'arduino', 'dlc') frame = dlc.get_frame(Vid, frame_ix) dlc.plot_frame(frame, axes=axes) dlc.plot_bodyparts(bodyparts, DlcDf, frame_ix, colors=bp_cols, axes=axes) # trajectory DlcDfSlice = bhv.time_slice(DlcDf, t_on, t_off) dlc.plot_trajectories(DlcDfSlice, bodyparts, axes=axes, colors=bp_cols, lw=1, p=0.99) # %% plot all of the selected trial type # trial selection SDf = bhv.groupby_dict(SessionDf, dict(correct_side='left',outcome='incorrect')) # SDf = SessionDf.groupby('correct_side').get_group('right') # plot some random frame fig, axes = plt.subplots() frame_ix = 1000 frame = dlc.get_frame(Vid, frame_ix) dlc.plot_frame(frame, axes=axes) # plot all traj in selection for i in tqdm(SDf.index):
meso_framesDf.drop(meso_framesDf.tail(n).index,inplace=True) # %% AVG across neurons across events events = ['GO_CUE_EVENT','REWARD_STATE','REWARD_RIGHT_COLLECTED_EVENT'] fig, axes = plt.subplots(ncols=len(events), sharey=True, figsize=(8,4)) pre, post = 500,2000 for i,event in enumerate(events): t_refs = bhv.get_events_from_name(LogDf, event).values N_mean,frame_time = [],[] for t_ref in t_refs: sliceDf = bhv.time_slice(meso_framesDf, t_ref-pre, t_ref+post) frame_time.append(sliceDf['t'].values - t_ref) # relative to t_ref frame_idx = sliceDf.index.values # get frames N_mean.append(np.mean(neural_data[:,frame_idx], axis = 0)) # Avg across neurons N_mean_time = bhv.tolerant_mean(N_mean) time = np.arange(-pre,post+1,main_freq) # begin,stop,step axes[i].plot(time,N_mean_time,'o-', color = 'black') axes[i].vlines(0,0,1, color = 'black', alpha = 0.25) axes[i].set_ylim([0,0.03]) axes[i].set_title(event) axes[i].set_xlabel('Time (ms)') axes[i].set_ylabel('\u0394F/F')
# check each reach ReachesLeftDf = bhv.get_spans_from_names(LogDf, "REACH_LEFT_ON", "REACH_LEFT_OFF") # drop invalid min_th = 5 max_th = 2000 binds = np.logical_and(ReachesLeftDf['dt'].values > min_th, ReachesLeftDf['dt'].values < max_th) ReachesLeftDf = ReachesLeftDf.loc[binds] ReachesLeftDf['is_grasp'] = False for i, row in ReachesLeftDf.iterrows(): t_on = row['t_on'] t_off = row['t_off'] Df = bhv.time_slice(LogDf, t_on, t_off) if 'GRASP_LEFT_ON' in Df.name.values: ReachesLeftDf.loc[i,'is_grasp'] = True if np.any(ReachesLeftDf['is_grasp']): GraspsLeftDf = ReachesLeftDf.groupby('is_grasp').get_group(True) else: GraspsLeftDf = pd.DataFrame([],columns=ReachesLeftDf.columns) ReachesRightDf = bhv.get_spans_from_names(LogDf, "REACH_RIGHT_ON", "REACH_RIGHT_OFF") # drop invalid min_th = 5 max_th = 2000 binds = np.logical_and(ReachesRightDf['dt'].values > min_th, ReachesRightDf['dt'].values < max_th)
def plot_hist_no_reaches_per_trial(LogDf, reach_crop): fig, axes = plt.subplots(figsize=[6, 4], ncols=2) kwargs = dict(bins=np.arange(reach_crop) - 0.5, range=(0, reach_crop), edgecolor='none', alpha=0.5, density=True) # Trials spanning from choice available to end of ITI TrialSpans = bhv.get_spans_from_names(LogDf, "GO_CUE_EVENT", "TRIAL_AVAILABLE_STATE") TrialDfs = [] for i, row in TrialSpans.iterrows(): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) sides = ['left', 'right'] no_reaches_dict = {'left': [], 'right': []} choice_reach_no_dict = {'left': [], 'right': []} key = [] # Obtain no of reaches before choice and total for each trial for TrialDf in TrialDfs: if met.has_choice(TrialDf).values: # Can't use metric due to cutting between choice and end of ITI if "GO_CUE_LEFT_EVENT" in TrialDf['name'].values: key = 'left' if "GO_CUE_RIGHT_EVENT" in TrialDf['name'].values: key = 'right' left_reach_spansDf = bhv.get_spans_from_names( TrialDf, 'REACH_LEFT_ON', 'REACH_LEFT_OFF') right_reach_spansDf = bhv.get_spans_from_names( TrialDf, 'REACH_RIGHT_ON', 'REACH_RIGHT_OFF') merge_spansDf = pd.concat( [left_reach_spansDf, right_reach_spansDf]).reset_index(drop=True) choice_time = bhv.get_events_from_name( TrialDf, 'CHOICE_EVENT')['t'].values[0] # Which reach triggered the choice? The one which corresponding spansDf contains choice_time for i, row in enumerate(merge_spansDf.iterrows()): if (row[1]['t_on'] < choice_time < row[1]['t_off']): no_reaches_needed = i + 1 choice_reach_no_dict[key].append(no_reaches_needed) no_reaches_dict[key].append( len(merge_spansDf) - no_reaches_needed ) # subtract the no. of reaches leading to choice # Plotting for ax, side in zip(axes, sides): ax.hist(no_reaches_dict[side], color='r', label='No. in vain reaches', **kwargs) ax.axvline(np.percentile(no_reaches_dict[side], 75), color='r') ax.hist(choice_reach_no_dict[side], color='y', label='No. reaches needed \n to clock choice', **kwargs) ax.axvline(np.percentile(choice_reach_no_dict[side], 75), color='y') ax.legend(frameon=False, fontsize='small') ax.set_title(side + ' trials') ax.set_xlabel('No. Reaches') ax.set_ylim([0, 1]) # Formatting axes[0].set_ylabel('Ratio of trials') fig.suptitle('Histogram of no. of reaches per trial ') fig.tight_layout() return axes
def grasp_dur_across_sess(animal_fd_path, tasks_names): SessionsDf = utils.get_sessions(animal_fd_path) animal_meta = pd.read_csv(animal_fd_path / 'animal_meta.csv') # Filter sessions to the ones of the task we want to see FilteredSessionsDf = pd.concat( [SessionsDf.groupby('task').get_group(name) for name in tasks_names]) log_paths = [ Path(path) / 'arduino_log.txt' for path in FilteredSessionsDf['path'] ] fig, axes = plt.subplots(ncols=2, figsize=[8, 4], sharey=True, sharex=True) sides = ['LEFT', 'RIGHT'] Df = [] # gather data for day, log_path in enumerate(log_paths): LogDf = bhv.get_LogDf_from_path(log_path) TrialSpans = bhv.get_spans_from_names(LogDf, "TRIAL_ENTRY_STATE", "ITI_STATE") TrialDfs = [] for i, row in tqdm(TrialSpans.iterrows(), position=0, leave=True): TrialDfs.append(bhv.time_slice(LogDf, row['t_on'], row['t_off'])) metrics = (met.get_start, met.get_stop, met.get_correct_side, met.get_outcome, met.get_interval_category, met.get_chosen_side, met.has_reach_left, met.has_reach_right) SessionDf = bhv.parse_trials(TrialDfs, metrics) for side in sides: event_on, event_off = 'REACH_' + str(side) + '_ON', 'REACH_' + str( side) + '_OFF' # event names # reaches grasp_spansDf = bhv.get_spans_from_names(LogDf, event_on, event_off) reach_durs = np.array(grasp_spansDf['dt'].values, dtype=object) Df.append([reach_durs], columns=['durs'], ignore_index=True) # grasps choiceDf = bhv.groupby_dict( SessionDf, dict(has_choice=True, chosen_side=side.lower())) grasp_durs = choiceDf[~choiceDf['grasp_dur'].isna( )]['grasp_dur'].values # filter out Nans Df.append([grasp_durs, 'g', side], columns=['durs', 'type', 'side'], ignore_index=True) sns.violinplot(data=Df[Df['type'] == 'r'], x=day, y='durs', hue='side', split=True, cut=0, legend='reaches') sns.violinplot(data=Df[Df['type'] == 'g'], x=day, y='durs', hue='side', split=True, cut=0, legend='grasps') fig.suptitle('CDF of first reach split on trial type \n' + animal_meta['value'][5] + '-' + animal_meta['value'][0]) axes.legend return axes
# %% check each reach ReachesDf = bhv.get_spans_from_names(LogDf, "REACH_ON", "REACH_OFF") # drop invalid min_th = 5 max_th = 2000 binds = np.logical_and(ReachesDf['dt'].values > min_th, ReachesDf['dt'].values < max_th) ReachesDf = ReachesDf.loc[binds] ReachesDf['is_grasp'] = False for i, row in ReachesDf.iterrows(): t_on = row['t_on'] t_off = row['t_off'] Df = bhv.time_slice(LogDf, t_on, t_off) if 'GRASP_ON' in Df.name.values: ReachesDf.loc[i,'is_grasp'] = True GraspsDf = ReachesDf.groupby('is_grasp').get_group(True) # %% fig, axes = plt.subplots(ncols=2, gridspec_kw=dict(width_ratios=(1,0.2))) axes[0].plot(ReachesDf['t_on']/6e4, ReachesDf['dt'],'.',label='reach') axes[0].plot(GraspsDf['t_on']/6e4, GraspsDf['dt'],'.',label='grasp') wm = 3 w = wm*60*1000 w2 = int(w/2) avgs = [] t_max = LogDf.iloc[-1]['t'] for t in tqdm(range(w2*2,int(t_max - w2),w2)): Df_reach = bhv.time_slice(ReachesDf, t-w/2, t+w/2, col='t_on')
fig.tight_layout() # %% LogDf.groupby('name').get_group('FRAME_EVENT').shape[0] LogDf.groupby('name').get_group('FRAME_INF_EVENT').shape[0] # -> works, assign idex nFrames = LogDf.groupby('name').get_group('FRAME_INF_EVENT').shape[0] offset = dFF.shape[1] - nFrames LogDf.loc[LogDf['name'] == 'FRAME_INF_EVENT','var'] = np.arange(offset, nFrames+offset) # %% test slicing w = (-3000, 3000) event = 'REACH_RIGHT_ON' times = LogDf.groupby('name').get_group(event)['t'] ix_ts = [] for t in times.values: Df = bhv.time_slice(LogDf,t+w[0],t+w[1]) try: frame_ix = Df.groupby('name').get_group('FRAME_INF_EVENT')['var'].values frame_times = Df.groupby('name').get_group('FRAME_INF_EVENT')['t'].values - t ix_ts.append((frame_ix.astype('int32'),frame_times)) except: pass # %% sorting by kmeans from sklearn.cluster import KMeans k = 4 # todo find a way to find k clust = KMeans(n_clusters=k) clust.fit(dFF) labels = clust.labels_ order = np.argsort(labels) dFF = dFF[order,:]