The app
Insights
Turn the feedback a program collects into charts, with a small language for picking which halts to plot.
A program collects a lot of feedback: every rep, every load, every RPE. An insight turns some of that feedback into a chart, so that progress (or the lack of it) is something you can see at a glance rather than dig for.
Insights belong to a program. You create them in the SPDK and they are drawn from whatever data is at hand:
- in the editor, from the simulator and the plan, so you can check that an insight shows what you want before anyone has run the program,
- on a run, from what the athlete actually logged, in the run’s Insights tab.
A program to plot
Throughout this page we will use this small program: four weeks of back squat and bench press, three sets each, with the load going up every week.
import "coach/common/rest.cl"
action Squat [title: "Back squat"]
action Bench [title: "Bench press"]
output:number reps []
input:number reps []
output:|kg| weight []
exec back_squat(load) {
specify:Squat reps 5, weight load
measure reps
}
exec bench(load) {
specify:Bench reps 5, weight load
measure reps
}
group main() {
let load = 60|kg|
repeat week:4 {
repeat 3 { back_squat(load) }
repeat 3 { bench(load - 20|kg|) }
rest(2|day|)
load = load + 2.5|kg|
}
}
main()
Creating an insight
Open the Insights tab in the SPDK sidebar and press +, or Click to add your first insight if there are none yet. The dialog has two parts: Feedback data, which says what to plot, and Chart, which says how.
Feedback data
Feedback data is one or more sources. Each source has:
- a Source: a selector that picks the halts to plot, e.g.
#main > exec:Squat, - a Value: an expression that turns each of those halts into a number,
e.g.
reps * weight, - an optional Name, which labels the source in the chart’s legend.
Use Add source to plot more than one thing on the same chart, say squat and bench volume side by side, and Remove to drop one.
Chart
| Field | Options |
|---|---|
| Title | What the chart is called. |
| Type | Line chart, Bar chart, Point chart, Pie chart, Donut chart. |
| Aggregate | Sum, Average, Minimum, Maximum, Count, Variance, Standard Deviation, No aggregation. |
| X-axis | Day, Week, Month or Day of week. Line, bar and point charts only. |
Aggregate decides what happens when several values land on the same spot of the x-axis: three squat sets on the same day can be added up (Sum), averaged (Average) and so on.
The X-axis is time by default. Turn on Custom expression to plot against something else instead, with a Value expression and a Name, e.g. the weight on the bar.
Press Create and the insight appears in the tab. Its menu has Edit and Delete.
Selectors
The Source of an insight is written in a small language of its own,
modelled on CSS selectors. Remember that every time an exec or a group is
called, the call goes on a stack: main calls back_squat, so while
back_squat runs, the stack is main > back_squat. A selector matches calls
by what they are and where they sit on that stack.
Picking a call
| Part | Syntax | Matches |
|---|---|---|
| Type | exec, group or * |
Calls of execs, of groups, or of either. |
| Action | :Squat, after the type |
Execs that specify the action Squat. |
| Name | #back_squat |
Calls of the exec or group named back_squat. |
| Filter | [reps > 3] |
Calls whose feedback makes the expression true. |
A selector needs at least a type or a name, and can have both:
exec:Squat every exec that specifies Squat
#back_squat every call of back_squat
exec#back_squat the same, spelled out
exec:Squat[reps > 3] Squat execs where the athlete did more than 3 reps
Combining
| Combinator | Syntax | Meaning |
|---|---|---|
| Child | a > b |
b called directly by a. |
| Descendant | a >> b |
b called anywhere inside a, however deep. |
| Union | a + b |
Either a or b. |
#main > exec:Squat Squat execs called directly by main
group#main >> exec:Squat Squat execs anywhere inside main
exec:Squat + exec:Bench both lifts in one source
* >> exec:Bench every Bench exec called from anywhere
Note that repeat, while and
if are not calls, so they don’t appear on the stack. In our
program back_squat is called inside a repeat, inside main, and still
#main > exec:Squat matches it.
Values
The Value of a source is an ordinary Coach expression, evaluated once for every halt the selector matches. Inside it you can use the names of what that exec measured and specified:
reps * weight
is the volume of a set: the reps the athlete did times the weight they were given. A few more:
weight
reps
max(weight, 0|kg|)
Value expressions can use operators, measurements and the
built-in functions, but nothing that would change the
program: no ask, no measure and no calls to execs or groups.
Putting it together
To chart the weekly squat volume of our program:
| Field | Value |
|---|---|
| Source | #main > exec:Squat |
| Value | reps * weight |
| Name | Squat |
| Title | Squat volume |
| Type | Bar chart |
| Aggregate | Sum |
| X-axis | Week |
Add a second source, #main > exec:Bench, named Bench, with the same value,
and the two lifts sit side by side.