Eye traces in pipeline


In [ ]:
%pylab inline
pylab.rcParams['figure.figsize'] = (6, 6)

In [ ]:
%matplotlib inline
import datajoint as dj
from pipeline import vis, preprocess
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

Eye tracking traces are in EyeTracking and in its part table EyeTracking.Frame. EyeTracking is a grouping table that refers to one scan and one eye video, whereas EyeTracking.Frame contains the single frames. The table BehaviorSync is used to synchronize the behavior measurements (Treadmill, Eyetracking) to the scan frames.


In [ ]:
(dj.ERD.from_sequence([preprocess.EyeTracking,preprocess.BehaviorSync]) - 1 + \
     dj.ERD(preprocess.EyeTracking).add_parts()).draw()

In this notebook, we'll fetch the pupil radius and position, and plot it along with a calcium trace, all on the behavior clock. The relative times of the eye, treadmill, and trace are precise, but the clock itself starts at some arbitrary offset.


In [ ]:
# choose an arbitrary scan
key = dict(animal_id=8804, session=1, scan_idx=3)

Eye


In [ ]:
# Fetch the pupil radius trace and the centers
r, center = (preprocess.EyeTracking.Frame() & key).fetch['major_r', 'center']

In [ ]:
# undetected frames are nans in the radius trace
detectedFrames = ~np.isnan(r)

In [ ]:
# convert positions to a 2d numpy array
xy = np.full((len(r),2),np.nan)
xy[detectedFrames, :] = np.vstack(center[detectedFrames])

In [ ]:
# get pupil tracking times on the behavior clock
et = (preprocess.Eye() & key).fetch1['eye_time']

In [ ]:
# plot xy position and radius
plt.plot(et,r)
plt.plot(et,xy)

Calcium Traces


In [ ]:
# choose an arbitrary calcium trace
trace_key = dict(key, extract_method=2, trace_id=256)

# ...and fetch the trace
tr = (preprocess.ComputeTraces.Trace() & trace_key).fetch1['trace']

Join the trace and segmentation tables to get more info about this trace and the mask used to generate it


In [ ]:
tr_info = preprocess.ComputeTraces.Trace() * preprocess.ExtractRaw.GalvoROI() & trace_key
tr_info

...and fetch the trace and slice number for the single trace from the joined tables using fetch1


In [ ]:
tr, slice_no = (preprocess.ComputeTraces.Trace() * preprocess.ExtractRaw.GalvoROI() 
                & trace_key).fetch1['trace','slice']

Fetch the imaging frame times on the behavior clock and the number of slices per scan


In [ ]:
ft, nslices = (preprocess.BehaviorSync() * preprocess.Prepare.Galvo() 
               & key).fetch1['frame_times','nslices']

In a single scan with 3 slices, imaging frames are collected from slice 1, 2, 3, 1, 2, 3...

So there are nslices * length(tr) frame times


In [ ]:
assert nslices*len(tr)==len(ft),\
            'You should never see this message unless the scan was aborted'

In [ ]:
# get the frame times for this slice
ft_slice = ft[slice_no-1::nslices] # slices are numbered 1 based


# Plot the trace to the pupil plot with some scaling
plt.plot(et,r)
plt.plot(et,xy)
plt.plot(ft_slice,tr/tr.min()*20-60)

Visual stimulus


In [ ]:
# fetch the frame times on the visual stimulus clock
vt = (preprocess.Sync() & key).fetch1['frame_times'].squeeze()
vt_slice = vt[slice_no-1::nslices]

# get the trials and for this scan and their flip times
flip_times = (vis.Trial() * preprocess.Sync() & key 
          & 'trial_idx > first_trial and trial_idx < last_trial').fetch['flip_times']

In [ ]:
plt.plot(et,r)
plt.plot(et,xy)
plt.plot(ft_slice,tr/tr.min()*20-60)

for flip_time in flip_times:
    # Get the imaging frame where the vis stim trial started
    
    start_idx = np.where(vt_slice > flip_time[0,0])[0][0]
    
    # Use that frame to index into the times on the behavior clock
    plt.plot(ft_slice[start_idx],150,'ok', mfc='orange', ms=4)


plt.legend(['Pupil Radius (pxls)', 'Pupil X (pxls)','Pupil Y (pxls)',
            'dF/F (scaled)', 'Vis Trial Start'], bbox_to_anchor=(1.4,1),
          bbox_transform=plt.gca().transAxes)
plt.xlabel('time on behavior clock (s)')

In [ ]: