Skip to main content
Your data and your spec are separate. Data is a plain table you pass to GraphProvider as the data prop. The spec names that table’s columns by key through its mapping. So one spec can draw many datasets, and one dataset can be drawn many ways.

Basic structure

Data is a table with declared columns and rows:
The columns array defines the shape; rows holds the values.

Referencing columns from a spec

A spec never holds data. It names the columns it needs in its mapping. The strings you pass to mapping (or the createSpec shorthand) are column keys:
The binding is by key, so a column’s label is display text only. Legends and tooltips show it, and fall back to the key when there is none. An axis title comes from config({ axes: { y: { label: '…' } } }); without one, the axis shows the column’s label, or no title when the column has none.
Row keys must exactly match a column key. Values under keys with no matching column definition are ignored.

Value format detection

Every column gets one value format, which drives how a scale interprets it and how the renderer formats it. Inference runs per column, in two passes:
  1. The year pass. The engine looks at the first 5 non-empty rows. The first undeclared column with at least two non-empty cells there, all whole numbers from 1800 to 2199, becomes a temporal year column. This keeps 2021, 2022, 2023 off a numeric axis. If any column declares valueFormat: { type: 'year' }, the pass is skipped.
  2. The first non-empty cell. Every other undeclared column takes its format from its first non-empty cell alone, tried in this order: number → date → weekly date range → percentage → currency → text. A Date object is a date.
Every cell in the column is then parsed under that one format. A cell that does not fit becomes null, with no warning. So row order matters:
If a column looks empty on the chart, check its first non-empty cell first.

Declaring a format

The same cell can mean two things: 2010 is a headcount or a year, '1' a category or a number. When you know, set valueFormat on the column. A declared column skips inference and is parsed and formatted under that format:
Any format below is accepted. A temporal one can carry the dateFormat its cells use, such as { type: 'date', dateFormat: 'dd-MM-yyyy' }. A cell that does not fit becomes null, as under inference. Declare a numeric format for every count column whose values could pass for years. Declaring the year column as integer keeps that column numeric, but the year pass still checks its undeclared siblings: an undeclared population column holding 1950, 2000 would become dates. Declare both to keep both numeric:
Only a declaration with type: 'year' stops the year pass for the whole table; an integer declaration does not.

Numbers

Numbers and numeric strings are read as numbers. Thousands separators, decimals and magnitude suffixes are supported:

Dates

Date-like strings are parsed in many formats: ISO dates, named months and locale-specific orderings:
Short month names (Jan, Feb) work as well as full names. data._metadata.parsingLocale decides whether an ambiguous date like 01/02/2024 is read day-first (en-GB, pt-PT, ar) or month-first (en-US). The first non-empty cell fixes one date format for the whole column, so a column that mixes 2024-01-15 with 15/01/2024 loses the cells that do not match. Weekly date ranges are also detected: 1 Feb – 7 Feb or 1 Feb 2024 – 7 Feb 2024, each a 7-day span.

Dates without a year

A format with no year — month (Jan), day_month (14 Jan) or a weekly range without one — gets a synthetic year. The engine walks the column in row order, one sequence per group. The sequence starts in the current year. Each time a date falls earlier in the year than the one before it, the year advances. So Jan … Dec, Jan, Feb reads as 14 consecutive months instead of folding back on itself, and reordering the rows moves the axis.

Percentages

Values with a % suffix are percentages, stored as fractions: '64.5%' becomes 0.645. The renderer multiplies by 100 when it formats, so the axis reads as you wrote it.
A bare number in a percentage column is not scaled, so a 12 among '64.5%' values renders as 1200%. Write '12%'.

Currencies

Currency strings are parsed by their symbol. Supported symbols: $, €, £, ¥, ₹, ₱, ₩, ₪, ₫, ₽, ฿, ₦, ₺, zł, kr, Fr, R, P, R$, Rp, RM, د.إ, ﷼, Ch$, NT$, HK$, S$, A$, C$, NZ$, MX$.
Symbols can appear as prefix or suffix, and negative values are supported (-$100, $-100).

Text

Anything else is text.

How formats reach scales

The format feeds the scale you declare for each aesthetic. A bare position scale (scale.x()) picks its type from the column’s format. For x, y and ySecondary:
  • A text column → a discrete (band) scale.
  • A numeric, percentage or currency column → a continuous scale.
  • A date column → a datetime scale.
The visual aesthetics read the same formats differently. On color, a text column infers a discrete scale; a numeric or date column infers a continuous one. On size, alpha and strokeWidth, a date column infers continuous: timestamps become plain numbers, since a ramp needs no date-aware ticks. On lineType, every format infers discrete. An aesthetic bound to a constant ({ value: 5 }), left unmapped, or pointing at a column that is not in the data falls back to continuous. An explicit method — scale.x.continuous(), scale.x.discrete(), scale.x.datetime() — overrides the inference. It must still fit the column’s format: a continuous scale on a date column fails to compile with INCOMPATIBLE_TYPE. See the line chart guide for worked examples.

Empty and missing values

A cell is empty when it is null, undefined, an empty or whitespace-only string, or '-'. Empty cells become null in the parsed column. Two rules follow:
  • A row whose every cell is empty is dropped.
  • A column with no non-empty cell at all is dropped, so nothing can map to it.
Each geom handles the gaps its own way. For lines, the missingValues param breaks the path, bridges it, or treats the gap as zero.

Schema

Column[]
required
The column definitions.
string
required
A unique, stable name for the column. Row objects use it as their key, and a spec’s mapping references it.
string
Display text for legends, tooltips and, when the axis config sets no label, the axis title. Legends and tooltips fall back to the key.
ExplicitValueFormat
How to read the column’s cells when you know better than inference, for example { type: 'integer' }, { type: 'text' } or { type: 'currency', iso: 'usd' }. A declared column skips inference; see Declaring a format.
Row[]
required
The rows. Each is an object keyed by column key. A value is a string, number, Date or null.
object
Host state carried with the table. The engine reads parsingLocale; the other keys are set by the Graphy editor and are not part of the SDK.
There are two parsingLocale settings with different jobs. data._metadata.parsingLocale (default 'en-GB') decides how data cells are parsed. config({parsingLocale}) (default 'en-US') decides how values written in the spec, such as highlight predicates and annotation anchors, are read. It is also the display locale unless formattingLocale on GraphProvider overrides it. The config one does not change how a data cell is read.