Graphs
The canvas.graph pane: marks, curves, data, fits, surfaces, axis furniture and parameters.
#The graph pane
canvas.graph is a pane on the scene's canvas: a plotting surface whose body holds marks, whose frame (axes, grid, ticks) it draws itself, and whose domains are animatable. Its head carries the pane's id — canvas.graph#projectile{...} — and the frame is governed by attributes: x-domain / y-domain (derived from the data when omitted), x-axis-label / y-axis-label, show-grid, show-axes, show-ticks, and show-background as the master switch.
canvas.graph#fit-graph{
scatter(data: (1, 2.0), (2, 2.4), (3, 3.1), (4, 4.8); colour: grey)
fit(model: polynomial; degree: 1 to 4; default: 1; colour: teal)
}(
x-axis-label: x
y-axis-label: y
)#Marks
Everything drawn on the surface is a mark, and marks share a household of attributes: colour, label (rich text, so $maths$ sets properly), hidden (declared but not drawn — and animatable), lock (protects the mark on an editable: graph), and z (stacking order). The shapes are line, segment, vector, point, polygon, circle, square, rectangle, triangle, star, diamond, hexagon, plus freestanding text.
#Curves and expressions
A curve plots an expression in x: curve(expression: x^2; colour: blue). Expressions may reference parameters — a * sin(b * x) bends live as the reader drags a and b — and domain / range clip where it draws. A curve exposes derived max and min over its plotted domain.
#Plotting data
scatter takes a coordinate list — scatter(data: (1, 2.0), (2, 2.4), (3, 3.1)), with points as an alias — and dataset columns can be spliced into it at compile time with {{#survey.area}} substitutions. histogram takes bins and values lists and draws them vertical or horizontal. The Data chapter covers where columns come from and which consumers bind them directly.
#Fits and residuals
fit lays a least-squares fit over the graph's scatter data. The author sets the model family and the degree range — fit(model: polynomial; degree: 1 to 4; default: 1) — and the reader drives the degree with a control in the pane footer. residuals draws the vertical differences: residuals(of: fit; colour: orange).
slope, intercept and r2. The slope is the fitted polynomial's derivative at zero — exact, and live under the reader's chosen degree — so prose citing !value:#f.slope() can never disagree with the graph.#Integrals
integral shades the area under a referenced curve between two bounds — integral(of: #bell; from: -1; to: 1) — and exposes the computed area as derived value. Its bounds are parametised, so a parameter can sweep the region while the reader watches the value change.
#Surfaces
Two marks plot a function of the plane — the one place y is legal in an expression alongside x. contour draws level sets, either levels: 8 evenly-spaced or at: 1, 2, 4 exactly; heatmap paints the field itself. Both take a colour that is a single hue or a ramp — multicolour (the full spectrum) or temperature (blue through white to red) — and expose derived min and max over the visible window.
canvas.graph{
heatmap(expression: sin(x) * cos(y); colour: temperature)
contour(expression: sin(x) * cos(y); at: 0; colour: grey)
}#Axis furniture
axis.label names a value on an axis — axis.label(x: 3.1416; label: $\pi$) puts π where the number would have gone, and line: true adds a rule across the plot at that value. axis.brace names an interval: a curly brace spanning x: [m, m + s] with its label at the tip, drawn in the gutter beside the tick numbers. Which axis either speaks to is chosen by which coordinate is given.
#Parameters
A parameter declares a single-letter quantity the reader varies with a slider in the pane footer: parameter(var: a; range: [-5, 5]; default: 1). Every expression on the surface that mentions a responds as it moves. Its current value is derived — readable as #id.value.
#Derived attributes
Marks that compute something expose it as a derived attribute — read-only, recomputed at render time, reached by member access on the mark's id: #f.slope, #area.value, #field.max. In attribute position write the binding directly — text(label: #f.slope) — and in prose wrap it in !value. Derived values can never be {{substituted}}: a compile-time snapshot of a value that moves at render time would let the document disagree with itself, which is the failure this machinery exists to prevent.