Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
"""
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
"""
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")
Ejemplo n.º 9
0
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])