<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Previous
Step1:  The preprocess schema extracts, aligns, and synchronizes multiphoton trace data from both galvo and AOD systems.
Step2:  Here are the main elements of the preprocess schema
Step3:  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.
Step4:  Similarly, preprocess.ExtractRaw has several part tables.
Step5:  Example
Step6:  If you know the exact identity of the scan of interest, use it as restriction
Step7:  Alternatively, get a whole set of scans matching some condition.
Step8:  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.
Step9:  Example
Step10:  Select the preprocessing method
Step11:  Let's plot a random trace
<ASSISTANT_TASK:>
Python Code:
%pylab inline
pylab.rcParams['figure.figsize'] = (6, 6)
Explanation: Previous: pipeline_vis  ::: Next Synchronization 
Schema preprocess
End of explanation
import datajoint as dj
from pipeline.preprocess import *
Explanation: The preprocess schema extracts, aligns, and synchronizes multiphoton trace data from both galvo and AOD systems.
End of explanation
(dj.ERD.from_sequence([Prepare, Sync, ExtractRaw, Spikes])-1).draw()
Explanation: Here are the main elements of the preprocess schema:
End of explanation
dj.ERD(Prepare).add_parts().draw()
Explanation: 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.
End of explanation
dj.ERD(ExtractRaw).add_parts().draw()
Explanation: Similarly, preprocess.ExtractRaw has several part tables.
End of explanation
Prepare.GalvoAverageFrame().heading
Explanation: 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:
End of explanation
frames = Prepare.GalvoAverageFrame() & dict(animal_id=8623, slice=3, scan_idx=6)
frames
# 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)
Explanation: If you know the exact identity of the scan of interest, use it as restriction:
End of explanation
experiment.Fluorophore()
# select all slices imaged with GCaMP6f
slices = Prepare()*Slice() & (
    experiment.Session.Fluorophore() & 'fluorophore="GCaMP6f"') & Prepare.GalvoAverageFrame()
slices    
Explanation: Alternatively, get a whole set of scans matching some condition.
End of explanation
keys = list(slices.fetch.keys())
key = keys[8]   #  pick an arbitrary frame
key
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)
Explanation: 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.
End of explanation
calcium = ComputeTraces.Trace()
spikes = Spikes.RateTrace()
traces = calcium*spikes  # combined raw and spike rate traces
traces.heading
Explanation: 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.
End of explanation
Method.Galvo()   #  trace extraction methods for galvo imaging
SpikeMethod()
traces &= dict(extract_method=2, spike_method=3)
traces
Explanation: Select the preprocessing method
End of explanation
key = np.random.choice(list(traces.fetch.keys()))   # pick a random trace
key
# 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']
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()
Explanation: Let's plot a random trace:
End of explanation
<END_TASK>