Previous: pipeline_vis ::: Next Synchronization

Schema preprocess


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

The preprocess schema extracts, aligns, and synchronizes multiphoton trace data from both galvo and AOD systems.


In [ ]:
import datajoint as dj
from pipeline.preprocess import *

Here are the main elements of the preprocess schema:


In [ ]:
(dj.ERD.from_sequence([Prepare, Sync, ExtractRaw, Spikes])-1).draw()

Prepare and ExtractRaw combine the information from the galvo-based two-photon setups and the AOD-based setup. They perform all the operations that are specific to each type of imaging so that subsequent processing is no longer distinguished.


Many tables have part tables. A part table is so tightly dependent to its master table that it is never modified separately from its master. They are implemented as nested classes. Only one level of nesting is allowed. In other words, parts cannot have their own parts. On the ERD, parts are shown in a smaller font with no color code.

For example, preprocess.Prepare has many subtables that perform various jobs.


In [ ]:
dj.ERD(Prepare).add_parts().draw()

Similarly, preprocess.ExtractRaw has several part tables.


In [ ]:
dj.ERD(ExtractRaw).add_parts().draw()

Example: fetching and plotting average images of scans.

Many tables contain attributes of type blob or longblob, which contain array information such as images and traces:


In [ ]:
Prepare.GalvoAverageFrame().heading

If you know the exact identity of the scan of interest, use it as restriction:


In [ ]:
frames = Prepare.GalvoAverageFrame() & dict(animal_id=8623, slice=3, scan_idx=6)
frames

In [ ]:
# fetch data
g, r = frames.fetch.order_by('channel')['frame']

# plot data
def normalize(img):
    m = img.min()
    return (img - m)/(img.max() - m)

plt.imshow(np.stack(
        [normalize(r), normalize(g), np.zeros_like(r)], 2))
grid(False)

Alternatively, get a whole set of scans matching some condition.


In [ ]:
experiment.Fluorophore()

In [ ]:
# select all slices imaged with GCaMP6f
slices = Prepare()*Slice() & (
    experiment.Session.Fluorophore() & 'fluorophore="GCaMP6f"') & Prepare.GalvoAverageFrame()
slices

To address each entity in the set, get its primary key values with the fetch.keys() iterator. Then each key can be used in a restriction.


In [ ]:
keys = list(slices.fetch.keys())
key = keys[8]   #  pick an arbitrary frame
key

In [ ]:
frames = Prepare.GalvoAverageFrame() & key  
g, r = frames.fetch.order_by('channel')['frame']
plt.imshow(np.stack(
        [normalize(r), normalize(g), np.zeros_like(r)], 2))
grid(False)

Example: Plot calcium traces and inferred spikes

Raw calcium traces are hosted in preprocess.ComputeTraces.Trace whereas inferred spikes are hosted in preprocess.Spikes.RateTrace.


In [ ]:
calcium = ComputeTraces.Trace()
spikes = Spikes.RateTrace()
traces = calcium*spikes  # combined raw and spike rate traces
traces.heading

Select the preprocessing method


In [ ]:
Method.Galvo()   #  trace extraction methods for galvo imaging

In [ ]:
SpikeMethod()

In [ ]:
traces &= dict(extract_method=2, spike_method=3)
traces

Let's plot a random trace:


In [ ]:
key = np.random.choice(list(traces.fetch.keys()))   # pick a random trace
key

In [ ]:
# fetch synchronized times
times, nslices = (Sync()*Prepare.Galvo() & key).fetch1['frame_times', 'nslices']
times = times[0,::nslices] - times[0,0]  # start at 0

calcium, spikes = (traces & key).fetch1['trace', 'rate_trace']

In [ ]:
import seaborn as sns
with sns.axes_style('whitegrid'):
    fig, ax = plt.subplots(2,1, sharex=True)
ax[0].plot(times, calcium.squeeze(), label='Ca Trace')
ax[1].plot(times, spikes.squeeze(), label='Spike Rate')
ax[0].set_ylabel('Fluorescence')
ax[1].set_ylabel('inferred spike rate')
ax[1].set_xlabel('time [s]')
sns.despine(fig)
fig.tight_layout()