Skip to content

Calculate_think_time#122

Open
cgmaiorano wants to merge 4 commits into
mainfrom
73-task-write-trails-time-feature-functions-think_time_
Open

Calculate_think_time#122
cgmaiorano wants to merge 4 commits into
mainfrom
73-task-write-trails-time-feature-functions-think_time_

Conversation

@cgmaiorano
Copy link
Copy Markdown
Collaborator

Resolves #73

Broke up longer function from https://github.com/theBasicScientist/trailsab-proc/blob/main/trails_analyzer.py#L86 into private functions for calculating circle entry time and exit time. Tests behavior for calculating intermediate think times and separate tests for edge cases.

@cgmaiorano cgmaiorano linked an issue Mar 11, 2026 that may be closed by this pull request
6 tasks
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.21%. Comparing base (d4a7571) to head (ca8b78a).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #122      +/-   ##
==========================================
+ Coverage   98.16%   98.21%   +0.04%     
==========================================
  Files          19       19              
  Lines        1145     1177      +32     
==========================================
+ Hits         1124     1156      +32     
  Misses         21       21              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cgmaiorano cgmaiorano marked this pull request as ready for review March 11, 2026 19:01
],
{"B": ("B", 5.0, 5.0, 1.0)},
[{"label": "A", "order": 1}, {"label": "B", "order": 2}],
[("B", "C", 3.0, "B")],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make these expected values have some description to them by either adding a description field or like an inline comment? the id does explain the scenario, but it doesn't explain how the 3.0 was derived.

],
{"B": ("B", 5.0, 5.0, 1.0)},
[{"label": "A", "order": 1}, {"label": "B", "order": 2}],
[],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty much the same comment here as line 153, could we include a description field in the test parameters that explains why no think time is expected?

assert seg.think_time == think_time
assert seg.think_circle_label == circle_label
else:
assert seg.think_time == 0.0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we also check the default think_circle_label which I guess would be an ""

Comment thread tests/unit/test_trails_time.py Outdated
assert [seg.start_label for seg in result] == ["A", "B"]


def test_empty_segments_returns_empty() -> None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about when segments[0].points is empty? we have a guard for it in line 129 on time.py, I feel like we would need a test for that too.

Comment thread src/graphomotor/features/trails/time.py Outdated
@@ -1,5 +1,9 @@
"""Feature extraction module for time-based metrics in trails drawing data."""

from typing import Any, Dict, List, Optional
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nitty gritty but calculate_total_error_time uses dict[str, float] for type hints, so we could keep constistancy.

Comment thread src/graphomotor/features/trails/time.py Outdated
def _find_circle_entry_time(
points: pd.DataFrame, circle: models.CircleTarget
) -> Optional[float]:
"""Find when a point last entered the circle by scanning backwards."""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could use a little more detail to this docstring. This returns the seconds value from the last sampled point that's inside the circle, which is kind of different from calculating or interpolating the boundary-crossing time, which I think this could be interpreted as. We could also just change the function name to something like find_last_time_inside_circle or something like that

Comment thread src/graphomotor/features/trails/time.py Outdated
def _find_circle_exit_time(
points: pd.DataFrame, circle: models.CircleTarget
) -> Optional[float]:
"""Find when a point first left the circle by scanning forward."""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above (line 62), but I also think that we should explain the fallback behavior in the docstring as well.

Comment thread src/graphomotor/features/trails/time.py Outdated
"""
trail_circles = circles[trail_id]
circle_order = {item["label"]: item["order"] for item in config[trail_id]["items"]}
segments = sorted(segments, key=lambda s: circle_order.get(s.start_label, 999))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use float("inf") instead of 999 as sort key fallback? or maybe keep it and put it in the docstring with a logger warning?

Comment thread src/graphomotor/features/trails/time.py Outdated
next_seg.think_time = exit_time - entry_time
next_seg.think_circle_label = circle_label

if not segments or len(segments[0].points) == 0:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we turn these nested ifs into early return guards?

Copy link
Copy Markdown
Collaborator

@kimit0310 kimit0310 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few small things + the nested ifs vs early return guards thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Task: Write Trails Time Feature functions: think_time

3 participants