Skip to content

analysis.py

ActivityAlignmentCondition

Bases: dj.Manual

Alignment activity table

Attributes:

Name Type Description
miniscope.Activity foreign key

Activity primary key

event.AlignmentEvent foreign key

Alignment Event primary key

trial_condition foreign key

varchar(128) # user-friendly name of condition

condition_description varchar(1000), nullable

condition description

bin_size float

Bin-size (in second) used to compute the PSTH Default 0.04

Source code in workflow_miniscope/analysis.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@schema
class ActivityAlignmentCondition(dj.Manual):
    """Alignment activity table

    Attributes:
        miniscope.Activity (foreign key): Activity primary key
        event.AlignmentEvent (foreign key): Alignment Event primary key
        trial_condition: varchar(128) # user-friendly name of condition
        condition_description ( varchar(1000), nullable): condition description
        bin_size (float, optional): Bin-size (in second) used to compute the PSTH
            Default 0.04
    """

    definition = """
    -> miniscope.Activity
    -> event.AlignmentEvent
    trial_condition: varchar(128) # user-friendly name of condition
    ---
    condition_description='': varchar(1000)
    bin_size=0.04: float # bin-size (in second) used to compute the PSTH
    """

    class Trial(dj.Part):
        definition = """  # Trials (or subset) to compute event-aligned activity
        -> master
        -> trial.Trial
        """

ActivityAlignment

Bases: dj.Computed

Computed table for alignment activity

Attributes:

Name Type Description
ActivityAlignmentCondition foreign key

Activity Alignment Condition key

aligned_timestamps longblob

aligned timestamps

Source code in workflow_miniscope/analysis.py
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
@schema
class ActivityAlignment(dj.Computed):
    """Computed table for alignment activity

    Attributes:
        ActivityAlignmentCondition (foreign key): Activity Alignment Condition key
        aligned_timestamps (longblob): aligned timestamps
    """

    definition = """
    -> ActivityAlignmentCondition
    ---
    aligned_timestamps: longblob
    """

    class AlignedTrialActivity(dj.Part):
        """Calcium activity aligned to the event time within the designated window

        Attributes:
            miniscope.Activity.Trace (foreign key): Activity trace primary key
            ActivityAlignmentCondition.Trial (foreign key): Alignment condition key
            aligned_trace (longblob): (s) Calcium activity aligned to the event time
        """

        definition = """
        -> master
        -> miniscope.Activity.Trace
        -> ActivityAlignmentCondition.Trial
        ---
        aligned_trace: longblob  # (s) Calcium activity aligned to the event time
        """

    def make(self, key):
        """Populate ActivityAlignment and AlignedTrialActivity

        Args:
            key (dict): Dict uniquely identifying one ActivityAlignmentCondition
        """
        session_time, rec_time, nframes, frame_rate = (
            miniscope.RecordingInfo * session.Session & key
        ).fetch1("session_datetime", "recording_datetime", "nframes", "fps")

        # Estimation of frame timestamps with respect to the session-start
        # (to be replaced by timestamps retrieved from some synchronization routine)
        # rec_start = (rec_time - session_time).total_seconds() if rec_time else 0
        # frame_timestamps = np.arange(nframes) / frame_rate + rec_start

        trialized_event_times = trial.get_trialized_alignment_event_times(
            key, trial.Trial & (ActivityAlignmentCondition.Trial & key)
        )

        min_limit = (trialized_event_times.event - trialized_event_times.start).max()
        max_limit = (trialized_event_times.end - trialized_event_times.event).max()

        aligned_timestamps = np.arange(-min_limit, max_limit, 1 / frame_rate)
        nsamples = len(aligned_timestamps)

        trace_keys, activity_traces = (miniscope.Activity.Trace & key).fetch(
            "KEY", "activity_trace", order_by="mask_id"
        )
        activity_traces = np.vstack(activity_traces)

        aligned_trial_activities = []
        for _, r in trialized_event_times.iterrows():
            if r.event is None or np.isnan(r.event):
                continue
            alignment_start_idx = int((r.event - min_limit) * frame_rate)
            roi_aligned_activities = activity_traces[
                :, alignment_start_idx : (alignment_start_idx + nsamples)
            ]
            if roi_aligned_activities.shape[-1] != nsamples:
                shape_diff = nsamples - roi_aligned_activities.shape[-1]
                roi_aligned_activities = np.pad(
                    roi_aligned_activities,
                    ((0, 0), (0, shape_diff)),
                    mode="constant",
                    constant_values=np.nan,
                )

            aligned_trial_activities.extend(
                [
                    {**key, **r.trial_key, **trace_key, "aligned_trace": aligned_trace}
                    for trace_key, aligned_trace in zip(
                        trace_keys, roi_aligned_activities
                    )
                ]
            )

        self.insert1({**key, "aligned_timestamps": aligned_timestamps})
        self.AlignedTrialActivity.insert(aligned_trial_activities)

    def plot_aligned_activities(
        self, key: dict, roi, axs: tuple = None, title: str = None
    ) -> plt.figure.Figure:
        """Plot event-aligned and trial-averaged calcium activities

        Activities including: dF/F, neuropil-corrected dF/F, Calcium events, etc.

        Args:
            key (dict): key of ActivityAlignment master table
            roi (int): miniscope segmentation mask
            axs (tuple, optional): Definition of axes for plot.
                Default is plt.subplots(2, 1, figsize=(12, 8))
            title (str, optional): Optional title label. Defaults to None.

        Returns:
            fig (matplotlib.figure.Figure): Plot event-aligned and trial-averaged
                calcium activities
        """

        fig = None
        if axs is None:
            fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(12, 8))
        else:
            ax0, ax1 = axs

        aligned_timestamps = (self & key).fetch1("aligned_timestamps")
        _, aligned_spikes = (self.AlignedTrialActivity & key & {"mask_id": roi}).fetch(
            "trial_id", "aligned_trace", order_by="trial_id"
        )

        aligned_spikes = np.vstack(aligned_spikes)

        ax0.imshow(
            aligned_spikes,
            cmap="inferno",
            interpolation="nearest",
            aspect="auto",
            extent=(
                aligned_timestamps[0],
                aligned_timestamps[-1],
                0,
                aligned_spikes.shape[0],
            ),
        )
        ax0.axvline(x=0, linestyle="--", color="white")
        ax0.set_axis_off()

        ax1.plot(aligned_timestamps, np.nanmean(aligned_spikes, axis=0))
        ax1.axvline(x=0, linestyle="--", color="black")
        ax1.set_xlabel("Time (s)")
        ax1.set_xlim(aligned_timestamps[0], aligned_timestamps[-1])

        if title:
            plt.suptitle(title)

        return fig

AlignedTrialActivity

Bases: dj.Part

Calcium activity aligned to the event time within the designated window

Attributes:

Name Type Description
miniscope.Activity.Trace foreign key

Activity trace primary key

ActivityAlignmentCondition.Trial foreign key

Alignment condition key

aligned_trace longblob

(s) Calcium activity aligned to the event time

Source code in workflow_miniscope/analysis.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class AlignedTrialActivity(dj.Part):
    """Calcium activity aligned to the event time within the designated window

    Attributes:
        miniscope.Activity.Trace (foreign key): Activity trace primary key
        ActivityAlignmentCondition.Trial (foreign key): Alignment condition key
        aligned_trace (longblob): (s) Calcium activity aligned to the event time
    """

    definition = """
    -> master
    -> miniscope.Activity.Trace
    -> ActivityAlignmentCondition.Trial
    ---
    aligned_trace: longblob  # (s) Calcium activity aligned to the event time
    """

make(key)

Populate ActivityAlignment and AlignedTrialActivity

Parameters:

Name Type Description Default
key dict

Dict uniquely identifying one ActivityAlignmentCondition

required
Source code in workflow_miniscope/analysis.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def make(self, key):
    """Populate ActivityAlignment and AlignedTrialActivity

    Args:
        key (dict): Dict uniquely identifying one ActivityAlignmentCondition
    """
    session_time, rec_time, nframes, frame_rate = (
        miniscope.RecordingInfo * session.Session & key
    ).fetch1("session_datetime", "recording_datetime", "nframes", "fps")

    # Estimation of frame timestamps with respect to the session-start
    # (to be replaced by timestamps retrieved from some synchronization routine)
    # rec_start = (rec_time - session_time).total_seconds() if rec_time else 0
    # frame_timestamps = np.arange(nframes) / frame_rate + rec_start

    trialized_event_times = trial.get_trialized_alignment_event_times(
        key, trial.Trial & (ActivityAlignmentCondition.Trial & key)
    )

    min_limit = (trialized_event_times.event - trialized_event_times.start).max()
    max_limit = (trialized_event_times.end - trialized_event_times.event).max()

    aligned_timestamps = np.arange(-min_limit, max_limit, 1 / frame_rate)
    nsamples = len(aligned_timestamps)

    trace_keys, activity_traces = (miniscope.Activity.Trace & key).fetch(
        "KEY", "activity_trace", order_by="mask_id"
    )
    activity_traces = np.vstack(activity_traces)

    aligned_trial_activities = []
    for _, r in trialized_event_times.iterrows():
        if r.event is None or np.isnan(r.event):
            continue
        alignment_start_idx = int((r.event - min_limit) * frame_rate)
        roi_aligned_activities = activity_traces[
            :, alignment_start_idx : (alignment_start_idx + nsamples)
        ]
        if roi_aligned_activities.shape[-1] != nsamples:
            shape_diff = nsamples - roi_aligned_activities.shape[-1]
            roi_aligned_activities = np.pad(
                roi_aligned_activities,
                ((0, 0), (0, shape_diff)),
                mode="constant",
                constant_values=np.nan,
            )

        aligned_trial_activities.extend(
            [
                {**key, **r.trial_key, **trace_key, "aligned_trace": aligned_trace}
                for trace_key, aligned_trace in zip(
                    trace_keys, roi_aligned_activities
                )
            ]
        )

    self.insert1({**key, "aligned_timestamps": aligned_timestamps})
    self.AlignedTrialActivity.insert(aligned_trial_activities)

plot_aligned_activities(key, roi, axs=None, title=None)

Plot event-aligned and trial-averaged calcium activities

Activities including: dF/F, neuropil-corrected dF/F, Calcium events, etc.

Parameters:

Name Type Description Default
key dict

key of ActivityAlignment master table

required
roi int

miniscope segmentation mask

required
axs tuple

Definition of axes for plot. Default is plt.subplots(2, 1, figsize=(12, 8))

None
title str

Optional title label. Defaults to None.

None

Returns:

Name Type Description
fig matplotlib.figure.Figure

Plot event-aligned and trial-averaged calcium activities

Source code in workflow_miniscope/analysis.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
def plot_aligned_activities(
    self, key: dict, roi, axs: tuple = None, title: str = None
) -> plt.figure.Figure:
    """Plot event-aligned and trial-averaged calcium activities

    Activities including: dF/F, neuropil-corrected dF/F, Calcium events, etc.

    Args:
        key (dict): key of ActivityAlignment master table
        roi (int): miniscope segmentation mask
        axs (tuple, optional): Definition of axes for plot.
            Default is plt.subplots(2, 1, figsize=(12, 8))
        title (str, optional): Optional title label. Defaults to None.

    Returns:
        fig (matplotlib.figure.Figure): Plot event-aligned and trial-averaged
            calcium activities
    """

    fig = None
    if axs is None:
        fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(12, 8))
    else:
        ax0, ax1 = axs

    aligned_timestamps = (self & key).fetch1("aligned_timestamps")
    _, aligned_spikes = (self.AlignedTrialActivity & key & {"mask_id": roi}).fetch(
        "trial_id", "aligned_trace", order_by="trial_id"
    )

    aligned_spikes = np.vstack(aligned_spikes)

    ax0.imshow(
        aligned_spikes,
        cmap="inferno",
        interpolation="nearest",
        aspect="auto",
        extent=(
            aligned_timestamps[0],
            aligned_timestamps[-1],
            0,
            aligned_spikes.shape[0],
        ),
    )
    ax0.axvline(x=0, linestyle="--", color="white")
    ax0.set_axis_off()

    ax1.plot(aligned_timestamps, np.nanmean(aligned_spikes, axis=0))
    ax1.axvline(x=0, linestyle="--", color="black")
    ax1.set_xlabel("Time (s)")
    ax1.set_xlim(aligned_timestamps[0], aligned_timestamps[-1])

    if title:
        plt.suptitle(title)

    return fig