Files
Stride/docs/STATS_DSL.md
T

194 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Run analysis DSL
Write queries in **Stats**, use **Ctrl+Space** for completion and **Ctrl/Cmd+Enter**
to execute. **Format** produces a canonical query. Live validation uses the same
parser as execution. Comments occupy their own lines starting with `#`.
## Largest gaps between runs
```text
runs
during all time
summarize gap_since_previous_run, distance
by run
sort by gap_since_previous_run desc
take 10
compare none
```
Each gap is actual elapsed start-to-start time, expressed in days. Its predecessor
comes from your complete running history, even if it falls outside the period or
fails the query's filters. The first recorded run has a missing gap. Each result
links to the preceding run; this cannot reveal unrecorded activities.
## Statistical analysis
```text
runs
during last 24 months
where distance >= 5 km
summarize count(), median(pace), p90(heart_rate), sum(distance)
by weekday
having count() >= 5 runs
rank by median(pace) asc
limit 4
compare none
plot speed vs heart_rate
```
Functions: `sum`, `mean`, `weighted_mean`, `median`, `min`, `max`, `stddev`,
`count`, `p10`, `p25`, `p75`, `p90`, `p95`, `p99`. Use `count()` for all runs or
`count(power)` for runs with that metric. Percentiles use linear interpolation
at `(n-1)*p`; standard deviation is population standard deviation.
`mean(pace)` gives each run equal weight. `weighted_mean(pace)` weights by
recorded distance. Other weighted means use timer duration. Bare `pace` is total
timer time / distance; bare heart rate and running dynamics are weighted by timer
time. Bare distance, duration, ascent, calories and count are totals. Other bare
metrics are unweighted means. Calculated-field bare summaries are means.
Missing values are excluded, not replaced by zero. Empty sums and means remain
missing; counts are zero. Nonpositive recorded pace and sensor values are missing.
Each summary card shows usable-run coverage and its definition.
## Metrics and units
| Metric | Input unit(s) |
|---|---|
| `distance`, `distance_change`, `rolling_7d_distance`, `rolling_28d_distance` | `km`, `m` |
| `duration` | `h`, `min`, `s` |
| `pace` | `/km`, such as `5:30 /km` or `330 /km` |
| `pace_change` | `sec/km`, signed; negative is faster |
| `heart_rate`, `heart_rate_change`, `max_heart_rate` | `bpm` |
| `elevation`, `stride_length` | `m` |
| `cadence` | `spm` |
| `power` | `W` |
| `ground_contact` | `ms` |
| `vertical_oscillation` | `cm` |
| `speed` | `km/h`, `m/s` |
| `gap_since_previous_run` | `days`, `h`, `min` |
| `run_day_streak` | `days` |
| `count`, `rolling_7d_count`, `rolling_28d_count` | `runs` |
| `elevation_per_km` | `m/km` |
| `calories` | `kcal` |
| `training_effect` | `score` |
Changes compare with the immediately preceding recorded run before filtering.
Rolling 7/28-day metrics include this run and earlier runs less than 168/672 hours
old; the exact boundary is excluded. Streaks count consecutive local calendar days
with a run. Multiple runs on one day don't lengthen the streak.
Pace standard deviations and sums use numeric `sec/km`, not pace formatting.
Garmin calories and aerobic training effect remain missing when not recorded.
## Calculated fields
```text
runs
during last 12 weeks
let efficiency = speed / heart_rate
let pace_ratio = pace / pace
where efficiency > 0.07 (km/h/bpm)
summarize mean(efficiency), median(pace), count()
by week
plot efficiency vs distance
compare none
```
Define fields before referring to them. Arithmetic supports `+`, `-`, `*`, `/`,
parentheses, numeric constants, and earlier fields. Addition/subtraction requires
matching units. Pace arithmetic uses seconds/km, duration uses hours; division of
equal units gives `ratio`. Scalar multiplication keeps the field's unit. Combined
units appear in validation and completion, e.g. `(km/h/bpm)` for efficiency.
Missing inputs, zero divisors and nonfinite results yield missing values.
Expressions cannot call functions, access attributes, index values or execute code.
## Filters and periods
```text
runs
during 2026-07-01 to 2026-09-30
where distance between 8 and 20 km
and heart_rate < 150 bpm
or title contains "Race"
and has power
summarize median(pace), count()
by month
compare previous period
```
Numeric operators: `=`, `!=`, `<`, `<=`, `>`, `>=`, and inclusive `between`.
`has` / `missing` test metric availability; title search is case-insensitive and
uses a double-quoted string. AND binds more strongly than OR: the example selects
8–20 km runs below 150 bpm **or** race-titled runs with power. Parenthesized boolean
filters are not supported; use separate AND chains joined by OR.
Periods: `during last N days/weeks/months`, inclusive explicit date ranges, or
`during all time`. Rolling periods may use `ending YYYY-MM-DD`. Dates and groups
use your account timezone. Supported relative ranges are 1–732 days, 1–104 weeks,
1–24 calendar months; explicit ranges cover at most 732 days. All time covers the
complete recorded history through today and requires `compare none`.
Comparisons otherwise use an equal-length preceding period. Time series align
previous dates by elapsed calendar days; categorical groups use matching categories.
## Grouping, ranking and limits
Group with `by day/week/month/year`, `by weekday`, `by hour`, `by run`, `by all`, or
`by distance bins 5 km`. Weeks start Monday. Numeric bins are half-open ranges
`[lower, upper)` anchored at zero; negative inputs use negative bins. Missing bin
values are excluded. Time groups include empty calendar buckets, weekday/hour
include all categories; numeric bins include observed bins.
- `sort by FIELD asc/desc` orders runs; missing values sort last. `date` is allowed.
- `take N` selects the first sorted runs **before** grouping, also for comparison.
- `having SUMMARY OP VALUE UNIT` filters groups after aggregation. Multiple having
clauses combine with AND; a summary need not be displayed to filter on it.
- `rank by SUMMARY asc/desc` orders groups; the ranking summary must be selected.
- `limit N` limits groups; without ranking, time groups retain the most recent N,
categorical groups retain the first N in category order.
The order is history-derived metrics → date/per-run filters → sort/take → groups
→ having → rank/limit → displayed cohort → chart trends. Cards and contributing
runs reflect the displayed cohort. Limits are 1–1,000 runs/groups, six displayed
summaries, eight calculated fields, twenty numeric filter conditions and ten
having clauses. Wider grouping or limits are required above 1,000 displayed groups.
## Trends, relationships and export
```text
runs
during last 24 weeks
summarize distance, count(), weighted_mean(pace)
by week
trend rolling 4 buckets
compare none
```
Time groups support `trend cumulative`, `trend rolling N buckets` (1–52),
`trend change`, and `trend percent_change`. Rolling/cumulative summaries pool
contributing runs and recalculate the selected statistic; they do not average
bucket means. These windows operate on displayed buckets after having/limits.
Change compares consecutive displayed buckets; the first, missing inputs, and
percentage division by zero remain missing. Percentage change uses the absolute
previous value as denominator. Trends cannot also rank groups.
Charts support `chart auto/line/bar/none`. `plot X vs Y` adds a run-level scatter
plot and Pearson correlation using complete pairs. Constant axes or fewer than
two pairs have no correlation. Select a scatter point to open its activity.
Select a chart point, group row, or period picker to inspect contributing runs.
For cumulative/rolling chart points, drill-through shows the pooled runs; group
rows show only the original group's runs. The grouped
results table and cards always retain untransformed statistics. Evidence shows
individual input values, not an aggregate applied to one run.
**Export CSV** downloads untransformed grouped results. **Export runs** downloads
all runs in the displayed cohort, not only the evidence page. CSV contains raw
numeric precision; pace is seconds/km, duration is hours, and missing values are
blank. Run titles are escaped against spreadsheet formula interpretation. All
queries, predecessor links, scatter points and exports remain owner-scoped.
Analysis operates on persisted whole-run summaries; it does not load raw samples
or routes. Saved views are stored in this browser; bookmark URLs to share a query
with yourself across devices. Queries cannot join other users or raw sample data.