Analyze: Aggregate Result Statistics¶
After a movie is traced, the Analyze page computes aggregate statistics from the
per-frame trackpoint data, in addition to the position-vs-time charts. The
calculations are ported from the legacy iOS app’s showResult() and live in the
pure, DOM-free module src/app/static/analysis_results.mjs (issue #986). The
display wiring lives in canvas_tracer_controller.mjs (display_results()).
Result modes¶
A selector on the Analyze page (#result-mode-select) chooses which statistics
to show:
All (default) — both groups below.
Gravitropism — Distance and Angle.
Circumnutation — Max Amplitude.
The tracked “tip” marker is the Apex if present, otherwise the first graphable (non-ruler) marker. Ruler markers set the millimeter scale; when two or more are present, distances are reported in mm, otherwise in pixels.
Gravitropism¶
Computed from the tip in the first and last (trimmed) frames, and the Inflection Point marker (see Reserved marker names below).
Distance — Euclidean displacement of the tip from first to last frame, multiplied by the scale.
Angle — the bend at the inflection pivot, via the law of cosines. With
b= first-tip→first-inflection,c= last-tip→last-inflection, anda= first-tip→last-tip:angle = acos((b² + c² − a²) / (2·b·c)) · 180/π
The inflection point is tracked per frame, so
buses its first-frame position andcits last-frame position. The angle is scale-invariant. It is omitted when no inflection point is present or the triangle is degenerate (a tip coincides with the inflection point).
Circumnutation¶
Max Amplitude — horizontal range of the tip over all (trimmed) frames,
(max x − min x) × scale.Rate —
Max Amplitude ÷ elapsed time between the x-extreme frames(legacy semantics; see #1053). Null when the extremes fall on the same frame.
Rate and the capture interval (fpm)¶
Rate is displacement per unit time. The time base is the capture interval
fpm (frames per minute), a per-movie value the user supplies at upload or on the
Analyze page (#1056). The conversion is:
elapsed_time(min) = frame_span ÷ fpm
Gravitropism Rate =
Distance ÷ elapsed_timeover the first→last frame.Circumnutation Rate =
Max Amplitude ÷ elapsed_timebetween the frames of the minimum and maximum x.
When fpm is unset (legacy movies, or not yet entered), the graph x-axis stays in
frames and Rate is reported per frame (mm/frame or pixel/frame); once a
positive fpm is set it is reported per minute. fpm is distinct from the
encoded playback fps and is stored as a string on the movie row (authoritative)
with a best-effort snapshot in the traced MP4 (see
Movie attribution and research metadata). Editing fpm on the Analyze page only rescales time and
rate — it does not require retracing.
This replaces the legacy frames × 20 ÷ framerate formula (an iOS playback-time
artifact); the FPS = 20 constant is not used.
Reserved marker names¶
Two marker names are reserved and given special treatment:
Ruler Nmm(e.g.Ruler 0mm,Ruler 10mm) — define the mm/pixel scale; excluded from graphing.Inflection Point(matched case-insensitively) — the gravitropism pivot. It is tracked and graphed like any plant marker, but its reserved name lets the dedicated Add Inflection Point button and the Angle calculation locate it. Only one is allowed per movie. See issue #1033.