Compare L2, Fréchet, and DTW conclusions¶
This example asks whether the same small set of trajectories has similar pairwise ordering and local neighbors under three different distance contracts.
Construct trajectories¶
import numpy as np
from eyetrajectoriespy import TrajectorySet
time = np.linspace(0.0, 1.0, 7)
curves = np.array([
[0.0, 0.1, 0.4, 0.9, 1.5, 2.2, 3.0],
[0.0, 0.0, 0.1, 0.4, 0.9, 1.5, 2.2],
[0.0, 0.2, 0.8, 1.4, 1.9, 2.4, 2.8],
[3.0, 2.4, 1.8, 1.1, 0.6, 0.2, 0.0],
])
values = np.stack([
np.column_stack([curve, 0.35 * curve**2])
for curve in curves
])
gaze = TrajectorySet(
time=time,
values=values,
curve_ids=("A", "B", "C", "D"),
dimension_names=("x", "y"),
coordinate_system="unknown",
time_unit="s",
)
Declare three distance contracts¶
from eyetrajectoriespy import trajectory_distance_sensitivity
result = trajectory_distance_sensitivity(
gaze,
specifications=(
{"name": "l2", "method": "functional_l2"},
{"name": "frechet", "method": "discrete_frechet"},
{
"name": "dtw_norm",
"method": "dtw",
"step_pattern": "symmetric2",
"normalize": True,
"window_radius": None,
},
),
dimensions=("x", "y"),
dimension_weights=(1.0, 0.5),
neighbor_k=2,
)
The same selected dimensions and dimension weights are used in all three distance contracts.
Inspect global agreement¶
from eyetrajectoriespy import trajectory_distance_comparison_frame
comparison = trajectory_distance_comparison_frame(result)
print(comparison[
[
"specification_a",
"specification_b",
"spearman_rank_correlation",
"mean_absolute_rank_difference",
"mean_top_k_neighbor_jaccard",
"nearest_neighbor_identity_agreement_fraction",
]
])
The rank correlation compares all unique curve pairs. It is descriptive and has no ordinary correlation p-value.
Inspect local neighbor changes¶
from eyetrajectoriespy import trajectory_distance_neighbor_frame
neighbors = trajectory_distance_neighbor_frame(result)
print(neighbors[
[
"specification_a",
"specification_b",
"curve_id",
"neighbors_a",
"neighbors_b",
"jaccard",
"nearest_neighbor_match",
"cutoff_tie_a",
"cutoff_tie_b",
]
])
This can show cases where two distance methods have similar global ordering but still disagree on the nearest comparison trajectory for a particular trial.
Plot the specification agreement matrix¶
from eyetrajectoriespy import plot_trajectory_distance_rank_correlations
ax = plot_trajectory_distance_rank_correlations(result)
Produce reporting text¶
from eyetrajectoriespy import trajectory_distance_sensitivity_reporting_text
print(trajectory_distance_sensitivity_reporting_text(result))
Interpretation¶
The goal is not to choose the metric with the highest agreement. The goal is to determine whether claims based on "similar trajectories" survive across the distance definitions that were scientifically defensible before viewing the result.
The executable counterpart is
examples/trajectory_distance_sensitivity.py.