Manual
Overview
Language
IntroductionScenes & structureText & inlineGraphsCode panesAnimationDataReuse & logicExpressions & parameters
Elements
Text
ParagraphHeading 1Heading 2Heading 3Heading 4Unordered ListDivider
Media
ImageTableEquation
Callouts
NoteDefinitionExampleTask
Graph
GraphLinePolygonCurveIntegralScatterHistogramPointSegmentVectorCircleSquareRectangleTriangleStarDiamondHexagonTextAxis labelAxis BraceFitResidualsContourHeatmapParameter
Code
Code canvasLines
Animation
CueDraw cueTrace cueHighlight cueSpotlight cueType cue
Structure
SceneStep
Reference
Internote Reference
Inline
Formatting
BoldItalicsInline CodeHighlightLink
Text colour
Red textOrange textYellow textGreen textTeal textBlue textPurple textPink textGrey text
Maths
Maths
Reference
Internote ReferenceValueConstant
Other
FootnoteIcon
Directives
DatasetIncludeConstantsTemplatePresetConditionalForIgnore
Keyframes
KeyframeZoom keyframe
Attribute types
?
  1. Language
  2. Data

Data

@data datasets: declaring them inline or from CSV, reaching columns, and feeding tables and marks.

#Declaring a dataset

@data declares a named dataset — tabular data with named columns, written once and reached from anywhere in the document. Inline, the body is pipe-delimited rows under a header row that names the columns:

@data#islands{
    island     | area   | species
    Baltra     | 25.09  | 58
    Bartolomé  | 1.24   | 31
    Santa Cruz | 903.82 | 444
}

Attached, a CSV supplies both — @data#survey:galapagos-plants-1973.csv — with src as the implicit attribute and column names from the file's header row. Downstream, nothing distinguishes the two forms: inline for a table small enough to read in the source, attached for real data. An id is required either way, because datasets are reached as #id.column.

Datasets are untyped: every cell is a string until an attribute's declared type parses it, exactly as any literal. A blank cell is an empty string — Chalk has no missing value.

#Reaching columns

Columns are reached by ordinary member access, fully qualified — there is no bare-column shorthand, because attributes are unquoted and label: island must stay the literal string island. Two mechanisms consume a column, and the braces are the difference:

  • {{#survey.area}} — substitution: compile-time text, the cells joined with commas, spliced before parsing. Works in prose, code bodies and attribute values alike.
  • #islands / #islands.column — binding: a reference carried through to the renderer, for attributes typed to accept one.

#Substitution vs binding

A substitution is a snapshot; a binding is live. Columns are substitutable precisely because a dataset is immutable by construction — nothing can swap it and no cell can depend on a varying value. The values that do vary at render time — derived attributes, animated attributes, reader-set parameters — refuse substitution as a compile error and must be bound: {{#fit.slope}} fails, !value:#fit.slope() is the way to say it in prose.

#Tables from data

A table binds a dataset directly and projects columns out of it:

table(data: #islands; columns: island, area, species)

columns: is a list of plain strings the table resolves against its own data: — library-interpreted names, not references, which is why they are written bare. Elsewhere, a column reaches a consumer as text through substitution — the Code panes chapter splices {{#survey.area}} straight into a numpy array literal.

#Scope and limits

  • Directives have no placement rules — a @data is document-visible wherever it is written, including inside an @included partial.
  • CSV only, for attached data. Other formats convert to CSV trivially.
  • No computed columns, no row filters, no aggregates — a transform belongs upstream, stored in the data. This is what keeps column access a pure lookup (and keeps columns substitutable).
  • For scalars and repeated fragments, use @let; for tables of values, @data is the tool.
On this page
Declaring a datasetReaching columnsSubstitution vs bindingTables from dataScope and limits
Data · Internote