def test_construct_dataframe(self): df = traja.TrajaDataFrame( {"x": range(len(self.df)), "y": range(len(self.df))}, index=self.df.index, xlim=(0, 2), ylim=(0, 2), spatial_units="m", title="Serious title", fps=2.0, time_units="s", id=42, ) assert df.title == "Serious title" # Test 'merge' df2 = df.copy() assert df2.title == "Serious title" assert df._get_time_col() == None assert self.df._get_time_col() == "Time" # Modify metavar df.set("title", "New title") assert df.title == "New title" # Test __finalize__ df_copy = df.copy() df2_copy = df2.copy() assert isinstance(df_copy, traja.TrajaDataFrame)
def generate( n: int = 1000, random: bool = True, step_length: int = 2, angular_error_sd: float = 0.5, angular_error_dist: Callable = None, linear_error_sd: float = 0.2, linear_error_dist: Callable = None, fps: float = 50, spatial_units: str = "m", seed: int = None, **kwargs, ): """Generates a trajectory. If ``random`` is ``True``, the trajectory will be a correlated random walk/idiothetic directed walk (Kareiva & Shigesada, 1983), corresponding to an animal navigating without a compass (Cheung, Zhang, Stricker, & Srinivasan, 2008). If ``random`` is ``False``, it will be a directed walk/allothetic directed walk/oriented path, corresponding to an animal navigating with a compass (Cheung, Zhang, Stricker, & Srinivasan, 2007, 2008). By default, for both random and directed walks, errors are normally distributed, unbiased, and independent of each other, so are **simple directed walks** in the terminology of Cheung, Zhang, Stricker, & Srinivasan, (2008). This behaviour may be modified by specifying alternative values for the ``angular_error_dist`` and/or ``linear_error_dist`` parameters. The initial angle (for a random walk) or the intended direction (for a directed walk) is ``0`` radians. The starting position is ``(0, 0)``. Args: n (int): (Default value = 1000) random (bool): (Default value = True) step_length: (Default value = 2) angular_error_sd (float): (Default value = 0.5) angular_error_dist (Callable): (Default value = None) linear_error_sd (float): (Default value = 0.2) linear_error_dist (Callable): (Default value = None) fps (float): (Default value = 50) spatial_units: (Default value = 'm') **kwargs: Additional arguments Returns: trj (:class:`traja.frame.TrajaDataFrame`): Trajectory .. note:: Based on Jim McLean's `trajr <https://github.com/JimMcL/trajr>`_, ported to Python. **Reference**: McLean, D. J., & Skowron Volponi, M. A. (2018). trajr: An R package for characterisation of animal trajectories. Ethology, 124(6), 440-448. https://doi.org/10.1111/eth.12739. """ if seed is None: np.random.seed(0) else: np.random.seed(seed) if angular_error_dist is None: angular_error_dist = np.random.normal(loc=0.0, scale=angular_error_sd, size=n - 1) if linear_error_dist is None: linear_error_dist = np.random.normal(loc=0.0, scale=linear_error_sd, size=n - 1) angular_errors = angular_error_dist linear_errors = linear_error_dist step_lengths = step_length + linear_errors # Don't allow negative lengths step_lengths[step_lengths < 0] = 0 steps = polar_to_z(step_lengths, angular_errors) if random: # Accumulate angular errors coords = np.zeros(n, dtype=np.complex) angle = 0 for i in range(n - 1): angle += angular_errors[i] length = step_length + linear_errors[i] coords[i + 1] = coords[i] + polar_to_z(r=length, theta=angle) else: coords = np.append(complex(0), np.cumsum(steps)) x = coords.real y = coords.imag df = traja.TrajaDataFrame(data={"x": x, "y": y}) if fps in (0, None): raise Exception("fps must be greater than 0") df.fps = fps time = df.index / fps df["time"] = time df.spatial_units = spatial_units for key, value in kwargs.items(): df.__dict__[key] = value # Update metavars metavars = dict(angular_error_sd=angular_error_sd, linear_error_sd=linear_error_sd) df.__dict__.update(metavars) return df
def traj_from_coords( track: Union[np.ndarray, pd.DataFrame], x_col=1, y_col=2, time_col: Optional[str] = None, fps: Union[float, int] = 4, spatial_units: str = "m", time_units: str = "s", ) -> TrajaDataFrame: """Create TrajaDataFrame from coordinates. Args: track: N x 2 numpy array or pandas DataFrame with x and y columns x_col: column index or x column name y_col: column index or y column name time_col: name of time column fps: Frames per seconds spatial_units: default m, optional time_units: default s, optional Returns: trj: TrajaDataFrame .. doctest:: >> xy = np.random.random((1000, 2)) >> trj = traja.traj_from_coord(xy) >> assert trj.shape == (1000,4) # columns x, y, time, dt """ if not isinstance(track, traja.TrajaDataFrame): if isinstance(track, np.ndarray) and track.shape[1] == 2: trj = traja.from_xy(track) elif isinstance(track, pd.DataFrame): trj = traja.TrajaDataFrame(track) else: trj = track trj.traja.spatial_units = spatial_units trj.traja.time_units = time_units def rename(col, name, trj): if isinstance(col, int): trj.rename(columns={col: name}) else: if col not in trj: raise Exception(f"Missing column {col}") trj.rename(columns={col: name}) return trj # Ensure column names are as expected trj = rename(x_col, "x", trj) trj = rename(y_col, "y", trj) if time_col is not None: trj = rename(time_col, "time", trj) # Allocate times if they aren't already known if "time" not in trj: if fps is None: raise Exception(( "Cannot create a trajectory without times: either fps or a time column must be specified" )) # Assign times to each frame, starting at 0 trj["time"] = pd.Series(np.arange(0, len(trj)) / fps) # Get displacement time for each coordinate, with the first point at time 0 trj["dt"] = trj.time - trj.time.iloc[0] return trj
def speed_intervals(trj: TrajaDataFrame, faster_than: float = None, slower_than: float = None) -> pd.DataFrame: """Calculate speed time intervals. Returns a dictionary of time intervals where speed is slower and/or faster than specified values. Args: faster_than (float, optional): Minimum speed threshold. (Default value = None) slower_than (float or int, optional): Maximum speed threshold. (Default value = None) Returns: result (:class:`~pd.DataFrame`) -- time intervals as dataframe .. note:: Implementation ported to Python, heavily inspired by Jim McLean's trajr package. .. doctest:: >> df = traja.generate() >> intervals = traja.speed_intervals(df, faster_than=100) >> intervals.head() start_frame start_time stop_frame stop_time duration 0 1 0.02 3 0.06 0.04 1 4 0.08 8 0.16 0.08 2 10 0.20 11 0.22 0.02 3 12 0.24 15 0.30 0.06 4 17 0.34 18 0.36 0.02 """ derivs = get_derivatives(trj) if faster_than is None and slower_than is None: raise Exception( "Parameters faster_than and slower_than are both None, at least one must be provided." ) # Calculate trajectory speeds speed = derivs["speed"].values times = derivs["speed_times"].values times[0] = 0.0 flags = np.full(len(speed), 1) if faster_than is not None: flags = flags & (speed > faster_than) if slower_than is not None: flags = flags & (speed < slower_than) changes = np.diff(flags) stop_frames = np.where(changes == -1)[0] start_frames = np.where(changes == 1)[0] # Handle situation where interval begins or ends outside of trajectory if len(start_frames) > 0 or len(stop_frames) > 0: # Assume interval started at beginning of trajectory, since we don't know what happened before that if len(stop_frames) > 0 and (len(start_frames) == 0 or stop_frames[0] < start_frames[0]): start_frames = np.append(1, start_frames) # Similarly, assume that interval can't extend past end of trajectory if (len(stop_frames) == 0 or start_frames[len(start_frames) - 1] > stop_frames[len(stop_frames) - 1]): stop_frames = np.append(stop_frames, len(speed) - 1) stop_times = times[stop_frames] start_times = times[start_frames] durations = stop_times - start_times result = traja.TrajaDataFrame( OrderedDict( start_frame=start_frames, start_time=start_times, stop_frame=stop_frames, stop_time=stop_times, duration=durations, )) return result
""" Plotting with traja ----------------------------------- `traja <https://traja.readthedocs.io>`_ is a Python library providing a selection of easy-to-use spatial visualizations. It is built on top of pandas and is designed to work with a range of libraries. For more details on the library refer to its documentation. First we'll load in data using traja. """ import traja df = traja.TrajaDataFrame({'x': [0, 1, 2, 3, 4], 'y': [1, 3, 2, 4, 5]}) ############################################################################### # Plotting with Traja # ===================== # # We start out by plotting a basic sime series trajectory using the ``traja`` # accessor and ``.plot()`` method. df.traja.plot() ############################################################################### # Generate Random Walks # ===================== # # Also, random walks can be generated using ``generate``. df = traja.generate(n=1000, random=True, fps=30) df.traja.plot() ############################################################################### # Traja can re-scale data with any units
def generate(n=1000, random=True, step_length=2, angular_error_sd=0.5, angular_error_dist=None, linear_error_sd=0.2, linear_error_dist=None, fps=50, spatial_units='m', seed=None, **kwargs): """Generates a trajectory. If `random` is `True`, the trajectory will be a correlated random walk/idiothetic directed walk (Kareiva & Shigesada, 1983), corresponding to an animal navigating without a compass (Cheung, Zhang, Stricker, & Srinivasan, 2008). If `random` is `False`, it will be a directed walk/allothetic directed walk/oriented path, corresponding to an animal navigating with a compass (Cheung, Zhang, Stricker, & Srinivasan, 2007, 2008). By default, for both random and directed walks, errors are normally distributed, unbiased, and independent of each other, so are **simple directed walks** in the terminology of Cheung, Zhang, Stricker, & Srinivasan, (2008). This behaviour may be modified by specifying alternative values for the `angularErrorDist` and/or `linearErrorDist` parameters. The initial angle (for a random walk) or the intended direction (for a directed walk) is `0` radians. The starting position is `(0, 0)`. .. note:: Author: Jim McLean (trajr), ported to Python by Justin Shenk. Args: n: (Default value = 1000) random: (Default value = True) step_length: (Default value = 2) angular_error_sd: (Default value = 0.5) angular_error_dist: (Default value = None) linear_error_sd: (Default value = 0.2) linear_error_dist: (Default value = None) fps: (Default value = 50) spatial_units: (Default value = 'm') **kwargs: Returns: """ if seed is None: np.random.seed(0) if angular_error_dist is None: angular_error_dist = np.random.normal(loc=0., scale=angular_error_sd, size=n) if linear_error_dist is None: linear_error_dist = np.random.normal(loc=0., scale=linear_error_sd, size=n) angular_errors = angular_error_dist linear_errors = linear_error_dist step_lengths = step_length + linear_errors # Don't allow negative lengths step_lengths[step_lengths < 0] = 0 steps = polar_to_z(step_lengths, angular_errors) if random: # Accumulate angular errors coords = np.zeros(n + 1, dtype=np.complex) angle = 0 for i in range(n): angle += angular_errors[i] length = step_length + linear_errors[i] coords[i + 1] = coords[i] + polar_to_z(r=length, theta=angle) else: coords = np.append(complex(0), np.cumsum(steps)) x = coords.real y = coords.imag df = traja.TrajaDataFrame(data={'x': x, 'y': y}) if fps in (0, None): raise Exception("fps must be greater than 0") df.fps = fps time = df.index / fps df['time'] = time df.spatial_units = spatial_units for key, value in kwargs.items(): df.__dict__[key] = value # Update metavars metavars = dict(angular_error_sd=angular_error_sd, linear_error_sd=linear_error_sd) df.__dict__.update(metavars) return df
def speed_intervals( trj: TrajaDataFrame, faster_than: float = None, slower_than: float = None, interpolate_times: bool = True, ): """Calculate speed time intervals. Returns a dictionary of time intervals where speed is slower and/or faster than specified values. Args: faster_than (float, optional): Minimum speed threshold. (Default value = None) slower_than (float or int, optional): Maximum speed threshold. (Default value = None) interpolate_times (bool, optional): Interpolate times between steps. (Default value = True) Returns: result (:class:`~collections.OrderedDict`) -- time intervals as dictionary. .. note:: Implementation ported to Python, heavily inspired by Jim McLean's trajr package. """ derivs = get_derivatives(trj) if faster_than is not None: pass if slower_than is not None: pass # Calculate trajectory speeds speed = derivs["speed"] times = derivs["speed_times"] flags = np.full(len(speed), 1) if faster_than is not None: flags = flags & (speed > faster_than) if slower_than is not None: flags = flags & (speed < slower_than) changes = np.diff(flags) stop_frames = np.where(changes == -1)[0] start_frames = np.where(changes == 1)[0] # Handle situation where interval begins or ends outside of trajectory if len(start_frames) > 0 or len(stop_frames) > 0: # Assume interval started at beginning of trajectory, since we don't know what happened before that if len(stop_frames) > 0 and ( len(start_frames) == 0 or stop_frames[0] < start_frames[0] ): start_frames = np.append(1, start_frames) # Similarly, assume that interval can't extend past end of trajectory if ( len(stop_frames) == 0 or start_frames[len(start_frames) - 1] > stop_frames[len(stop_frames) - 1] ): stop_frames = np.append(stop_frames, len(speed)) stop_times = times[stop_frames] start_times = times[start_frames] if interpolate_times and len(start_frames) > 0: # TODO: Implement raise NotImplementedError() r = linear_interp_times( slower_than, faster_than, speed, times, start_frames, start_times ) start_times = r[:, 0] stop_times = r[:, 1] durations = stop_times - start_times result = traja.TrajaDataFrame( OrderedDict( start_frame=start_frames, start_time=start_times, stop_frame=stop_frames, stop_time=stop_times, duration=durations, ) ) return result
""" 3D Plotting with traja ---------------------- Plot trajectories with time in the vertical axis. Note: Adjust matplotlib args ``dist``, ``labelpad``, ``aspect`` and ``adjustable``` as needed. """ import traja df = traja.TrajaDataFrame({"x": [0, 1, 2, 3, 4], "y": [1, 3, 2, 4, 5]}) trj = traja.generate() ax = trj.traja.plot_3d(dist=15, labelpad=32, title="Traja 3D Plot") ######## # Colors # ------- # # `Matplotlib cmaps<https://matplotlib.org/examples/color/colormaps_reference.html>`_ are available trj.traja.plot_3d(dist=15, labelpad=32, title="Traja 3D Plot", cmap="jet")
def getValuesFrom(day,header,cur_data): for i in range(len(header)): if header[i] == "Worm ID": id_head = i elif header[i] == "Area": area_head = i elif header[i] == "Shade": shade_head = i elif header[i] == "Cumulative Angle": cml_angle_head = i elif header[i] == "Length": l_head = i elif header[i] == "Max Width": mxw_head = i elif header[i] == "Mid Width": mdw_head = i elif header[i] == "Diagonals": dgl_head = i elif header[i] == "x1": x1_head = i elif header[i] == "x2": x2_head = i elif header[i] == "y1": y1_head = i elif header[i] == "y2": y2_head = i elif header[i] == "# Video Frame" or header[i] == "Video Frame": frame_head = i avg_area = sum(cur_data[area_head])/len(cur_data[area_head]) avg_shade = sum(cur_data[shade_head])/len(cur_data[shade_head]) angle_variance = np.var(cur_data[cml_angle_head]) avg_length = sum(cur_data[l_head])/len(cur_data[l_head]) avg_mxw = sum(cur_data[mxw_head])/len(cur_data[mxw_head]) avg_mdw = sum(cur_data[mdw_head])/len(cur_data[mdw_head]) diagonal_variance = np.var(cur_data[dgl_head]) # Approximate total traveled distance # TODO: Threshold of change (<2.5?) total_travel = calcTravel(cur_data[x1_head],cur_data[y1_head],cur_data[x2_head],cur_data[y2_head]) travel_speed = total_travel / (cur_data[0][-1] - cur_data[0][0]) # TODO: Traja... stuff? x_arr = [] y_arr = [] time_arr = [] point_arr = [] for i in range(len(cur_data[x1_head])): x_arr.append((cur_data[x1_head][i] + cur_data[x2_head][i])/2) y_arr.append((cur_data[y1_head][i] + cur_data[y2_head][i])/2) time_arr.append(cur_data[frame_head][i]) point_arr.append([x_arr[-1],y_arr[-1]]) # TODO: Check if able to set noise of movement (extended or smaller groupings of motion) df = trj.TrajaDataFrame({'x':x_arr,'y':y_arr,'time':time_arr}) df_derivs = df.traja.get_derivatives() if SHOW_MOTION: plt.plot(df['x'],df['y']) avg_accel = np.nanmean(df_derivs["acceleration"]) max_accel = np.nanmax(df_derivs["acceleration"]) max_speed = np.nanmax(df_derivs["speed"]) avg_speed = np.nanmean(df_derivs["speed"]) point0 = ((cur_data[x1_head][0] + cur_data[x2_head][0])/2, (cur_data[y1_head][0] + cur_data[y2_head][0])/2) last_point = ((cur_data[x1_head][-1] + cur_data[x2_head][-1])/2, (cur_data[y1_head][-1] + cur_data[y2_head][-1])/2) rvr_sinuosity_index = total_travel / ci.pointDistance(point0,last_point) #try: clustP = sc.makeFractionedClusters(point_arr,8) if SHOW_MOTION: x, y = zip(*clustP) plt.scatter(x,y) plt.show() sinuosity_index = trajSinIndex(clustP) #except: # return np.array([float(day),cur_data[id_head][0],avg_area,avg_shade,angle_variance,avg_length,avg_mxw,avg_mdw,diagonal_variance,total_travel,travel_speed,avg_speed,max_speed,max_accel,avg_accel,rvr_sinuosity_index,sinuosity_index]) return np.array([float(day),cur_data[id_head][0],avg_area,avg_shade,angle_variance,avg_length,avg_mxw,avg_mdw,diagonal_variance,total_travel,travel_speed,avg_speed,max_speed,max_accel,avg_accel,rvr_sinuosity_index,sinuosity_index])