Post-run diagnostic suite for mt_clean_track results
Source:R/mt_diagnose_clean_track.R
mt_diagnose_clean_track.RdSix diagnostic panels that let you eyeball whether an
mt_clean_track run was healthy. Analogous to
plot.lm() for a linear model: each panel addresses a
distinct failure mode and prints a brief interpretive note
pointing at a remedy when something looks off.
Arguments
- x
A
move2object returned bymt_clean_trackwithremove = FALSE. Must carry the flag columns the orchestrator attaches (is_outlier,flagged_by_*,flag_iteration,error_class).- individual
For multi-track input, the track id to focus the first five panels on. Default
NULLpicks the individual with the highest flag rate (the one most worth diagnosing). Pass any track id to override.- window_days
Numeric. Width of the rolling window (in days) used by Panel 2. Default 7. Larger windows smooth more; smaller windows resolve finer time-localised flag clusters.
- plot
Logical. If
TRUE(default), render the six- panel figure. SetFALSEto skip plotting and just receive the diagnostic data.- silent
Logical. If
FALSE(default), print the interpretive notes for each panel that tripped a concern. SetTRUEto suppress.
Value
Invisibly, a list with components by_individual
(data.frame of per-track flag rates), run_lengths (integer
vector of consecutive-flag run lengths on the focused track),
modes (numeric vector of detected substantive modes in
m/s), and notes (character vector of interpretive
messages emitted). These let downstream code consume the
diagnostic without re-running the function.
Details
Run mt_diagnose_clean_track() on the object returned by
mt_clean_track(..., remove = FALSE). The function reads the
flag columns and recomputes the small amount of additional
information needed (per-fix step speeds; nothing requires re-
running the per-fix detectors). On multi-individual input the
first five panels focus on a single individual (default: the one
with the highest flag rate); a sixth panel summarises the cohort.
The six panels
- 1. log-speed density with detected modes
KDE of \(\log(\text{step speed})\) with vertical lines for each substantive mode and the v_max cap that was used. A single dominant mode + sparse upper tail = healthy. Two or more substantive modes = bimodal behaviour (rest + flight); the per-fix detectors threshold against a single distribution and can over-flag the smaller mode. Remedy: see
vignette('state_conditional')(in preparation), or run each behavioural state separately.- 2. flag rate vs time
Rolling-window flag rate over the timeline. Roughly flat at <1\ noise events = healthy. A sustained elevated band over a contiguous window = the migration-over-flagging signature; the detectors are catching legitimate movement, not errors. Remedy: filter out that window or run it separately with stricter thresholds.
- 3. per-detector activity history
Bar chart of how many fixes each combination of detectors flagged during the iteration loop, BEFORE the conjunction rule was applied. "consensus" bins (>=2 detectors agree) are the high-confidence flags; "single-detector" bins are fixes one detector flagged that the conjunction subsequently rejected. A large bridge-only or prob-only bar means that detector is firing noisily on the data; a track with mostly consensus bars is converging cleanly.
- 4. cumulative flagging by iteration
Cumulative flag count across the per-fix iteration loop. Rapid plateau in 2-4 iterations = healthy. Linear growth without plateau = self- reinforcing flagging; the detectors are not converging on a stable flag set.
- 5. consecutive-flag run length distribution
Histogram of run lengths of consecutively flagged fixes. Most flags isolated (length 1) = discrete errors, the case the package is calibrated for. A heavy tail of long runs without
error_class = "block"= a sustained behavioural state being mistaken for outliers.- 6. per-individual flag rates (multi-track only)
Dot plot of flag rate per individual with reference lines at 0.5\ (typical clean), 2\ Use this to triage which individuals need further attention.
What the diagnostic does NOT do
It does not re-run the per-fix detectors and therefore cannot show
the underlying bridge \(\eta\) or joint-probability distributions
(a possible follow-up). It also assumes a single behavioural-state
threshold was applied; tracks where the user has already segmented
by state and run mt_clean_track per segment will read
"healthy" on every panel because each segment IS unimodal.
See also
mt_clean_track for the orchestrator that
produces the input.
Examples
if (FALSE) { # \dontrun{
library(move2)
x <- mt_read(system.file("extdata/synthetic_tracks.csv.gz",
package = "move2utils"))
x <- x[!sf::st_is_empty(x), ]
res <- mt_clean_track(x, plot = FALSE, remove = FALSE)
mt_diagnose_clean_track(res)
} # }