graphomotor.features.velocity

Feature extraction module for velocity-based metrics in spiral drawing data.

 1"""Feature extraction module for velocity-based metrics in spiral drawing data."""
 2
 3import numpy as np
 4from scipy import stats
 5
 6from graphomotor.core import models
 7
 8
 9def _calculate_statistics(values: np.ndarray, name: str) -> dict[str, float]:
10    """Helper function to calculate statistics for a given array.
11
12    Args:
13        values: 1-D Numpy array of numerical values.
14        name: Name prefix for the statistics (e.g., "linear_velocity").
15
16    Returns:
17        Dictionary containing calculated metrics (sum, median, variation, skewness,
18        kurtosis) with keys prefixed by the provided name.
19    """
20    return {
21        f"{name}_sum": np.sum(np.abs(values)),
22        f"{name}_median": np.median(np.abs(values)),
23        f"{name}_coefficient_of_variation": stats.variation(values),
24        f"{name}_skewness": stats.skew(values),
25        f"{name}_kurtosis": stats.kurtosis(values),
26    }
27
28
29def calculate_velocity_metrics(spiral: models.Spiral) -> dict[str, float]:
30    """Calculate velocity-based metrics from spiral drawing data.
31
32    This function computes three types of velocity metrics by calculating the difference
33    between consecutive points in the spiral drawing data. The three types of velocity
34    are:
35
36    1. **Linear velocity**: The magnitude of change of Euclidean distance in pixels
37       per second. This is calculated as the square root of the sum of squares of
38       the differences in x and y coordinates divided by the difference in time.
39    2. **Radial velocity**: The magnitude of change of distance from center (radius) in
40       pixels per second. Radius is calculated as the square root of the sum of
41       squares of x and y coordinates.
42    3. **Angular velocity**: The magnitude of change of angle in radians per second.
43       Angle is calculated using the arctangent of y coordinates divided by x
44       coordinates, and then unwrapped to maintain continuity across the -π to π
45       boundary.
46
47    For each velocity type, the following metrics are calculated:
48
49    - **Sum**: Sum of absolute velocity values
50    - **Median**: Median of absolute velocity values
51    - **Coefficient of variation**: Standard deviation divided by the mean
52    - **Skewness**: Asymmetry of the velocity distribution
53    - **Kurtosis**: Tailedness of the velocity distribution
54
55    Args:
56        spiral: Spiral object containing drawing data.
57
58    Returns:
59        Dictionary containing calculated velocity metrics.
60    """
61    x = spiral.data["x"].values
62    y = spiral.data["y"].values
63    time = spiral.data["seconds"].values
64    radius = np.sqrt(x**2 + y**2)
65    theta = np.unwrap(np.arctan2(y, x))
66
67    dx = np.diff(x)
68    dy = np.diff(y)
69    dt = np.diff(time)
70    dr = np.diff(radius)
71    dtheta = np.diff(theta)
72
73    linear_velocity = np.sqrt(dx**2 + dy**2) / dt
74    radial_velocity = dr / dt
75    angular_velocity = dtheta / dt
76
77    return {
78        **_calculate_statistics(linear_velocity, "linear_velocity"),
79        **_calculate_statistics(radial_velocity, "radial_velocity"),
80        **_calculate_statistics(angular_velocity, "angular_velocity"),
81    }
def calculate_velocity_metrics(spiral: graphomotor.core.models.Spiral) -> dict[str, float]:
30def calculate_velocity_metrics(spiral: models.Spiral) -> dict[str, float]:
31    """Calculate velocity-based metrics from spiral drawing data.
32
33    This function computes three types of velocity metrics by calculating the difference
34    between consecutive points in the spiral drawing data. The three types of velocity
35    are:
36
37    1. **Linear velocity**: The magnitude of change of Euclidean distance in pixels
38       per second. This is calculated as the square root of the sum of squares of
39       the differences in x and y coordinates divided by the difference in time.
40    2. **Radial velocity**: The magnitude of change of distance from center (radius) in
41       pixels per second. Radius is calculated as the square root of the sum of
42       squares of x and y coordinates.
43    3. **Angular velocity**: The magnitude of change of angle in radians per second.
44       Angle is calculated using the arctangent of y coordinates divided by x
45       coordinates, and then unwrapped to maintain continuity across the -π to π
46       boundary.
47
48    For each velocity type, the following metrics are calculated:
49
50    - **Sum**: Sum of absolute velocity values
51    - **Median**: Median of absolute velocity values
52    - **Coefficient of variation**: Standard deviation divided by the mean
53    - **Skewness**: Asymmetry of the velocity distribution
54    - **Kurtosis**: Tailedness of the velocity distribution
55
56    Args:
57        spiral: Spiral object containing drawing data.
58
59    Returns:
60        Dictionary containing calculated velocity metrics.
61    """
62    x = spiral.data["x"].values
63    y = spiral.data["y"].values
64    time = spiral.data["seconds"].values
65    radius = np.sqrt(x**2 + y**2)
66    theta = np.unwrap(np.arctan2(y, x))
67
68    dx = np.diff(x)
69    dy = np.diff(y)
70    dt = np.diff(time)
71    dr = np.diff(radius)
72    dtheta = np.diff(theta)
73
74    linear_velocity = np.sqrt(dx**2 + dy**2) / dt
75    radial_velocity = dr / dt
76    angular_velocity = dtheta / dt
77
78    return {
79        **_calculate_statistics(linear_velocity, "linear_velocity"),
80        **_calculate_statistics(radial_velocity, "radial_velocity"),
81        **_calculate_statistics(angular_velocity, "angular_velocity"),
82    }

Calculate velocity-based metrics from spiral drawing data.

This function computes three types of velocity metrics by calculating the difference between consecutive points in the spiral drawing data. The three types of velocity are:

  1. Linear velocity: The magnitude of change of Euclidean distance in pixels per second. This is calculated as the square root of the sum of squares of the differences in x and y coordinates divided by the difference in time.
  2. Radial velocity: The magnitude of change of distance from center (radius) in pixels per second. Radius is calculated as the square root of the sum of squares of x and y coordinates.
  3. Angular velocity: The magnitude of change of angle in radians per second. Angle is calculated using the arctangent of y coordinates divided by x coordinates, and then unwrapped to maintain continuity across the -π to π boundary.

For each velocity type, the following metrics are calculated:

  • Sum: Sum of absolute velocity values
  • Median: Median of absolute velocity values
  • Coefficient of variation: Standard deviation divided by the mean
  • Skewness: Asymmetry of the velocity distribution
  • Kurtosis: Tailedness of the velocity distribution
Arguments:
  • spiral: Spiral object containing drawing data.
Returns:

Dictionary containing calculated velocity metrics.