Check how much segments vary from their usual length
Source:R/check_segment_length.R
check_segment_length.RdMeasures how far each segment of a structure strays from its usual length.
A keypoint can be confident and present in every frame and still be in the
wrong place — a left/right swap, a limb taken from a neighbouring
individual, a wrong match that several cameras agree on — and the segments
that should keep their length then stretch and shrink. This check reports,
per individual and segment, how much the length varies and how often it is
far from its reference, and plot.check_segment_length() draws the
distribution of each segment's length relative to that reference.
Usage
check_segment_length(data, ...)
# Default S3 method
check_segment_length(data, ...)
# S3 method for class 'anipoint'
check_segment_length(data, structure = NULL, tolerance = 0.3, n = 256, ...)Arguments
- data
A Cartesian 2D or 3D anipoint with a structure that has segments, attached with
anicore::set_structure().- ...
Additional arguments (currently unused).
- structure
Name of the structure to use (default
NULL). May be omitted when only one of the frame's structures has segments.- tolerance
A single non-negative number (default
0.3): how far, as a share of the reference length, a segment's length may differ from it before the frame counts as off.0.3allows 30% either way.- n
Density grid resolution per track (default
256).
Value
A data frame of class check_segment_length with one row per
(track, density grid point): the grouping columns (the frame's keys, with
segment in place of the structure's variable), the relative length
value (length divided by the reference), and its kernel density.
Stored as attributes:
groups: one row per track, with thereferencelength and where it came from (reference_source,"structure"or"median"), the number of frames with a measured length (n), how many of them are off (n_off) and their share (share_off), themedianlength, itsmadandcv, and the five-number summary of the relative length (relative_min,relative_q25,relative_median,relative_q75,relative_max).off: one row per run of consecutive frames off, with itsstartandstop(in the frame's index), its length in frames (n_frames), and the largest relative deviation within it (max_deviation, so0.5is 50% longer or shorter than the reference) — when the segments are off.structure,tolerance, the relative length above which values enter the density grid at that value (clamp), and the grouping columns.
Use summary() for one row per track.
Details
The segment lengths per frame are those of anicore::as_anisegment().
Each track — each combination of the frame's keys, so each individual and
segment (and session or trial, when the frame has them) — is compared with a
reference length: the structure's length for that segment when it
records one, otherwise the median of the segment's length over the track. A
structure's length applies to every individual, so leave it NA to let
each individual be measured against its own median.
For each track the check reports
the spread of the length, robustly:
mad, the median absolute deviation (scaled by 1.4826, so it estimates the standard deviation of normally distributed lengths) in the frame's units, andcv, that MAD divided by the median length — a robust coefficient of variation, which compares segments of different sizes. Both measure how much the length varies, whatever the reference.the share off: the share of frames whose length differs from the reference by more than
tolerancetimes the reference. It counts the frames with a measured length; a frame missing either end point is neither on nor off.
A segment that is consistently longer than the structure says shows up in the share off and in its median, not in its spread.
The distribution of each track's length relative to its reference is reduced
to a kernel-density grid, as check_confidence() does, so the object stays
small however long the recording. One wild frame (a knee placed on the far
side of the arena) would otherwise stretch that grid until the bulk of the
distribution falls between two grid points, so relative lengths above
max(2, 1 + 2 * tolerance) enter the grid at that value. The summary
statistics use the lengths as they are.
This is the data-generating half of the check. The plotting method
(plot.check_segment_length()) lives in anivis, mirroring the
performance / see split in easystats.
Examples
af <- anicore::example_anipoint(n_obs = 50, n_individuals = 1) |>
anicore::set_structure(anicore::example_structure())
chk <- check_segment_length(af)
chk
#>
#> ── Check: segment lengths
#> Share of frames more than 30% off the reference length, for 10 segments of
#> structure "keypoint" (robust CV in brackets):
#> • 1 | spine | 1 | 1: 62.0% [59.3%]
#> • 1 | head | 1 | 1: 60.0% [59.0%]
#> • 1 | shoulder_right | 1 | 1: 56.0% [57.9%]
#> • 1 | shoulder_left | 1 | 1: 66.0% [65.0%]
#> • 1 | hip_right | 1 | 1: 46.0% [37.0%]
#> • 1 | hip_left | 1 | 1: 54.0% [61.9%]
#> • 1 | thigh_right | 1 | 1: 62.0% [57.3%]
#> • 1 | thigh_left | 1 | 1: 56.0% [49.2%]
#> • 1 | shin_right | 1 | 1: 64.0% [65.8%]
#> • 1 | shin_left | 1 | 1: 38.0% [39.0%]
#>
summary(chk)
#> individual segment session trial reference reference_source n n_off
#> 1 1 spine 1 1 1.818649 median 50 31
#> 2 1 head 1 1 1.629934 median 50 30
#> 3 1 shoulder_right 1 1 1.453123 median 50 28
#> 4 1 shoulder_left 1 1 1.582974 median 50 33
#> 5 1 hip_right 1 1 1.565197 median 50 23
#> 6 1 hip_left 1 1 1.884591 median 50 27
#> 7 1 thigh_right 1 1 1.773552 median 50 31
#> 8 1 thigh_left 1 1 1.517423 median 50 28
#> 9 1 shin_right 1 1 1.760855 median 50 32
#> 10 1 shin_left 1 1 1.657705 median 50 19
#> share_off median mad cv
#> 1 0.62 1.818649 1.0788542 0.5932175
#> 2 0.60 1.629934 0.9622727 0.5903754
#> 3 0.56 1.453123 0.8414232 0.5790447
#> 4 0.66 1.582974 1.0287462 0.6498818
#> 5 0.46 1.565197 0.5794855 0.3702316
#> 6 0.54 1.884591 1.1666611 0.6190525
#> 7 0.62 1.773552 1.0161405 0.5729410
#> 8 0.56 1.517423 0.7459615 0.4915977
#> 9 0.64 1.760855 1.1589926 0.6581989
#> 10 0.38 1.657705 0.6461253 0.3897710
# When the segments were off
attr(chk, "off")
#> individual segment session trial start stop n_frames max_deviation
#> 1 1 spine 1 1 1 1 1 0.4629417
#> 2 1 spine 1 1 3 7 5 0.8934607
#> 3 1 spine 1 1 10 12 3 0.5874330
#> 4 1 spine 1 1 17 21 5 0.7339981
#> 5 1 spine 1 1 23 26 4 0.5015951
#> 6 1 spine 1 1 28 33 6 1.3054341
#> 7 1 spine 1 1 35 37 3 0.9072267
#> 8 1 spine 1 1 42 43 2 0.5615886
#> 9 1 spine 1 1 48 49 2 1.2197713
#> 10 1 head 1 1 1 4 4 0.8546798
#> 11 1 head 1 1 6 7 2 1.4518356
#> 12 1 head 1 1 9 11 3 1.2126735
#> 13 1 head 1 1 13 15 3 1.3677249
#> 14 1 head 1 1 19 19 1 0.6396866
#> 15 1 head 1 1 21 22 2 0.5656493
#> 16 1 head 1 1 25 25 1 0.6431874
#> 17 1 head 1 1 28 28 1 0.3408505
#> 18 1 head 1 1 30 31 2 0.7660708
#> 19 1 head 1 1 33 33 1 0.9467222
#> 20 1 head 1 1 35 36 2 0.5559340
#> 21 1 head 1 1 39 41 3 0.8187651
#> 22 1 head 1 1 43 45 3 0.4884381
#> 23 1 head 1 1 48 48 1 0.8712853
#> 24 1 head 1 1 50 50 1 0.6229127
#> 25 1 shoulder_right 1 1 1 1 1 0.5542795
#> 26 1 shoulder_right 1 1 5 7 3 1.3653128
#> 27 1 shoulder_right 1 1 9 10 2 1.1534013
#> 28 1 shoulder_right 1 1 13 13 1 0.3650842
#> 29 1 shoulder_right 1 1 16 17 2 0.5322496
#> 30 1 shoulder_right 1 1 20 20 1 0.8656660
#> 31 1 shoulder_right 1 1 22 24 3 0.5973590
#> 32 1 shoulder_right 1 1 26 27 2 1.7112476
#> 33 1 shoulder_right 1 1 29 32 4 0.7943246
#> 34 1 shoulder_right 1 1 35 35 1 0.8383701
#> 35 1 shoulder_right 1 1 37 38 2 1.1147182
#> 36 1 shoulder_right 1 1 42 43 2 0.7132963
#> 37 1 shoulder_right 1 1 46 49 4 1.0769838
#> 38 1 shoulder_left 1 1 2 3 2 0.7847619
#> 39 1 shoulder_left 1 1 5 7 3 1.4724167
#> 40 1 shoulder_left 1 1 10 10 1 1.0544725
#> 41 1 shoulder_left 1 1 12 15 4 0.8076325
#> 42 1 shoulder_left 1 1 17 18 2 0.3708121
#> 43 1 shoulder_left 1 1 20 25 6 0.8053343
#> 44 1 shoulder_left 1 1 27 28 2 0.5365686
#> 45 1 shoulder_left 1 1 30 30 1 0.8112793
#> 46 1 shoulder_left 1 1 32 35 4 1.2462201
#> 47 1 shoulder_left 1 1 38 39 2 1.0749045
#> 48 1 shoulder_left 1 1 41 46 6 1.0940274
#> 49 1 hip_right 1 1 2 2 1 0.4811279
#> 50 1 hip_right 1 1 8 10 3 1.3282354
#> 51 1 hip_right 1 1 12 14 3 0.5581687
#> 52 1 hip_right 1 1 16 16 1 0.5361030
#> 53 1 hip_right 1 1 19 20 2 0.6408247
#> 54 1 hip_right 1 1 22 22 1 0.5495231
#> 55 1 hip_right 1 1 25 26 2 0.7494433
#> 56 1 hip_right 1 1 28 30 3 0.6074807
#> 57 1 hip_right 1 1 35 35 1 0.3155229
#> 58 1 hip_right 1 1 43 47 5 0.9812120
#> 59 1 hip_right 1 1 50 50 1 0.4052419
#> 60 1 hip_left 1 1 1 2 2 0.6545971
#> 61 1 hip_left 1 1 4 4 1 0.3913786
#> 62 1 hip_left 1 1 7 8 2 0.4832870
#> 63 1 hip_left 1 1 10 13 4 1.2991697
#> 64 1 hip_left 1 1 17 17 1 0.7504274
#> 65 1 hip_left 1 1 19 19 1 0.6480032
#> 66 1 hip_left 1 1 22 26 5 0.9395280
#> 67 1 hip_left 1 1 28 28 1 0.9305781
#> 68 1 hip_left 1 1 30 30 1 0.5300252
#> 69 1 hip_left 1 1 35 36 2 0.6623524
#> 70 1 hip_left 1 1 39 39 1 0.6150782
#> 71 1 hip_left 1 1 41 42 2 0.5766802
#> 72 1 hip_left 1 1 47 50 4 0.8924887
#> 73 1 thigh_right 1 1 1 1 1 0.6314302
#> 74 1 thigh_right 1 1 3 6 4 0.9020680
#> 75 1 thigh_right 1 1 11 11 1 0.5384041
#> 76 1 thigh_right 1 1 13 13 1 0.8719663
#> 77 1 thigh_right 1 1 15 16 2 0.4467022
#> 78 1 thigh_right 1 1 18 19 2 0.5814511
#> 79 1 thigh_right 1 1 21 22 2 0.8402597
#> 80 1 thigh_right 1 1 24 29 6 0.8389120
#> 81 1 thigh_right 1 1 32 33 2 0.8593353
#> 82 1 thigh_right 1 1 36 37 2 0.4154239
#> 83 1 thigh_right 1 1 39 41 3 0.8010082
#> 84 1 thigh_right 1 1 44 47 4 1.0214399
#> 85 1 thigh_right 1 1 49 49 1 0.3340132
#> 86 1 thigh_left 1 1 1 4 4 1.4227958
#> 87 1 thigh_left 1 1 7 7 1 0.5389698
#> 88 1 thigh_left 1 1 11 11 1 0.4137906
#> 89 1 thigh_left 1 1 14 17 4 0.6681776
#> 90 1 thigh_left 1 1 20 22 3 0.7940393
#> 91 1 thigh_left 1 1 24 24 1 0.3098802
#> 92 1 thigh_left 1 1 27 30 4 0.7650286
#> 93 1 thigh_left 1 1 32 32 1 0.7271438
#> 94 1 thigh_left 1 1 36 41 6 0.6200713
#> 95 1 thigh_left 1 1 44 44 1 0.4573983
#> 96 1 thigh_left 1 1 48 49 2 0.6675451
#> 97 1 shin_right 1 1 1 2 2 0.5096149
#> 98 1 shin_right 1 1 4 5 2 0.7581320
#> 99 1 shin_right 1 1 11 15 5 0.7860806
#> 100 1 shin_right 1 1 17 18 2 0.6916901
#> 101 1 shin_right 1 1 21 23 3 0.6748321
#> 102 1 shin_right 1 1 25 25 1 0.6338547
#> 103 1 shin_right 1 1 27 27 1 0.5174738
#> 104 1 shin_right 1 1 29 36 8 1.5632789
#> 105 1 shin_right 1 1 39 43 5 0.8670075
#> 106 1 shin_right 1 1 46 48 3 1.1875998
#> 107 1 shin_left 1 1 1 3 3 0.7187820
#> 108 1 shin_left 1 1 6 6 1 0.8295895
#> 109 1 shin_left 1 1 9 10 2 0.4389259
#> 110 1 shin_left 1 1 12 14 3 0.6060504
#> 111 1 shin_left 1 1 17 17 1 0.8872260
#> 112 1 shin_left 1 1 23 24 2 1.1089717
#> 113 1 shin_left 1 1 27 28 2 1.9936946
#> 114 1 shin_left 1 1 31 31 1 0.3257938
#> 115 1 shin_left 1 1 38 38 1 0.4997744
#> 116 1 shin_left 1 1 40 40 1 0.9800427
#> 117 1 shin_left 1 1 42 42 1 1.2005405
#> 118 1 shin_left 1 1 48 48 1 0.4037116