194 lines
8.4 KiB
Markdown
194 lines
8.4 KiB
Markdown
# 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.
|