def compute_averaged_quantities(body_parts_tracking: dict) -> dict: """ For some things like orientation average across body parts to reduce noise """ # import matplotlib.pyplot as plt def unwrap(x): return np.degrees(np.unwrap(np.radians(x))) # get data body = pd.DataFrame(body_parts_tracking["body"]).interpolate(axis=0) tail_base = pd.DataFrame( body_parts_tracking["tail_base"]).interpolate(axis=0) # get speed & acceleration results = dict(speed=body.bp_speed.values.copy()) results["acceleration"] = derivative(results["speed"]) # get direction of movement path = Path(body.x, body.y).smooth() results["theta"] = path.theta results["thetadot"] = path.thetadot # deg/s results["thetadotdot"] = path.thetadotdot # in deg / s^2 # compute orientation of the body results["orientation"] = orientation(tail_base.x, tail_base.y, body.x, body.y) # compute angular velocity in deg/s results["angular_velocity"] = (angular_derivative(results["orientation"]) * 60) # in deg/s return results
def average_xy_trajectory(paths: List[Path], rescale: bool = False) -> Path: ''' Computes the average XY trajectory from a set of paths, rescaling them in time if necessary ''' if rescale: paths = time_rescale(paths) X = np.mean(np.vstack([path.x for path in paths]), 0) Y = np.mean(np.vstack([path.y for path in paths]), 0) return Path(X, Y)
def BSpline( x: np.ndarray, y: np.ndarray, n_path_points: int = 500, degree=3, cut: float = 0.06, fps: int = 60, ) -> Path: ipl_t = np.linspace(0.0, len(x) - 1, len(x)) spl_i_x = scipy_interpolate.make_interp_spline(ipl_t, x, k=degree) spl_i_y = scipy_interpolate.make_interp_spline(ipl_t, y, k=degree) travel = np.linspace(0.0, len(x) - 1, n_path_points) if cut: cut = int(cut * n_path_points) return Path(spl_i_x(travel)[cut:-cut], spl_i_y(travel)[cut:-cut], fps=fps) else: return Path(spl_i_x(travel), spl_i_y(travel), fps=fps)
def fit_best_trace( control_points: dict, center_line: Path, k: int, angle_cost: float = 1, length_cost: float = 1, ) -> Tuple[Path, Path]: """ Fits a best trace through the arena based on the cost for length and angle. It returns a Path with the best trace and one with the best trace in the track's coordinates system """ node_values = compute_nodes_values(control_points, k, angle_cost=angle_cost, length_cost=length_cost) n = 1 prev = 0 node = int(k / 2) trace = [node] while n < len(node_values) - 1: # get the next best node, at this node and coming from the previous next_best = node_values[n][node].next_best_node[prev] prev = node node = int(next_best) trace.append(node) n += 1 trace_path = Path( [control_points[n][v].x for n, v in enumerate(trace)], [control_points[n][v].y for n, v in enumerate(trace)], ) trace_to_track = TCS.path_to_track_coordinates_system( center_line, trace_path) return trace_path, trace_to_track
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
from data import paths from data.data_structures import LocomotionBout import draw from data.dbase._tracking import calc_angular_velocity from kinematics.msd import MSD from kinematics import time from geometry import Path from matplotlib import rc rc("font", **{"family": "sans-serif", "sans-serif": ["Helvetica"]}) rc("text", usetex=False) folder = Path( # r"/Users/federicoclaudi/Dropbox (UCL)/Rotation_vte/Presentations/Presentations/Fiete lab" r'D:\Dropbox (UCL)\Rotation_vte\Presentations\Presentations\Fiete lab' ) recorder.start( base_folder=folder.parent, folder_name=folder.name, timestamp=False ) """ Fit MSD model to turn trajectories in mice """ # %% # load and clean roi crossings ROI = "T3" MIN_DUR = 1.3 _bouts = pd.read_hdf(
def fit(self) -> Path: for i in range(len(self.waypoints) - 1): self.fit_segment(self.waypoints[i], self.waypoints[i + 1]) return Path(self.x, self.y, self.theta)
def animate_one(ROI: str, crossing_id: int, FPS: int): scale = 1 / 30 # to scale velocity vectors save_folder = (paths.analysis_folder / "behavior" / "roi_crossings_animations") # ----------------------------------- prep ----------------------------------- # # load tracking bouts = pd.read_hdf(paths.analysis_folder / "behavior" / "roi_crossings" / f"{ROI}_crossings.h5") bout = bouts.sort_values("duration").iloc[crossing_id] logger.info(f"Animating bout {crossing_id} - {round(bout.duration, 2)}s") # tracking: dict = ROICrossing.get_crossing_tracking(bout.crossing_id) # generate a path from tracking path = Path(bout.x, bout.y) # create fig and start camera if ROI == "T4": f = plt.figure(figsize=(12, 12)) elif "S" in ROI: f = plt.figure(figsize=(8, 14)) else: f = plt.figure(figsize=(5, 14)) axes = f.subplot_mosaic(""" AA AA BB """) camera = Camera(f) # ----------------------------------- plot ----------------------------------- # n_interpolated_frames = int(60 / FPS) n_frames = len(bout.x) - 1 trajectory = GrowingPath() for frame in track(range(n_frames), total=n_frames): # repeat each frame N times interpolating between frames for interpol in np.linspace(0, 1, n_interpolated_frames): # get interpolated quantities x = interpolate_at_frame(path.x, frame, interpol) y = interpolate_at_frame(path.y, frame, interpol) speed = interpolate_at_frame(path.speed, frame, interpol) trajectory.update(x, y, speed=speed) # time elapsed _time = (np.arange(len(trajectory.speed)) / n_interpolated_frames / 60) # plot the arena draw.ROI(ROI, set_ax=True, shade=False, ax=axes["A"]) # plot tracking so far draw.Tracking(trajectory.x, trajectory.y, lw=3, ax=axes["A"]) draw.Dot(x, y, s=50, ax=axes["A"]) # plot speed and velocity vectors draw.Arrow( x, y, interpolate_at_frame(path.velocity.angle, frame, interpol, method="step"), L=scale * interpolate_at_frame(path.velocity.magnitude, frame, interpol), color=colors.velocity, outline=True, width=2, ax=axes["A"], ) draw.Arrow( x, y, path.acceleration.angle[frame], L=4 * scale * path.acceleration.magnitude[frame], color=colors.acceleration, outline=True, width=2, ax=axes["A"], zorder=200, ) # plot speed trace axes["B"].fill_between(_time, 0, trajectory.speed, alpha=0.5, color=colors.speed) axes["B"].plot(_time, trajectory.speed, lw=4, color=colors.speed) axes["A"].set(title=f"{ROI} - crossing: {crossing_id}") axes["B"].set(xlabel="time (s)", ylabel="speed (cm/s)") camera.snap() # ------------------------------- video creation ------------------------------- # save_path = save_folder / f"{ROI}_{bout.crossing_id}.mp4" logger.info(f"Saving animation @: '{save_path}'") animation = camera.animate(interval=1000 / FPS) animation.save(save_path, fps=FPS) logger.info("Done!") plt.cla() plt.close(f) del camera del animation # ----------------------------------- plot ----------------------------------- # f = plot_roi_crossing(bout, step=4) recorder.add_figures(svg=False) plt.close(f)
def plot_roi_crossing( crossing: pd.Series, tracking: dict = None, step: int = 5, highlight: str = None, arrow_scale=0.5, ) -> plt.Figure: """ Plots an entire ROI crossing, tracking, vectors and mouse """ if highlight == "velocity": v_alpha, a_alpha = 1, 0.4 elif highlight == "acceleration": v_alpha, a_alpha = 0.4, 1 else: v_alpha, a_alpha = 1, 1 # path = Path( # convolve_with_gaussian(crossing.x, kernel_width=11), # convolve_with_gaussian(crossing.y, kernel_width=11)) path = Path(crossing.x, crossing.y) f = plt.figure(figsize=(20, 10)) axes = f.subplot_mosaic( """ AACC AADD BBEE """ ) f._save_name = ( f"{crossing.roi}_{crossing.crossing_id}" + "" if highlight is None else highlight ) # draw main crossing plot draw.ROI(crossing.roi, ax=axes["A"], set_ax=True) draw.Tracking(path.x, path.y, lw=0.5, color="k", ax=axes["A"]) # draw velocity and acceleartion vectors draw.Arrows( path.x, path.y, path.velocity.angle, label="velocity", L=arrow_scale * path.velocity.magnitude / 30, step=step, color=colors.velocity, ax=axes["A"], outline=True, alpha=v_alpha, ) draw.Arrows( path.x, path.y, path.acceleration.angle, label="acceleration", L=arrow_scale * 6 * path.acceleration.magnitude / 30, step=step, color=colors.acceleration, ax=axes["A"], outline=True, alpha=a_alpha, ) draw.Tracking.scatter( path.x[::step], path.y[::step], color="k", ax=axes["A"], zorder=200, ) # draw speed traces time = np.arange(len(path.speed)) / 60 axes["B"].fill_between(time, 0, path.speed, alpha=0.5, color=colors.speed) axes["B"].plot( time, path.speed, lw=4, color=colors.speed, ) if tracking is not None: for bp in PAWS: axes["C"].plot( tracking[bp]["bp_speed"], color=colors.bodyparts[bp], label=bp ) axes["C"].plot( tracking["body"]["bp_speed"], color=colors.bodyparts["body"], label="body", ) axes["C"].plot( np.mean( np.vstack( [tracking[bp]["bp_speed"] for bp in PAWS if "h" in bp] ), 0, ), color="k", label="mean", ) # clean plots axes["A"].legend() axes["B"].set(xlabel="time (s)", ylabel="speed (cm/s)") axes["C"].legend() f.tight_layout() return f
ROI = "T1" # load tracking bouts = pd.read_hdf( f"/Users/federicoclaudi/Dropbox (UCL)/Rotation_vte/Locomotion/analysis/behavior/roi_crossings/{ROI}_crossings.h5" ) selected_bouts = bouts.sample(6).reset_index() # draw stuff f, axes = plt.subplots(figsize=(18, 12), ncols=3, nrows=2) axes = axes.flatten() for i, bout in selected_bouts.iterrows(): # generate a path from tracking path = Path(bout.x, bout.y) ax = axes[i] # draw arena and tracking draw.ROI(ROI, set_ax=True, shade=False, ax=ax) # draw.Tracking(bouts.x, bouts.y, alpha=0.5) # draw bout tracking and velocity/acceleration vectors # draw.Tracking.scatter(path.x, path.y, c=path.tangent.angle, cmap='bwr', vmin=-180, vmax=180) draw.Tracking(path.x, path.y, color=[0.6, 0.6, 0.6], lw=5, ax=ax) draw.Arrows( path.x, path.y, path.velocity.angle,
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)) # %% # ----------------------------------- plot ----------------------------------- #
# %% ( left_line, center_line, right_line, left_to_track, center_to_track, right_to_track, control_points, ) = track.extract_track_from_image( points_spacing=1, restrict_extremities=False, apply_extra_spacing=False, ) tracking = Path(tracking_db.x[fast], tracking_db.y[fast]) linearized = TCS.path_to_track_coordinates_system(center_line, tracking) # %% from fcutils.maths import derivative unit = units.iloc[0] spikes = np.zeros_like(tracking_db.x) spikes[unit.spikes] = 1 direction = derivative(tracking_db.global_coord) direction[direction > 0] = 1 direction[direction < 0] = -1 data = pd.DataFrame(
set_ax=True, # img_path=r'C:\Users\Federico\Documents\GitHub\pysical_locomotion\draw\hairpin.png' img_path="/Users/federicoclaudi/Documents/Github/LocomotionControl/draw/hairpin.png", ) all_xy_vectors = { "velocity": {}, "acceleration": {}, } # stores vectors at each XY position, for averaging scale_factor = {"velocity": 1 / 80, "acceleration": 1 / 5} for vn, (vec_name, xy_vectors) in enumerate(all_xy_vectors.items()): ax = axes[vn] for n, (i, cross) in enumerate(bouts.iterrows()): path = Path(cross.x, cross.y) cross_bins = [] for t, (x, y) in enumerate(zip(path.x.round(0), path.y.round(0))): if (x, y) in cross_bins: continue # avoid repeated sampling of same location # add entry to dictionary if (x, y) not in xy_vectors.keys(): xy_vectors[(x, y)] = [] xy_vectors[(x, y)].append(path[vec_name][t]) cross_bins.append((x, y)) # draw stuff for (x, y), vecs in xy_vectors.items():