Skip to content

Guides & reference

Charts and data-visualisation engines

Reference for Plot, Vega-Lite, Vega, Plotly, Sankey, Treemap, Choropleth, Calendar Heatmap, Word Cloud and Venn: syntax, checks, limits and fixes.
Sculptural study of connected forms and structured ideas

This page is the reference for the flowss engines that turn numbers into charts: Plot for plain XY charts and plotted formulas, the three chart grammars Vega-Lite, Vega and Plotly, and the specialist chart engines Sankey flow, Treemap (squarified), Choropleth (GIS), Calendar Heatmap, Word Cloud and Venn / Euler. For each engine you get what it draws, a working example you can paste straight into the Studio, the full syntax, the options it accepts, what flowss checks or works out for you, its limits, and the messages you may see. It also explains where each chart is drawn (inside flowss or in your browser), how big a chart can get, how charts export, and which engine to pick. Charts that belong to a business or operations workflow, such as funnels, waterfalls, Pareto charts and control charts, are documented on their own reference pages and are listed in Charts documented on other pages.

At a glance

EngineUse it forSourceDrawnWhat flowss works out or checksReference
PlotScatter, line, grouped bars, histograms, box plots and plotted formulasShort text languageInside flowssAdaptive sampling of formulas, the histogram bin rule, five-number summaries, cut bar baselines, log-axis values with no position, intervals with no stated meaning, every cap that bitplot
Vega-LiteStatistical charts, layers, facets, interactive selectionsJSONIn your browserEncodings that name a field the data does not have, channels with nothing to encode, a missing markvega-lite
VegaBespoke visualisations the higher-level grammars cannot expressJSONIn your browserVega's own validity check, scales and data sets that resolve to nothing, unknown mark types, a Vega-Lite spec pasted into Vegavega
PlotlyScientific, statistical and 3D plotsJSONIn your browserArrays of different lengths on one trace, ragged heatmap rows, labels that do not match the matrix, axes a trace names and the layout never declaresplotly
Sankey flowEnergy balances, budgets, traffic and conversion flowsShort text languageInside flowssWhether every node conserves flow, total in against total out, loops, zero flowssankey
Treemap (squarified)Hierarchical proportionsShort text languageInside flowssParent sizes against their children, sizeless and negative leaves, percentage breakdowns that do not sum to 100treemap
Choropleth (GIS)Values by country or US state on a hex-tile mapShort text languageInside flowssCodes the map has no tile for, a colour ramp with no rangechoropleth
Calendar HeatmapDaily values across one yearShort text languageInside flowssDates outside the drawn year, impossible dates, dates written twicecalendarheatmap
Word CloudTerms sized by weightShort text languageInside flowssA year taken as a weight, zero weights, repeated terms, missing weightswordcloud
Venn / EulerOne, two or three overlapping setsShort text languageInside flowssLabels for sets that were never declared or are not drawn, unused setsvenn

Every engine on this page is available on every plan, including Free, and the engines themselves are not metered. (Free does limit how many figures you keep, to three per studio.) Only the optional AI features, such as flowss Studio Agent: pick the best chart in Data → Chart, Explain & fix, Fix with the flowss Studio Agent and automatic repair, need AI: there is no AI on Free, your own AI key works from Starter, and hosted AI points start on Plus. See Plans and what they include.


Working with chart engines

Opening an engine

  1. In the Studio, click Engines & templates at the top of the tool rail (its tooltip also names the current engine), or the engine name at the top of the code sheet. The library opens with two tabs, Engines and Templates. (Pressing / opens the same library on the Templates tab with the template search focused.)
  2. On the Engines tab, search by name or by what you are making, for example "scatter", "histogram", "sankey", "treemap", "map", "heatmap" or "word cloud", or by the tool you are replacing, such as "Excel charts", "GraphPad Prism", "Tableau" or "Datawrapper".
  3. Click the engine. Its starter (its first template) replaces the current figure's source. The switch is one undo step, so ⌘Z (Ctrl+Z on Windows and Linux) brings your source back. Start a New figure (⌥⌘N) first if you want to keep both.

You can also click Open in Studio on any engine's reference page, which opens /studio?engine= followed by the engine id, or filter the template gallery by engine, for example /templates?engine=plot. Every reference page shows the engine's template count, its source language, the studio it opens in and its engine id, a Syntax at a glance sample where one exists, and up to six sample templates with a link to all of them.

Three ways to get a chart from data

RouteBest whenWhat you get
Data → Chart in the Studio (⌘D, or drop a .csv, .tsv or JSON-records file on the canvas)You have a table and want a correct chart quicklyRecommended figures built without AI and checked against your rows, in Vega-Lite, Plotly, Sankey flow, Treemap, Choropleth, Calendar Heatmap, Word Cloud and other engines; or a chart builder that writes Vega-Lite for the type you pick
Writing the source yourself, in the engines on this pageYou want full control, a formula, a reproducible figure in version control, or a figure the server can drawExactly the chart you describe
The Figure studioYou need journal-ready, multi-panel figures with statisticsA dataset-to-figure workflow; see Figure analysis and statistics

Data → Chart is documented in full, including its recommendation rules, chart builder and limits, in Data, timeline, TikZ and the diagram tools.

Where each chart is drawn

GroupEngines on this pageWhat it means for you
Inside flowssPlot, Sankey flow, Treemap, Choropleth, Calendar Heatmap, Word Cloud, Venn / EulerWorks offline. The source never leaves flowss. The render API can draw it on a server, so thumbnails, previews, embeds and automated reports all work
In your browserVega-Lite, Vega, PlotlyWorks offline in the browser once the Studio has loaded. The headless render API cannot draw these and refuses them with the code needs-browser; use the Studio or an embed instead

None of the engines on this page uses an outside render service, so none of them is subject to the daily outside-service render allowance.

Tip: If a chart has to be drawn on a server, for example in a CI pipeline or for an automatically generated report, write it in Plot (for XY charts) or one of the native chart engines rather than in Vega-Lite or Plotly.

Size budgets

Before it draws, the Studio checks the size of the source against a budget for the engine, so a pasted giant cannot freeze the page. A source over budget is not drawn.

EnginesBudget (bytes of source)
Plot300,000
Vega-Lite, Vega, Plotly80,000
Choropleth, Calendar Heatmap, Word Cloud150,000 (they grow one row per observation)
Sankey flow, Treemap, Venn / Euler60,000

Bytes are counted in UTF-8, so accented letters and symbols such as ± and ° count as two or more. The message reads "Source is … — past the … safe-rendering budget for … Rendering this in the browser would freeze the page." followed by three options: split the figure into smaller figures, render it on the server with the render API, or trim the source. The server option applies only to engines drawn inside flowss. Most native engines also have their own, smaller caps on what they draw (listed with each engine below); those are reached first, and the figure says which cap was hit.

Checks and readiness

Every engine on this page has a checker. Its findings appear in up to three places:

  • Inside the figure. Plot prints a notes strip under the chart, Sankey flow and Treemap print a headline and their most important findings under the drawing, and Venn / Euler prints notices for anything it could not draw. Exports carry these lines.
  • The readiness chip in the Studio's status panel. A chart whose checks fail cannot read as Sound. Open the chip's detail to see what is Blocking or Holding it at a level, and use Fix beside a finding to hand just that one to the flowss Studio Agent (AI needs to be on your plan).
  • Diagram Intelligence (⇧⌘X) adds metrics and insights for Sankey flow: nodes, flows, sources, sinks, throughput, whether flow is conserved, leaking or gaining nodes, cycles and the largest flow. See Flow-systems analysis in Studio.

A checker that could not read part of a document never presents its result as complete. It names the line it could not read, and verdicts such as "clean" are withheld until the whole document has been read.

When a chart fails to draw at all, a Render error box appears over the canvas with the message. If the message names a line, Go to line followed by the number puts your cursor on it. Explain & fix sends the error and the source to AI and applies the fix, which you can undo.

Exporting charts

Charts export like any other figure from the Studio's File menu (the ⋮ button), under Export:

ItemShortcutWhat you get
Export PNG⇧⌘PA raster image at the chosen image scale
Export SVG⇧⌘SA vector file
Export PDFA PDF of the figure
Copy diagram as PNG⌥⌘PThe PNG on your clipboard
Copy diagram as SVGThe SVG on your clipboard
Copy source and Download sourceThe chart's source text
Export every figure as one PDFEvery figure in the workspace in one PDF
Image scale1×, 2× or 3× (3× until you change it)
Transparent backgroundA tick-box. Without it, exports get the page colour of the current theme. A PDF always has an opaque page
Export as TikZ / LaTeX⌘LSee below

A few chart-specific details:

  • Plotly PNG and PDF exports use Plotly's own image exporter, at least 800 × 480 pixels before scaling, so text and lines stay crisp.
  • Vega-Lite and Vega are drawn as SVG, so every export path works and the SVG stays editable in a vector editor.
  • The native engines produce SVG directly, which is why they also work in the render API, embeds and thumbnails.

To put a chart in a LaTeX paper, Export as TikZ / LaTeX (⌘L) converts any figure into a standalone LaTeX document with AI. It needs AI on your plan, and sources over 30 KB cannot be converted; see Data, timeline, TikZ and the diagram tools. Every export format is covered in Exporting your work.


Plot

Plot draws plain XY charts and plotted functions: scatter plots, line charts, grouped bars, histograms with a named bin rule, Tukey box plots, and formulas sampled adaptively so a fast-changing curve is not quietly drawn as a different, smoother one. It is drawn inside flowss, so it works offline, on the server and in embeds. It is the right engine for "here are some x values and some y values, draw them", and for any figure where you want to plot a formula rather than type in points.

title: Cooling curve
subtitle: Cabinet A, 24-hour soak test
x: Time (h)
y: Core temperature (°C)
grid: both
legend: right

scatter "Measured" colour: blue error: sd
  0, 21.4 ± 0.3
  4, 16.2 ± 0.4
  8, 12.9 ± 0.6
  12, 10.8 ± 0.5
  24, 8.4 ± 0.4

plot "Model" y = 8.2 + 13.2*exp(-x/7.4) for x in [0, 24] dashed: yes

note: The dashed curve is drawn from the design constants, not fitted to these points.

How a Plot document is written

A Plot document is line-based. Directives are written key: value. A series starts with a header line naming its kind, followed by its data rows; indenting the rows is conventional but not required. Blank lines are ignored. # and // start a comment anywhere outside quotes, with one exception so that hex colours can be written: a # that comes straight after a key: and is followed only by hex digits is a colour, as in colour: #0f172a, not a comment.

Directives

DirectiveWhat it setsExample
title:The chart title. Wraps over up to 3 lines; up to 300 characters are kepttitle: Revenue by region
subtitle:A subtitle under the title. Wraps over up to 6 lines; up to 300 characterssubtitle: Reported, unaudited
caption:A caption printed with the notes under the chart (up to 600 characters)caption: Source: annual report
note:A caveat printed in the notes strip. Repeat for several notes (up to 600 characters each)note: Site 4 was offline in March.
x: and y:Axis titles. A unit in a trailing bracket after a space is set as the unitx: Time (h)
x unit: and y unit:The axis unit on its owny unit: °C
x scale: and y scale:linear (also lin), log (also log10, logarithmic), log2, symlog or sqrt (also root)x scale: log
x limits: and y limits: (also x range:, y range:)The axis range, written 0 .. 24, 0, 24, 0 to 24 or auto. Either end can be autoy limits: 0 .. 110
grid:none (also off, no), x, y or both. The default is y; any other word gives bothgrid: y
legend:auto (the default), right, bottom or none (also off, no)legend: bottom
width:Figure width in pixels, between 240 and 4,000 (the default is 760)width: 900
height:Height of the plotting area in pixels, from 160 up to 900. Without it, the plotting area is 60% as tall as it is wide (55% on bar and box figures)height: 400
palette:A categorical palette (see Colours, below). The default is okabe-itopalette: tol-bright

The unit in an axis title is only read as a unit when there is a space before the bracket. Time (h) has the unit "h"; sigma(tau) is a function of tau and keeps its bracket as part of the title.

Series kinds

Kind (and aliases)Data it takesHow it is drawn
scatter (points, point)x, y pairsMarks at each point
line (curve, lines)x, y pairsPoints joined by a line
bar (bars, column, columns)label value pairsBars on a categorical x axis, grouped when several bar series share labels
histogram (hist)Raw valuesValues binned and counted
box (boxplot)Raw valuesOne Tukey box per series
plot (function, f)A formulaThe formula sampled across an interval

The first series with data decides what kind of figure it is, because a figure cannot have a numeric and a categorical x axis at once:

First seriesThe figure hasSeries it also accepts
scatter, line, plot or histogramA numeric x axisscatter, line, plot, histogram
barA categorical x axisbar only
boxOne box per seriesbox only

A series that does not fit is not drawn and is named in the notes strip, for example "«Model» is a function series, and this figure has a categorical x axis (because the first series is a bar series). It was not drawn …". Move it to a figure of its own.

Writing data rows

Fields in a row can be separated by commas, semicolons, tabs or runs of spaces, which is what spreadsheets, CSV files and papers produce.

RowMeaning
4, 16.2 or 4 16.2A point at x = 4, y = 16.2
4, 16.2 ± 0.4A point with a symmetric interval of 0.4
4, 16.2, 0.4The same, written as a third value
4, 16.2, 15.6, 16.9A point with explicit lower and upper ends
North West 12.4In a bar series: a bar labelled "North West" of height 12.4 (the value is read from the end, so labels can contain spaces)
North, 12.4 ± 1.1In a bar series: a bar with a symmetric interval
4.1 4.4 4.9 5.0In a histogram or box series: four raw values. One per line or several per line both work, and a values: prefix is allowed

Any series can carry its data inline after a colon on the header line. Items are separated by commas, so inside one item use spaces:

bar "Revenue": North 12.4, South 9.1, East 7.8
scatter "A": 0 1.2, 1 1.9, 2 3.1
box "Before": 120 135 128 142 160 151 133

Series options

Options go on the series header, after the name and before any inline data, written key: value.

OptionApplies toValues
colour: (or color:)Any seriesA named colour (blue, red, green, amber, orange, yellow, purple, violet, indigo, teal, cyan, pink, magenta, lime, brown, grey, gray, slate, black) or a hex colour such as #0f172a. Anything else is ignored with a note and the palette colour is used
error: (or errors:)Series with intervalsWhat the intervals mean: sd (also stdev), sem (also se), ci (also ci95), iqr or range
curve:linelinear (also straight), monotone (also smooth), step (also stepafter), stepbefore or stepmiddle
shape:scattercircle, square, triangle, diamond, cross, plus or star
markers:lineyes or no
dashed: (or dash:)Any line or functionyes or no
bins:histogramA whole number of bins, up to 200
samples:plotThe size of the starting sample grid, up to 4,000

The option list stops at the first key: Plot does not recognise, so a misspelt option shows up as unreadable data rather than being silently ignored.

curve: monotone never overshoots, so the smoothed line cannot invent a peak the data does not contain.

Plotting a formula

plot y = sin(x) for x in [0, 2pi]
plot "Envelope" y = exp(-x/8) for x in [0, 30] samples: 400 dashed: yes
f 1/x for x in [-4, 4]
plot "Decay" y = 100*exp(-t/12) for t in [0, 60] colour: teal

The line starts with plot, function or f, then an optional quoted name, then the formula (the y = is optional), then for, the variable and the interval in square or round brackets, separated by a comma or semicolon. The variable can have any name, and the formula may use only that name. Names are not case-sensitive. The interval ends can themselves be expressions, such as 2pi, but may not mention the variable. On a function line the options come after the interval, and only three apply: samples:, colour: (or color:) and dashed: (or dash:). A function line takes no data rows; a row written under it is skipped with a note.

Formula elementWhat is available
Operators+, -, *, /, %, and ^ or ** for powers (right-associative, so 2^-x works)
Implicit multiplication2pi, 3x, 2(x+1) and (x+1)(x-1) are products
Constantspi, tau, e, phi, inf
Trigonometricsin, cos, tan, asin, acos, atan, atan2(y, x), sinh, cosh, tanh
Exponential and logarithmicexp, ln (natural log), log (base 10, or log(x, b) for base b), log10, log2
Powers and rootssqrt, cbrt, pow(a, b), hypot(…) (up to 8 arguments)
Rounding and signabs, sign, floor, ceil, round, trunc, mod(a, b)
Comparisonmin(…), max(…) (up to 8 arguments), clamp(x, lo, hi)
Piecewise helpersstep(x) (0 below zero, 1 from zero), ramp(x) (0 below zero, x from zero)
Special functionserf, erfc, gamma, lgamma
Note: log is base 10, as on a calculator. Use ln for the natural logarithm.

Plot samples the formula on an even grid (129 points unless you set samples:), then repeatedly splits any stretch that is still bending, so a narrow peak or a fast oscillation is resolved rather than smoothed away. It breaks the line wherever the function has no finite value and across asymptotes, so 1/x is not joined straight across zero. If refinement runs into the 4,000-sample limit, the notes strip says which curve stopped being refined and that "The curve you see is smoother than the function is."

Histograms and box plots

  • Histograms choose their bin count by the Freedman–Diaconis rule. When the interquartile range is zero, Sturges' rule is used instead. The rule that ran is named in the notes strip, for example "«Batch 7»: 5 bins, chosen by Freedman–Diaconis." Set bins: to choose the count yourself. The last bin includes its upper edge, so every value is counted.
  • Box plots are Tukey boxes: median, quartiles, whiskers and outliers. With fewer than about five values, a note suggests that a strip of points would be more honest. Two box series with the same name cannot both be drawn; the second is named and skipped.

Colours and palettes

Series take colours from the figure's palette in order, unless a series sets its own colour:. The categorical palettes you can name with palette: are okabe-ito (the default), tol-bright, tol-muted, tol-light, tol-vibrant, tol-high-contrast, tol-medium-contrast and greyscale-safe. Named colours have light and dark variants and follow the Studio theme.

What the figure tells you

Under the title, a summary line gives the series and points drawn, for example "1 series · 5 points". If any cap bit, the count is printed with ≥ and the word "capped". The notes strip under the chart lists, in order of importance, everything the chart could not draw or wants you to know, together with your own notes and caption. Plot raises these by itself:

  • A cut bar baseline: "The bar baseline is …, not zero. A bar encodes quantity by its length, so a cut baseline makes small differences look large …". A histogram gets the equivalent warning: "The y axis does not reach zero on a figure whose bars encode quantity by length, which exaggerates every difference in it."
  • Values a logarithmic axis cannot place: "The x axis is logarithmic and 2 values are zero or negative. A log axis has no position for them, so they are not on this figure at all …" (a similar note covers the y axis).
  • An interval meaning Plot does not know: "… is not an interval this engine can name. The bars are drawn, but the figure cannot say what they mean — use sd, sem, ci, iqr or range."
  • A colour Plot will not use: "… is not a colour this engine will use, so the palette chose instead."
  • Intervals with no stated meaning: "«Observed» carries intervals with no stated meaning … add «error: sd» or «error: ci»."
  • Rows that could not be read: "«scatter 1»: 1 row could not be read as data and was skipped."
  • Lines outside any series: "«…» is not a directive and there is no series open for it to belong to, so it was skipped."
  • Clipped titles and notes: the clipped part is printed in the strip so nothing you wrote is lost.

What Plot deliberately does not do: pie charts, dual y axes, stacked areas, 3D, interactivity, CSV loading, date parsing and regression fitting. Use the chart grammars below, or the Figure studio, for those.

Plot limits

LimitValue
Series per figure8 (a ninth is named in the notes strip and not drawn)
Points per series2,000
Points in the whole figure8,000
Bar categories40
Raw values per histogram or box series5,000
Function samples4,000 per curve
Histogram bins200
Formula length and nesting400 tokens, 32 levels of brackets
Source400,000 characters or 20,000 lines (the Studio's 300,000-byte budget applies first)
Labels and series names80 characters
Notes kept64 (14 are shown; the strip says how many more it could not fit)

Vega-Lite

Vega-Lite is a grammar of interactive graphics written as a JSON specification: you describe the data, a mark and how fields map to channels, and Vega-Lite works out the scales, axes and legends. It covers scatter, line, bar, area, heatmap, box plot, violin and density charts, layered and faceted charts, geographic maps and interactive selections. flowss uses Vega-Lite 6.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "title": "Monthly sign-ups",
  "data": {"values": [
    {"month": "Jan", "signups": 120},
    {"month": "Feb", "signups": 148},
    {"month": "Mar", "signups": 171}
  ]},
  "mark": "bar",
  "encoding": {
    "x": {"field": "month", "type": "ordinal", "sort": null},
    "y": {"field": "signups", "type": "quantitative"}
  }
}

How flowss draws Vega-Lite

  • The chart is drawn in your browser as SVG.
  • Any background colour in the specification is replaced with a transparent one, so the chart sits on the canvas. When you export, the background comes from the export settings (the theme's page colour, or none with Transparent background), not from the specification.
  • The Studio's dark theme is applied to the chart when you are in dark mode.
  • The Vega action menu (View Source, Open in Vega Editor and the export links) is not shown. Export from the Studio's export menu instead. Embedding options written inside the specification under usermeta.embedOptions are ignored, so a shared specification cannot turn that menu back on.
  • The specification must be a JSON object. A specification that is only a string is refused with "A Vega or Vega-Lite spec must be a JSON object, not a string: a string spec is fetched as a URL."

Data

Put data inline with "data": {"values": [...]}. A "data": {"url": "..."} can load from flowss itself, from the Vega example datasets at https://cdn.jsdelivr.net/npm/vega-datasets@2/, and from raw GitHub files on raw.githubusercontent.com and gist.githubusercontent.com. Most other hosts are blocked by the page's security policy, so paste the values inline instead, or aggregate them first.

What flowss checks

flowss reads every encoding and follows the specification's transforms (filter, calculate, aggregate, bin, window, join-aggregate, density, quantile, regression, loess and others) to work out which fields exist at each point. It then reports:

FindingLevelWhy it matters
An encoding names a field the data does not haveErrorVega-Lite does not fail: every mark gets the same position, or the same colour with a legend reading "undefined", and the chart still looks like a result
A channel declares a type but no field, aggregate, value or datumWarningThe channel encodes nothing
No mark anywhere (while encodings exist)WarningNothing is drawn
No encoding at allGapThere is nothing plotted to check
A transform whose output fields cannot be known from the specification alone, such as pivotGapReported as unchecked, not guessed
Data loaded from a url, a named data source supplied at run time, or no data at allGapThe fields are not in the document, so the encodings there are reported as unchecked rather than clean
A document that is not valid JSONGapNothing in it is checked

Fields inferred without a type are not reported, because Vega-Lite infers them reliably. The count aggregate needs no field, and a nested field such as a.b is checked by its first part.

Templates and Data → Chart

The chart builder in Data → Chart writes Vega-Lite for Scatter, Line, Bar, Histogram, Box plot, Violin, Heatmap, Pie, Area and Density, with your rows embedded. Several recommended figures (lines over time, histograms, sorted bars, bars with error bars, part-of-whole arcs, heatmaps, box plots and scatters) are Vega-Lite too. The template gallery has well over a hundred Vega-Lite templates to start from.


Vega

Vega is the lower-level grammar under Vega-Lite. A Vega specification declares every data set, scale, axis, legend, signal and mark by name, which makes it the engine for bespoke visualisations: chord-style and radial layouts, sunbursts, force-directed networks, parallel coordinates and custom interactions. flowss uses Vega 6.

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "width": 300, "height": 160,
  "data": [{"name": "table", "values": [
    {"c": "A", "v": 28}, {"c": "B", "v": 55}, {"c": "C", "v": 43}
  ]}],
  "scales": [
    {"name": "x", "type": "band", "domain": {"data": "table", "field": "c"}, "range": "width", "padding": 0.1},
    {"name": "y", "type": "linear", "domain": {"data": "table", "field": "v"}, "range": "height", "nice": true}
  ],
  "axes": [{"orient": "bottom", "scale": "x"}, {"orient": "left", "scale": "y"}],
  "marks": [{"type": "rect", "from": {"data": "table"},
    "encode": {"enter": {
      "x": {"scale": "x", "field": "c"}, "width": {"scale": "x", "band": 1},
      "y": {"scale": "y", "field": "v"}, "y2": {"scale": "y", "value": 0},
      "fill": {"value": "#4c78a8"}}}}]
}

Vega is drawn exactly as Vega-Lite is: in your browser, as SVG, with a transparent background, the dark theme in dark mode, no action menu, and the same rules for data URLs.

What flowss checks

flowss first asks Vega's own parser whether it accepts the specification, and shows Vega's message when it does not (for example an undefined data set, an unknown scale on an axis, an unknown signal or a duplicate name). It then looks for the mistakes Vega accepts in silence:

FindingLevelWhy it matters
Vega rejects the specificationErrorNothing valid can be drawn
A scale referenced inside an encode block resolves to nothing in scopeErrorThe channel is undefined: marks fall back to the default colour while the legend still shows your palette
An unknown mark typeErrorThe mark is not drawn
No marks, or a data set with no rowsWarningAn empty but well-proportioned chart
The $schema names Vega-LiteWarningA Vega-Lite specification read as Vega has no marks. Move it to the Vega-Lite engine
A reference built at run time from a signalGapCannot be checked from the specification
A scale or data set that nothing usesNoteUsually left over from an edit

Names are checked in the scope where they are written: a group mark's own data, scales and signals are visible to its children but not to its siblings.


Plotly

Plotly draws publication-quality scientific and statistical plots from a JSON figure: scatter and line, bar, box, violin, histogram, heatmap, contour, 3D surface and scatter, polar, ternary, waterfall, funnel, parallel coordinates, Sankey, tables, indicators and more. flowss uses Plotly 2.35. It is the engine most templates use for specialist scientific figures such as ROC curves, Kaplan–Meier curves, dose–response curves and forest plots.

{
  "data": [
    {"type": "scatter", "mode": "lines+markers", "name": "Treatment",
     "x": [0, 7, 14, 21, 28], "y": [100, 92, 81, 77, 70]},
    {"type": "scatter", "mode": "lines+markers", "name": "Control",
     "x": [0, 7, 14, 21, 28], "y": [100, 97, 95, 94, 92]}
  ],
  "layout": {"title": "Tumour volume (% of baseline)",
             "xaxis": {"title": "Day"}, "yaxis": {"title": "% of baseline"}}
}

What a Plotly document can look like

ShapeExample
A full figure{"data": [...], "layout": {...}, "config": {...}} (layout and config are optional)
A bare array of traces[{"type": "bar", "x": [...], "y": [...]}]
A single trace{"type": "scatter", "x": [...], "y": [...]}

A document with no traces anywhere is refused with: "This Plotly document has no traces to draw. A figure reads {"data": [{"type": "scatter", "x": [...], "y": [...]}], "layout": {...}} — a bare array of traces, or a single trace, also works."

How flowss draws Plotly

  • The chart is drawn in your browser, 900 pixels wide (or 95% of the canvas, if that is narrower) and 520 pixels tall, and resizes with the canvas.
  • The paper and plot backgrounds are made transparent, and the font is set to the Studio's typeface and theme colour. Any layout.font you write (family, size or colour) is replaced by these settings. Margins default to 50, 30, 50 and 50 pixels (left, right, top, bottom); any margin your layout sets wins.
  • Your config is applied (zoom, mode-bar buttons, locale), except that the Plotly logo and every link that would send the chart's data to Chart Studio are switched off.
  • Plotly's own mode bar, with zoom, pan and its own image download, appears when you hover over the chart. For figures to share, use the Studio's export menu, which uses Plotly's exporter for PNG and PDF.

What flowss checks

FindingLevelWhy it matters
A trace's coordinate arrays have different lengths, for example 12 x values and 11 y valuesErrorPlotly draws 11 points and says nothing; the twelfth reading is simply missing
The rows of a heatmap, surface or contour z matrix differ in widthErrorA short row is padded with blanks drawn like measured zeros
A matrix trace's x or y labels do not match the matrix's columns or rowsErrorEvery label is off by the difference
A per-point array (text, hovertext, customdata, ids, or a marker's color, size, symbol, opacity) has the wrong lengthWarningPoints get fallback values, or values belong to no point
A trace is drawn against an axis such as x2 or y3 that the layout never declaresWarningPlotly invents an axis with default settings
A trace carries no data at allWarningIt still takes a legend entry

Trace types that keep their data elsewhere (parallel coordinates and categories, scatter-plot matrices, Sankey, tables and indicators) are recognised and not reported as empty.


Sankey flow

Sankey flow draws multi-stage flow diagrams for budgets, energy balances, material flows, conversion funnels and traffic. Each ribbon's thickness equals its value, nodes are placed in columns by their depth in the flow, and each node shows its total throughput. Unlike a drawing tool, it adds the flows up: it tells you when a node does not pass on what it receives, and when the diagram as a whole loses or gains a quantity.

title "Household energy (kWh)"
node Grid
node Solar
node Home label "Home supply"
node Heating
node Appliances
node Export
flow Grid Home 6200
flow Solar Home 2100
flow Solar Export 900
flow Home Heating 4300
flow Home Appliances 4000

Syntax

StatementMeaning
title "…"The figure title
node IDDeclare a node. Optional: label "…" gives it a display name
flow FROM TO VALUEA flow of VALUE from one node to another. Ids with spaces are quoted: flow "Natural gas" Electricity 40
  • A node named only in a flow is created automatically (and noted).
  • Two flow lines for the same pair add together, which is what two ribbons between one pair mean.
  • Values may be decimals, and thousand separators are allowed (1,200). A negative value is refused, because a negative flow is a flow the other way: write it in the other direction.
  • A unit after the number, such as 40.5 PJ, is not read; the value is used and a note says the unit was ignored, because a Sankey has one unit throughout.
  • # and // start a comment outside quotes.

What flowss works out

A node with no inbound flow is a source and a node with no outbound flow is a sink; neither is an imbalance. Every node between them must pass on what it receives, to within 0.5% of what flows through it.

FindingLevelMeaning
A node does not balanceErrorFor example "Home supply does not balance: 8300 in, 8000 out, so 300 does not leave …" (the node is named by its label, and the percentage of its throughput is given). If the difference is a real loss, give it a ribbon to a node that names it
Total in does not equal total outErrorThe diagram as a whole loses or gains a quantity, even if each node looks fine
A loopErrorA Sankey traces a quantity from where it enters to where it leaves; break the loop or draw the recirculated quantity as its own node
A flow from a node to itselfErrorIt is in neither side of any balance
A node with no flow at either endWarningDrawn as a bar of no height
A flow of zeroWarningA ribbon of no width looks exactly like a route that does not exist
A node declared twiceWarningThe first declaration wins
A node named only in a flowNoteIt is drawn under its bare id with no label, which is also what a mistyped node name leaves behind
The same pair given two flow linesNoteThe values are added
An unreadable line, a refused negative value, an ignored unit, or a cap that bitGapNamed with its line number

When everything balances, the headline reads, for example, "Conserved — 9200 in, 9200 out, across 6 nodes and 5 flows. The widths add up." The headline and up to four findings are printed under the diagram, with a count of any further findings.

Limits: 400 nodes, 2,000 flows and 6,000 lines. Anything past a cap is reported, never dropped in silence.

Tip: Mermaid also draws Sankey diagrams with its sankey-beta type (see Software and architecture engines). Use the Sankey flow engine when the numbers must balance, or when the figure has to be drawn on a server.

Treemap (squarified)

Treemap fills a rectangle with nested rectangles whose areas are proportional to their sizes, using the squarified layout so every rectangle stays close to square. Use it for disk usage, budgets, portfolios, market share and any part-of-whole hierarchy.

title "Disk usage (GB)"
node photos size 77
node videos size 200
node code size 42
node photos.2024 parent photos size 45
node photos.2023 parent photos size 32
node videos.movies parent videos size 80
node videos.shows parent videos size 120

Syntax

StatementMeaning
title "…"The figure title
node ID [parent PARENT] [size N]A node. Leaves carry a size; a parent is sized as the sum of its children
  • Ids cannot contain spaces. Use dots, dashes or underscores. The label drawn in each rectangle is the last part of the id after a dot, so photos.2024 is labelled "2024".
  • Write parent before size when a node has both. Sizes may be decimals.
  • Each rectangle shows its label when it is wide and tall enough, and its size when it is taller still.
  • Colours are chosen per node from its id and get slightly deeper with each level of nesting.
  • Comments start with # or // at the start of a line.

What flowss checks

FindingLevelMeaning
A negative sizeErrorThere is no negative area; every other rectangle is drawn too large
A node that is its own ancestorErrorIt is drawn nowhere
A parent's stated size differs from the sum of its childrenWarningThe larger of the two is used, so either your stated size is discarded or part of the parent is empty
A leaf with no size, or zeroWarningA rectangle of no area is not drawn
A parent naming a node nobody declaredWarningThe node is drawn as a share of the whole instead
An id declared twiceWarningThe checker reports that the last declaration wins. In practice the node is drawn once for each declaration, each time at the last declaration's size, so remove the extra line rather than relying on either
The title claims percentages and the top level does not sum to 100ErrorTriggered only when the title contains % or the word "percent" or "percentage"; a tolerance of half a point allows for rounding
A line that is not a node or title statementGapNamed with its line number

When there is at least one error or warning, a headline and up to three of them are printed under the treemap. A document with no nodes shows "Add nodes — node photos size 7700". Up to 2,000 nodes are read.


Choropleth (GIS)

Choropleth shades a built-in hex-tile map by value: one hexagon per country or US state, placed roughly where it sits on the map. Nothing is downloaded, so it works offline and prints cleanly. Use it for teaching maps and dashboard-style comparisons across countries or states.

title "GDP per capita, 2023 (US$)"
atlas world
scale "#fef3c7" "#dc2626"
legend "GDP per capita (US$)"
USA 76399
GBR 52432
DEU 53562
FRA 46315
JPN 33950
CHN 13136
BRA 10412
IND 2485
NGA 2184

Syntax

StatementMeaning
title "…"The figure title
atlas world or atlas usWhich map. world is the default
scale "#LOW" "#HIGH"The colour ramp from the lowest to the highest value, as six-digit hex colours in double quotes (three-digit hex and colour names do not work). The default runs from pale yellow (#fef3c7) to red (#dc2626)
legend "…"A caption over the colour legend
CODE VALUEA value for one tile, as an upper-case code followed by a number, for example USA 76399. Negative numbers and decimals are allowed

Values are mapped linearly between the lowest and the highest value. Every tile is printed with its code, and tiles with no value are drawn in a pale neutral colour. Once at least one value is read, a legend shows the ramp with the minimum and maximum values, under your legend caption. Hovering over a tile shows its full name and value. Comments start with # or // at the start of a line.

The atlases

AtlasCodesTiles
worldThree-letter ISO 3166 country codes45 countries: USA, CAN, MEX, BRA, ARG, COL, PER, CHL, GBR, FRA, DEU, ESP, ITA, POL, NLD, BEL, SWE, NOR, FIN, RUS, UKR, TUR, GRC, MAR, DZA, EGY, NGA, ETH, KEN, ZAF, GHA, CHN, JPN, KOR, IND, PAK, IRN, SAU, ARE, IDN, VNM, THA, PHL, AUS, NZL
usTwo-letter USPS state codesThe 50 states (no District of Columbia)
Warning: The world atlas is a teaching-sized selection of 45 countries, not a complete map, and tiles are approximate positions rather than real borders. A code with no tile, such as UK or CHE, shades nothing.

What flowss checks

FindingLevelMeaning
A code that is not a tile on the atlasErrorThe value shades nothing, yet still sets the range of the colour ramp. When the code is one letter away from a real one, the finding suggests it ("Did you mean …?")
A line that is neither a directive nor a valueErrorNothing is shaded for it
Every value is the sameWarningEvery shaded tile comes out the same colour
Only one or two tiles carry a valueWarningAlmost the whole map is in the no-data colour
No value at allGapEvery tile is drawn as no data
Warning: Numbers must not contain thousand separators: write 76399, not 76,399. The value is read up to the first comma, so USA 76,399 is drawn as 76 and nothing on the figure or in the checks says so.

Calendar Heatmap

Calendar Heatmap draws one year as a grid of days, seven rows by up to 53 week columns, in the style of a contributions graph. Each day is shaded by its value. Use it for activity, habits, incidents, sales or any daily series.

title "Commits in 2024"
year 2024
2024-01-05 3
2024-01-06 8
2024-02-14 5
2024-03-21 12
2024-06-30 1
2024-11-02 7

Syntax

StatementMeaning
title "…"The figure title
year YYYYThe year to draw. Optional: without it, the year of the first dated value is used, or the current year if there are no dated values
YYYY-MM-DD VALUEA value for one day. Values are zero or more (a negative number makes the line unreadable); decimals are allowed
  • Weeks run Sunday to Saturday, top to bottom, with Mon, Wed and Fri labelled and each month labelled where it begins.
  • Days with a value are shaded in four steps of green relative to the largest value, with a five-square Less to More legend whose first square is the empty colour. Days with no value, or a value of zero, are left empty.
  • Comments start with # or // at the start of a line.

What flowss checks

FindingLevelMeaning
A value dated outside the drawn yearErrorIt has no square, but it still sets the top of the colour scale, so every visible square may be paler than it should be
A date that does not exist, such as 2024-02-30ErrorIt is in the document and nowhere on the figure
A line that is neither a directive nor a dated valueErrorNothing is shaded for it
A date written twiceWarningThe last value replaces the earlier one rather than adding to it, which is what concatenating two exports produces
No dated value at allGapThe calendar is drawn empty

Word Cloud

Word Cloud sizes terms by weight and packs them, largest first, into centred rows, colouring them in turn from a fixed eight-colour palette. Use it for themes, keywords, survey free text and brainstorm summaries.

title "What customers mentioned"
performance 40
reliability 32
"developer experience" 28
security 24
"release 2024" 12
docs 9
pricing 6

Syntax

  • One term per line, optionally followed by a weight (a whole or decimal number of zero or more). A term with no weight gets a weight of 1.
  • Terms can contain spaces without quotes (developer experience 28), but quote a term whose name ends in a number, so the number is not taken as the weight: "release 2024" 12. Double or single quotes both work.
  • A negative number is not read as a weight: gamma -3 becomes the term "gamma -3" with the default weight of 1.
  • title "…" sets the title. Comments start with # or // at the start of a line.
  • Font sizes run from 16 to 56 pixels, scaled between the lowest weight (or 1, if that is lower) and the highest. With no weights at all, every term is drawn at 26 pixels.

What flowss checks

FindingLevelMeaning
A four-digit year (1900 to 2199) taken as the weight of an unquoted term, as in release 2024ErrorThat word is drawn far larger than everything else, and every other word shrinks. Quote the term
A weight of zeroErrorThe term carries no weight; it is drawn at the smallest size, so it looks merely rare. Give it a real weight or remove it
A term with no weight among weighted termsWarningIt defaults to 1, the smallest size, so it looks rare
The same term written twiceWarningIt appears twice at two sizes rather than once at their total
Every weight the sameWarningThe cloud carries no information in its sizes
No term at allGapThere is nothing to draw

Venn / Euler

Venn / Euler draws one, two or three overlapping circles and places your labels in the right regions, stacking several labels in one region. Use it for overlapping responsibilities, audience segments and skill matrices. The circles are a fixed arrangement; they are not sized to the data.

title "Who owns what"
set A "Sales"
set B "Marketing"
set C "Product"
only A "Quotas"
only B "Campaigns"
only C "Roadmap"
intersect "A,B" "Demand gen"
intersect "B,C" "Launches"
intersect "A,C" "Pricing"
intersect "A,B,C" "OKRs"

Syntax

StatementMeaning
title "…"The figure title
set ID "Label"Declare a set. Sets are drawn in the order declared, each with its own colour, and labelled with the label and the id
only ID "Text"A label in the region belonging to that set alone
intersect "ID,ID" "Text"A label in the overlap of two sets, or of all three with "A,B,C"

Set ids are usually single letters, but any short token works, quoted or not. A region line may come before the set it names. Comments start with # or // at the start of a line.

What flowss checks

FindingLevelMeaning
A label names a set that was never declaredErrorIt is not drawn; the figure says so in a notice
A label covers a fourth (or later) setErrorOnly three circles are drawn, so the region does not exist
A label names no set at allErrorNot drawn
More than three sets are declaredWarningThe figure is a three-set diagram; a fourth circle cannot produce the fifteen regions a four-set diagram needs
A set declared twice, or a set with no labelsWarningUsually an edit left over
An unreadable lineGapNamed with its line number

If no set can be read at all, the figure says so instead of drawing an empty circle, for example "No set in this source could be read, so there is nothing to overlap — line 1 was not read: …".


Charts documented on other pages

These engines draw charts too, but they belong to a workflow documented elsewhere:

EngineWhat it chartsDocumented in
Sales / conversion funnelStage-by-stage conversion, with each stage's rate and the end-to-end rateBusiness, strategy and planning engines
Waterfall ChartRevenue bridges, variance walks and budget walksBusiness, strategy and planning engines
Bullet / KPIKPIs against a target and qualitative bandsBusiness, strategy and planning engines
Marimekko / MosaicShare × volume in two dimensionsBusiness, strategy and planning engines
Quadrant Matrix2×2 matrices and points on two axesBusiness, strategy and planning engines
Pareto chartSorted bars with the cumulative-percentage curve and the vital fewProcess, operations and quality engines
Control chart (SPC)Control charts with computed limits and Nelson rulesProcess, operations and quality engines
Flow metrics (CFD)Cumulative flow diagrams with WIP, cycle time and throughputProcess, operations and quality engines
Flame GraphCPU and performance profilesSoftware and architecture engines
Cytoscape (Network)Large networks with force-directed and other layoutsSoftware and architecture engines
Mermaid pie, xychart-beta, quadrantChart, sankey-beta, radar-beta and treemap-betaQuick charts inside a Mermaid documentSoftware and architecture engines
Economics diagramsSupply and demand, IS–LM, Phillips, PPF, Lorenz curves and payoff matricesMaths, science and academic engines
Timeline (history)Eras and events across years or centuriesBusiness, strategy and planning engines

Choosing a chart engine

You want to…UseWhy
Plot some x and y values, or a formulaPlotShort text, honest defaults, draws on the server and offline
A statistical chart with layers, facets or aggregationVega-LiteThe grammar does the scales, axes and legends
A chart Vega-Lite cannot expressVegaFull control over every scale, mark and signal
3D surfaces, contours, ternary or polar plots, or a specialist scientific figurePlotlyThe widest range of trace types
A chart straight from a spreadsheetData → ChartRecommended figures are generated and checked without AI
Show where a quantity goes, with numbers that must add upSankey flowIt checks conservation at every node
Show parts of a whole in a hierarchyTreemapSquarified rectangles sized by value
Compare countries or US statesChoroplethA built-in, offline map
Show a daily series over a yearCalendar HeatmapOne square per day
Show which words matter mostWord CloudTerms sized by weight
Show overlapping groupsVenn / EulerLabels placed in the right regions
A multi-panel, journal-ready figure with statisticsThe Figure studioDataset to figure, with analysis
PlotVega-LitePlotlyVega
SourceShort text languageJSONJSONJSON
DrawnInside flowssIn your browserIn your browserIn your browser
Render API, thumbnails, offline server renderingYesNoNoNo
FormulasYes, adaptively sampledThrough sequence and calculate transformsNoThrough transforms
InteractivityNoYesYesYes
Size budget300,000 bytes80,000 bytes80,000 bytes80,000 bytes

Tips

  • Start from a template. Open the engine's reference page, or the template gallery filtered by engine, and replace the numbers with yours. Templates are worked examples that pass their own checks.
  • State what your error bars mean. In Plot, add error: sd, error: sem or error: ci to any series with intervals. A reader cannot tell a standard deviation from a confidence interval by looking.
  • Keep bars on a zero baseline. Setting y limits on a bar chart so the axis does not reach zero is allowed, but Plot will say in the figure that it overstates every comparison.
  • Use ln for natural logs in Plot. log is base 10.
  • Quote awkward labels. In Sankey flow quote ids with spaces; in Word Cloud quote terms that end in a number.
  • Check a Sankey before you share it. If the headline says a node does not balance, add a ribbon for the loss rather than adjusting a number to make it disappear.
  • Prefer native engines for automated output. Plot and the other native chart engines draw in embeds, thumbnails and the render API; Vega-Lite, Vega and Plotly need a browser.
  • Big data belongs elsewhere. The chart grammars are budgeted at 80,000 bytes of source. Aggregate first, or take the data to the Figure studio.

Limits and known constraints

  • Vega-Lite, Vega and Plotly cannot be drawn by the render API, which refuses them with needs-browser. Use the Studio or an embed.
  • Vega and Vega-Lite data URLs are meant for flowss itself, the Vega example datasets on jsDelivr, and raw GitHub and Gist files. Most other hosts are blocked.
  • Plot has no pie charts, dual axes, stacked areas, 3D, interactivity, CSV loading, date axes or regression fitting, by design. It draws at most 8 series, 2,000 points per series and 8,000 points in total.
  • Choropleth covers 45 countries on its world atlas and the 50 US states, as approximate hex tiles rather than true borders. Codes outside the atlas shade nothing, and numbers cannot carry thousand separators.
  • Venn / Euler draws at most three sets, in a fixed arrangement that is not proportional to the data.
  • Calendar Heatmap draws one year per figure and uses a fixed green colour scale.
  • Treemap ids cannot contain spaces, and the colour of each rectangle is chosen automatically.
  • Sankey flow reads up to 400 nodes and 2,000 flows; Treemap reads up to 2,000 nodes.
  • Size budgets apply before drawing: 300,000 bytes for Plot, 80,000 for Vega-Lite, Vega and Plotly, 150,000 for Choropleth, Calendar Heatmap and Word Cloud, and 60,000 for Sankey flow, Treemap and Venn / Euler.

Troubleshooting

What you seeEngineWhyWhat to do
"Source is … — past the … safe-rendering budget for …"AnyThe source is over the engine's budgetSplit the figure, trim the data or aggregate it
"Nothing to plot yet."PlotThere is no seriesStart with a series and its rows, for example scatter "A" then 0, 1
"No series in this document carried any data."PlotEvery series is emptyAdd rows under each series header
"«…» is a … series, and this figure has … It was not drawn"PlotThe series does not fit the figure's x axisMove it to its own figure; the first series decides the axis
"«…» was not drawn: «t» is not defined — the free variable here is «x»"PlotThe formula uses a name other than its variableUse the variable named after for, or change the for clause
"«…» takes 1 argument, not 2"PlotA function was called with the wrong number of arguments, such as ln(x, 2)Use log(x, 2) for a base-2 logarithm, or check the function table
"… is not an interval — write it as «y limits: 0 .. 24»"PlotThe limits could not be readWrite two numbers separated by .., a comma or to
"… is not a scale this engine has, so the x axis stayed linear."PlotUnknown scale nameUse linear, log, log2, symlog or sqrt
"1 series past the limit of 8 were not drawn: …"PlotToo many seriesSplit the figure
"A Vega or Vega-Lite spec must be a JSON object, not a string …"Vega, Vega-LiteThe source is a quoted stringPaste the specification object itself
A JSON parse message in the Render error boxVega, Vega-Lite, PlotlyThe JSON is invalid, often a trailing comma or a missing quoteClick Go to line if offered, or Explain & fix
"This Plotly document has no traces to draw …"PlotlyNo data and no trace foundProvide {"data": [...]}, an array of traces or a single trace
A chart with every mark at one position, or a legend entry "undefined"Vega-LiteAn encoding names a field the data does not haveOpen the readiness chip; the finding names the channel and the fields that do exist
A chart with data from a URL that never appearsVega, Vega-LiteThe host is blocked by the page's security policyPaste the values inline, or host the file on GitHub
"Add nodes — node photos size 7700"TreemapNo node could be readWrite node NAME size N; ids cannot contain spaces
A country stays in the no-data colourChoroplethThe code is not on the atlas, or is in lower caseUse the upper-case three-letter code from the atlas table; the readiness chip suggests a near match
A value far smaller than expectedChoroplethThe number has a thousand separator, so only the part before the first comma was readWrite the number without separators
A rectangle appears twiceTreemapThe same id is declared on two linesDelete one of the declarations
Every word is tiny except oneWord CloudA year at the end of a term was taken as its weightQuote the term, as in "release 2024" 12
"No set in this source could be read …"Venn / EulerNo set line could be readWrite set A "Label"

Something unclear or out of date on this page? Tell us from the Support link in any studio — the flowss team reads every report.

© 2026 Voranox Inc. flowss — Flow Systems Studio. All rights reserved.

This documentation, its text and its examples are protected by copyright. Engine and format names are trademarks of their respective owners — see the terms and copyright and licences.