Esempio n. 1
0
    def build(self):
        """
            Interpolate each segment to create a piecewise linear curve where
            the nmber of samples in each segments is matched to its length.
        """
        tot_length = np.sum([seg.length for seg in self.segments])
        samples_per_unit_length = self._n_samples / tot_length
        samples_per_segment = [
            int(seg.length * samples_per_unit_length) for seg in self.segments
        ]

        for segment, n_samples in zip(self.segments, samples_per_segment):
            segment.interpolate(n_samples)

        # stack all segmnts into a curve
        trace = np.vstack([segment.line for segment in self.segments])
        self.trace_ids = np.concatenate(
            [segment.ids for segment in self.segments])

        # smooth the curve to make it more bendy
        x = convolve_with_gaussian(trace[:, 0], 200)
        y = convolve_with_gaussian(trace[:, 1], 200)
        self.trace = np.vstack([x, y]).T

        # get the orientation of each segment
        self.trace_orientation = get_dir_of_mvmt_from_xy(
            self.trace[:, 0], self.trace[:, 1])
Esempio n. 2
0
def skeleton2path(
        skeleton: np.ndarray,
        points_spacing: int,
        apply_extra_spacing:
    bool = False,  # if true track is padded to look like mice's paths
) -> Trajectory:
    """
        It finds points on the skeleton and sorts
        them based on their position.
        Returns a Trajectory over the skeleton (smoothed)
    """
    y, x = np.where(skeleton)
    points = np.array([x, y]).T
    p = points[0]
    pts = [p]
    added = [0]
    for n in range(len(points)):
        # get the closest point to the current one
        dists = np.apply_along_axis(np.linalg.norm, 1, points - p)

        for idx in added:
            dists[idx] = 10000

        p = points[np.argmin(dists)]
        pts.append(p)
        added.append(np.argmin(dists))

    pts = pts[2:-2]
    X = np.float64([p[0] + 1 for p in pts])[::-1]
    Y = np.float64([p[1] + 1 for p in pts])[::-1] - 0.5

    # adjust coordinates to make it look more like the animals tracking (e.g. because mice have non-zero width)
    if apply_extra_spacing:
        Y[Y < 10] -= 2.5
        Y[Y > 50] += 1.5
        Y[(Y > 40) & (Y < 50) & (5 < X) & (X < 33)] += 2
        X[(X > 8) & (X < 20) & (Y > 40) & (Y < 50)] -= 2
        X[(X > 20) & (X < 33) & (Y > 40) & (Y < 50)] += 2
        Y[(X > 10) & (X < 15) & (Y > 43) & (Y < 48)] += 2.5
        X[(Y < 18) & (X > 8) & (X < 14)] -= 1
        X[(Y < 18) & (X > 24) & (X < 32)] -= 1
        X[(Y < 18) & (X > 16) & (X < 25)] += 1
        X[(Y < 18) & (X > 32)] += 1
        Y[(X > 30) & (X < 35) & (Y < 5)] += 1

    # smooth
    X = convolve_with_gaussian(X, kernel_width=31)
    Y = convolve_with_gaussian(Y, kernel_width=31)

    if points_spacing >= 1:
        return Trajectory(
            X, Y, name="skeleton", fps=60,
            smoothing_window=1).downsample_euclidean(spacing=points_spacing)
    else:
        return Trajectory(
            X, Y, name="skeleton", fps=60,
            smoothing_window=1).interpolate(spacing=points_spacing)
Esempio n. 3
0
def calc_angular_velocity(angles: np.ndarray) -> np.ndarray:
    # convert to radians and take derivative
    rad = np.unwrap(np.deg2rad(angles))
    rad = medfilt(rad, 11)
    rad = data_utils.convolve_with_gaussian(rad, 11)

    diff = derivative(rad)
    return np.rad2deg(diff)
Esempio n. 4
0
def process_body_part(
    bp_data: dict,
    M: np.ndarray,
    likelihood_th: float = 0.95,
    cm_per_px: float = 1,
) -> dict:
    # register to CMM
    x, y = register(bp_data["x"], bp_data["y"], M)

    # scale to go px -> cm
    x *= cm_per_px
    y *= cm_per_px

    # remove low confidence intervals
    like = bp_data["likelihood"]
    x[like < likelihood_th] = np.nan
    y[like < likelihood_th] = np.nan

    # interpolate nans
    xy = data_utils.interpolate_nans(x=x, y=y)
    x, y = np.array(list(xy["x"].values())), np.array(list(xy["y"].values()))

    # median filter pass
    x = data_utils.convolve_with_gaussian(x, kernel_width=5)
    y = data_utils.convolve_with_gaussian(y, kernel_width=5)

    # compute speed
    speed = Path(x, y, fps=60).speed  # in cm/s

    # make sure there are no nans
    results = dict(x=x, y=y, bp_speed=speed)
    for k, var in results.items():
        if np.any(np.isnan(var)):
            raise ValueError(f"Found NANs in {k}")

    return results
Esempio n. 5
0
def get_threshold_crossing(
    tracking: tuple, frame: int, direction: str, threshold: float
) -> int:
    """
        Gets the last/first time the speed of all paws crossed a threshold
    """
    speeds = (
        tracking.right_fl.bp_speed,
        tracking.left_fl.bp_speed,
        tracking.right_hl.bp_speed,
        tracking.left_hl.bp_speed,
    )
    if direction == "up":
        if frame == 0:
            return frame
        start = frame - 60 if frame > 60 else 0

        crosses = []
        for paw in speeds:
            paw = data_utils.convolve_with_gaussian(paw, 8)
            try:
                crosses.append(np.where(paw[start:frame] < threshold)[0][-1])
            except IndexError:
                crosses.append(np.nan)

        val = np.nanmin(crosses) + start
        if val > frame or np.isnan(val):
            logger.warning("Error in precise threshold crossing computation")
            return None
        return int(val)
    else:
        n_frames = len(tracking.right_fl.speed)
        if frame == n_frames:
            return frame
        end = frame + 60 if frame < (n_frames - 60) else n_frames

        crosses = []
        for paw in speeds:
            try:
                crosses.append(np.where(paw[frame:end] < threshold)[0][0])
            except IndexError:
                crosses.append(np.nan)

        val = np.nanmax(crosses) + frame
        if val > end or np.isnan(val):
            logger.warning("Error in precise threshold crossing computation")
            return None
        return int(val)
Esempio n. 6
0
def get_session_bouts(
    key: dict,
    tracking: pd.DataFrame,
    is_hairpin: bool,
    speed_th: float,
    max_pause: float,
    min_duration: float,
    min_peak_speed: float,
    min_gcoord_delta: float,
) -> list:
    """
        Gets all the locomotion bouts for an experimental session
    """
    tracking = TrackingData.from_dataframe(tracking)

    # get when the mouse is moving
    is_moving = get_when_moving(
        data_utils.convolve_with_gaussian(tracking.body.speed, 21),
        speed_th,
        max_pause,
        min_duration,
        min_peak_speed,
    )
    # plot_speeds(tracking.body.speed, is_moving=is_moving)

    # get bouts onsets and offsets
    onsets, offsets = get_onset_offset(is_moving, 0.5)
    logger.debug(f"Found {len(onsets)} bouts")

    # fill up all details
    bouts = []
    for bstart, bend in zip(onsets, offsets):
        if bend < bstart:
            raise ValueError("Something went wrong...")

        # get precise bout start and end times based on paw speeds
        bstart, bend = get_bout_start_end_times(tracking, bstart, bend)
        if bstart is None or bend is None:
            continue
        elif bend == len(tracking.body.x):
            bend -= 1

        # remove bouts too close to start and end of recording
        if bstart < 60 or bend > (len(tracking.body.speed) - 60):
            continue

        if is_hairpin:
            # check there's enough change in global coordinate
            okay, gdelta = check_gcoord_delta(
                tracking, bstart, bend, min_gcoord_delta
            )
            if not okay:
                continue

            # get bout direction of movement if hairpin
            direction = get_bout_direction(tracking, bstart, bend)

            # get complete and ROIs
            complete, start_roi, end_roi = get_bout_complete_and_rois(
                tracking, bstart, bend
            )
        else:
            direction, complete = "none", "none"
            start_roi, end_roi = -1, -1
            gdelta = -1

        if bstart in [b["start_frame"] for b in bouts]:
            continue

        # check that there's no movement before/after bout
        if not is_quiet(tracking, bstart, bend, duration=int(0.5 * 60)):
            continue

        # put everything together
        bout = key.copy()
        bout["start_frame"] = bstart
        bout["end_frame"] = bend
        bout["duration"] = (bend - bstart) / 60
        bout["direction"] = direction
        bout["color"] = colors.bout_direction_colors[direction]
        bout["complete"] = complete
        bout["start_roi"] = start_roi
        bout["end_roi"] = end_roi
        bout["gcoord_delta"] = gdelta

        bouts.append(bout)

    n_complete = len([b for b in bouts if b["complete"] == "true"])
    logger.debug(
        f" kept {len(bouts)}/{len(onsets)} ({len(bouts)/len(onsets)*100:.2f} %) bouts of which {n_complete} are complete"
    )
    return bouts
Esempio n. 7
0
_ = draw.Hairpin()

P = [0, 0.125, 1]
colors = make_palette(pink_dark, blue_dark, len(P))
traces = []
for n, p in enumerate(P):
    trace, _ = tp.fit_best_trace(
        control_points,
        center_line,
        K,
        angle_cost=p,
        length_cost=(1 - p) * 5e-3,
    )

    # draw best trace
    X = convolve_with_gaussian(trace.x, kernel_width=11)
    Y = convolve_with_gaussian(trace.y, kernel_width=11)
    traces.append(Path(X, Y))
    draw.Tracking(X, Y, color=colors[n], lw=3)

# %%
# ------------------------------- load tracking ------------------------------ #
_bouts = pd.read_hdf(paths.analysis_folder / "behavior" / "saved_data" /
                     f"complete_bouts.h5")
_bouts = _bouts.loc[_bouts.duration < 8]
print(f"Kept {len(_bouts)} bouts")

bouts = []
for i, bout in _bouts.iterrows():
    bouts.append(LocomotionBout(bout))
        axes[c, rn].axis('off')

# %%
from data.data_utils import convolve_with_gaussian
import seaborn as sns

f = plt.figure(figsize=(20, 12), constrained_layout=True)
f.suptitle(f'{unit.brain_region} - {unit.unit_id}')

axes = f.subplot_mosaic('''
        AABBCCFF
        AADDEEGG
    ''')

unit = units.loc[units.unit_id == 1036].iloc[0]
frate = convolve_with_gaussian(unit.firing_rate)

draw.ROI(roi, ax=axes['A'])
X, Y = [], []
for bout in bouts:
    draw.Tracking(bout.x, bout.y - 2, ax=axes['A'])
    axes['B'].plot(bout.velocity.magnitude, color='k', lw=.5)
    axes['C'].plot(bout.thetadot, color='k', lw=.5)

    axes['D'].plot(frate[bout.start_frame:bout.end_frame])
    X.extend(list(frate[bout.start_frame + 2:bout.end_frame - 2]))
    Y.extend(list(bout.speed))

sns.regplot(X, Y, ax=axes['E'])

starts = [b.start_frame for b in bouts]