Files
Stride/docs/STATS_DSL.md
T

8.4 KiB
Raw Blame History

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

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

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

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

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.

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.