Skip to content

Guides & reference

Lab views and renderers

Declare views in FlowScript, use the Figures gallery, and look up all 36 Lab renderers: what each is built from, computes and refuses.
Sculptural study of connected forms and structured ideas

In the Lab, a FlowScript document is a typed model of your study: its cohorts, arms, estimates, judgements and observations. A view is one way of drawing that model. You declare a view with a single line, such as view survival: km(os), and the Lab draws it with a renderer, a built-in figure type such as a Kaplan–Meier plot, a forest plot or a CONSORT flow. One document can carry many views of the same data, so a forest plot and its funnel plot can never be drawn from two different copies of the numbers. This page explains how views work, how to add and switch between them, how to use the Figures bench (the views gallery), and gives a reference entry for every one of the Lab's 36 renderers: what it is built from, the argument it takes, the options it reads, what it computes for you, what it refuses to draw, and the messages it shows when something is missing.

At a glance

TopicWhat you need to know
Declaring a viewview <name>: <renderer> or view <name>: <renderer>(<argument>, …) on a line of its own
Renderers available36, listed in the renderer reference below. Many also answer to one or more aliases
Adding a view without typingThe rail's Insert a block or view flyout (section Add view), or a worked example from the Figures bench
Seeing every figure with a working exampleRail: Figures, or ⌘K and type "Figures"
Switching viewsOne view is simply drawn. Two or three views appear as a toggle labelled Views in this document. Four or more appear as View rows in the zoom menu. ⌘K lists every view by name
Computed, never typedThe research figures compute their statistics (survival steps, AUC, pooled effects, τ², I², certainty, absolute risks) from your data. A number you type for the same statistic is checked against the computed one, never printed instead of it
When a figure cannot be drawnThe renderer draws an explanatory message instead of a figure, naming the block it needs. See Messages you may see
Example dataStarters that carry the "EXAMPLE text from a fictional …" notice are stamped Example data — not real on the canvas and on every export until you delete that notice
Plans and AIViews, the gallery and every renderer work without AI and without a network call. Your plan's access to the Lab is described in Lab and Plans and what they include

On Windows and Linux, read ⌘ as Ctrl and ⇧ as Shift.


How a view works

The declaration

A view is a one-line declaration in your FlowScript source:

view flow: consort(trial)
view survival: km(os)
view timeline: gantt

The parts are:

PartMeaning
viewThe keyword
flowThe view's name. It is what the view toggle, the zoom menu, ⌘K, share links and multi-panel figures use to refer to this view
consortThe renderer: the figure type to draw. A canonical id or any of its aliases
(trial)Optional arguments. Most renderers take one, naming the block to draw (km(os) draws the survival block called os). A few take something else, such as an instrument name for the risk-of-bias figures. Arguments may be identifiers, quoted strings or numbers, separated by commas

A document can declare as many views as you like. Each one is drawn from the same model, so every view of a document always agrees with every other.

Names, anonymous views and duplicates

  • A view without a name, such as view : consort(trial), still draws, but it is listed as untitled and nothing can address it. The checker warns: "This view has no name, so it is listed as untitled and nothing can address it — not the remembered tab, not a share link, not a panel child." and suggests an id. Give it a name.
  • Several unnamed views are listed as untitled, untitled-2, untitled-3 and so on.
  • A view name is a block id, so two views with the same name are a "Duplicate id" error, exactly like two blocks with the same id. Rename one of them.
  • The Lab remembers which view you were looking at, per document, and reopens it there.

Renderer names and aliases

Every renderer has one canonical id and may have aliases. view v: kaplan_meier(os) and view v: km(os) draw the same figure. If two names could collide, the canonical id always wins, so an alias can never silently redirect an existing view.

Two collisions are worth knowing:

  • funnel is the business conversion funnel. The meta-analysis funnel plot is funnel_plot (aliases small_study, publication_bias).
  • timeline is an alias of the clinical case timeline (clinical_timeline). The project timeline is gantt (alias roadmap).

What the checker tells you about views

The Lab's FlowScript checker validates view lines as you type:

SituationSeverityWhat you see
The renderer name is not one the Lab knowsError"View v names renderer x, which no renderer answers to — it would render as a placeholder reading "No view renderer named x" rather than fail." followed by "Did you mean …?" when a known name is within two edits, or otherwise by the first ten known renderer names and the total count
Two views share a nameError"Duplicate id … — every block id must be unique."
An argument names no block in the documentWarning"View v passes arg to renderer, but no block with that id is declared — the view would draw an empty figure rather than say so." with a suggestion when one is close
The view has no nameWarningThe untitled message above

Numeric arguments are never reported, and the risk-of-bias figures (rob_traffic_light, rob_summary_bar and their aliases) are exempt from the argument check because their argument is an instrument name, not a block id.

Illustrative values are drawn on every view

A FlowScript note is normally a private remark that no view draws. There is one exception: a note whose text contains the words "Illustrative values" or "(illustrative)" is drawn in a band below every view of the document. The figure's declared width never changes; the drawing grows downwards to make room. This is how a disclosure that some values were made up stays attached to the figure, whichever view a reader sees.

note disclosure { text: "Illustrative values: the counts below are invented for teaching." }

Example data stamp

The Lab's reporting-standard starters, and the Lab templates built on fictional data, open with a comment such as "Every string below is EXAMPLE text from a fictional trial: replace it." While that notice is in your source:

  • the canvas shows an amber note, Example data — not real. "This starter uses values from a fictional study — replace them with yours, then delete its "EXAMPLE text" notice to remove this mark from the figure and its exports." Click Got it to fold it to a small Example data chip; click the chip to open it again;
  • every view is drawn with a faint diagonal "EXAMPLE DATA" watermark and an amber Example data — not real label in the bottom-right corner;
  • the stamp travels with every export that comes from the canvas: SVG, PNG, print-size PNG, Copy image to clipboard, Export all views (ZIP) and the submission bundle.

To remove it, replace the example values with your own and then delete the notice line. The stamp is triggered by the words "EXAMPLE text from a fictional" (with upper-case EXAMPLE; "from fictional trials" counts too) anywhere in the source, so make sure no other line still contains them. The stamp disappears at the next redraw. The worked examples in the Figures bench do not carry that notice, so they are not stamped: treat every value in them as made up. See Core concepts and glossary for the marker across all studios.


Adding a view

There are four ways to add a view.

1. From the Insert flyout

  1. Click Insert a block or view on the Lab's tool rail (or run Insert block… from ⌘K).
  2. Type in the search field to filter, or scroll to the section headed Add view. Each row shows the renderer id and the engine's one-line description. The search matches the id, the renderer's domain and its description.
  3. Click a renderer. The Lab appends view <id>: <id> to your document, using the renderer id as the view's name (km, then km2, km3 if the name is taken), switches the canvas to it, and confirms with a toast such as "Added view 'km'".

A view added this way has no argument. Renderers that take one fall back to the first matching block in the document, which is what you want when there is only one. Add the argument by hand when you have several.

2. From a worked example on the Figures bench

The Figures bench shows every renderer with a complete, minimal document that compiles and draws. Use it when your document does not yet have the blocks a figure is built from. See The Figures bench below.

3. By typing

Open the Source shelf (rail Source, or ⌘\ to toggle the code pane) and type the line. After you type view <name>:, autocomplete suggests renderer names.

4. From the Advisor

The Lab's Advisor pane reads your document and your field of work and may propose a figure. Depending on what your document already has, the proposal either adds the view directly (when every block it needs is present) or opens the Figures bench on that renderer's card, for example "Nothing is drawn yet — add the Kaplan–Meier survival curves" or "Learn the Forest plot". See Lab.


Switching between views

How many views the document declaresWhere they appear
NoneThe canvas shows Add a view to draw it ("A view is how this document becomes a figure."), with Add a view (opens the Insert flyout) and Browse templates
OneIt is drawn. There is nothing to switch
Two or threeA segmented toggle labelled Views in this document on the view island, one segment per view name
Four or moreView rows in the zoom menu, each showing the view name and its renderer, with the current one checked
Two or more, on a phoneView rows under ⋮ ▸ Zoom

Every view also appears in ⌘K under Go to, labelled with the view's name, badged with its renderer and described as, for example, "Draw the km view of this document".

The Lab keeps drawing while your document has errors: the blocks that parsed are drawn as a best-effort figure, and the errors are listed in the Validation section of the document status popover (⇧⌘M). Only when the document has errors and there is nothing to draw does the canvas show Fix N errors to render ("The figure draws as soon as the source checks.") with Go to the first error. If a view's renderer fails while drawing, the canvas shows a notice such as "The "survival" view couldn't be drawn", the renderer's message, and: "Your source is fine — it parsed and validated, and only the drawing failed. Switch to another view, or undo the last change to this one; the rest of the studio keeps working."

To export one view or all of them, use the ⋮ menu's Export submenu: Export SVG, Export PNG (2×) (⌘⇧P), Export PNG (4×, print), Export PNG at print size (300 dpi), Export all views (ZIP) and Copy image to clipboard. Journal sizing, preflight and LaTeX are covered in Publishing, provenance and compliance in Lab and Exporting your work.


The Figures bench is the complete answer to "what can the Lab draw?". It lists every renderer the Lab registers, each as a card with a researcher's description, the blocks it is built from, what a list of blocks cannot say, and a worked example that compiles clean and draws the figure. The worked examples are checked against the real engine renderer by renderer, so pasting one never teaches you a broken shape.

Opening it

  • Click Figures on the Lab's tool rail. Click it again to close the workbench sheet.
  • Press ⌘K and choose Figures under Go to ("The gallery of view renderers, each with a scaffold you can start from").
  • Click an Advisor proposal that offers a figure. The bench opens with that figure's card expanded and scrolled into view, and clears any search or filter that would hide it.

The bench shares the workbench sheet with Source, Data, Statistics and Standards. On a narrow sheet, the shelves you are not using fold to icons.

Controls

ControlWhat it does
Search field (placeholder "survival, funnel, risk of bias…")Filters the cards. Every word you type must match (words are combined with AND), each as a case-insensitive substring. It searches the renderer id, every alias, the title, the purpose and the field labels. It does not search the worked examples or the note under Built from, so typing "2019" does not find the forest plot just because one example study is called "Ahmed 2019". An empty search shows every figure
Every field chipShows all fields. Selected by default
One chip per field of workShows only figures tagged with that field. Hover a chip to read the field's description; once selected, the description is shown in italics above the list
Count line"N of 36 figures", counting distinct figures on screen (a figure tagged with two fields is counted once), with the note "every card carries a working example"

Cards are grouped under field headings, in the order of the table below. A figure that serves two fields, such as roc, appears under both. If nothing matches, the bench says: "No figure matches those words in this field. Try one term at a time, or widen the filter to every field."

The fields of work

Field chipDescription shownFigures
Clinical trialsProspective interventional studies: allocation, follow-up and a pre-specified outcome.consort, km, table_one, spirit_schedule, intervention_table
EpidemiologyObservational cohorts and case-control studies, where the comparison was found rather than made.km, table_one
Clinical case reportsOne patient or a small series: what happened, in what order, and what came of it.clinical_timeline
Evidence synthesisSystematic reviews, meta-analysis, risk of bias and certainty of evidence.prisma, forest, funnel_plot, rob_traffic_light, rob_summary_bar, grade_sof, appraisal_table
Diagnostics and predictionDoes the test discriminate, is the model calibrated, and is acting on it worth it?roc, calibration, decision_curve
Health economicsCosts, effects and the trade-off between them.ce_plane, decision_curve
StatisticsDistributions, estimates and intervals, drawn from the observations rather than from summaries.forest, raincloud, panel, control_chart
Machine-learning evaluationBenchmarks, ablations and the discrimination and calibration of a learned model.ablation_table, roc, calibration
Laboratory scienceBench experiments: samples, conditions, replicates and readouts.experiment_flow, raincloud
Survey researchInstruments, constructs and the items that are supposed to measure them.item_map
Qualitative researchInterviews and focus groups: the themes found, the quotations that ground them, and whose voices they are.theme_map
Reliability engineeringFailure modes, their consequences, and what detection is worth.fmea_table
Operations and supplyNetworks of suppliers, plants and customers, with lead time and cost on the arrows.supply_map
Quality improvementIterative change in a service, judged against its own baseline over time rather than by one before-and-after.control_chart, intervention_table
Project deliveryPlans with dates on them, and the dependencies that decide whether the dates hold.gantt
Software architectureSystems, the containers they are made of, and what talks to what.c4_container
Business strategyObjectives, the measures behind them, and where a funnel leaks.funnel, okr_grid
FinanceOwnership, dilution and the arithmetic of a round.captable
SecurityThreats against assets, and how much of each one a control actually covers.risk_matrix
Education and assessmentCriteria, performance levels and the descriptors that keep marking consistent.rubric_grid
Law and contractsWho owes what to whom, and by when.clause_map
Scientific illustrationSchematics, scenes and composed multi-panel figures, where the structure is the claim.figure, scene, panel

A further field, Not yet filed, exists for any renderer that has no gallery card yet. Every renderer has a card today, so its chip does not appear.

What a card shows

Collapsed, a card shows the figure's title, its renderer id, a one-sentence purpose, and an in this document badge when your open document already declares a view with that renderer (under any alias). Click the card to expand it:

PartWhat it tells you
Built fromThe block kinds the figure is made of. Write these and you get the figure; write fewer and you get a shell or an explanatory message. This is the combination known to work, not always the only one: several figures accept a substitute, which the note below names
NoteWhat a list of blocks cannot say: how many of a block you need, which values are dropped silently, which values default to a number you did not state, and what the figure refuses
The engine calls it:The renderer's own one-line description, verbatim
Also accepted:Every alias the renderer answers to
Worked exampleA complete, minimal FlowScript document: the required blocks plus the view line
Start a new document from this exampleLoads the worked example (see below)

Starting from a worked example

A worked example is a whole small document: several blocks, the references between them, and a view line. It is never appended to your document, because adding it to a document that already uses the same block names would create duplicate ids and break every from: reference in the example. So:

  1. Expand the card and read the example.
  2. Click Start a new document from this example.
  3. The example replaces the content of the open document straight away. A toast reads "Template loaded —" followed by the renderer id (for example "Template loaded — km"), with an Undo button. There is no separate confirmation dialog (even though the small print under the button says the studio confirms first); the Undo in the toast, or ⌘Z, brings your document back.
  4. If your document had data rows bound from the Data bench, they are released, because they described the study that was there before. The Data bench says: "The rows bound to this document were released when the template replaced it — they described the study that was here before. Load the file again to switch the column checks back on."

If the open document already holds exactly that example, clicking the button does nothing.

Tip: To keep your current work and try an example, create a new document first (⌘K New document, or the document switcher), then start it from the example.

Renderer reference

The table lists all 36 renderers in the order the Lab registers them. The sections that follow describe each one in detail.

RendererFigureAlso acceptedBuilt fromArgument
consortCONSORT participant flownonecohortA study id
prismaPRISMA screening flownonecohortNone
ganttGantt timelineroadmapproject, taskNone
c4_containerC4 container diagramc4, containersystem, serviceNone
funnelConversion funnelnonefunnel_stepThe first step's id
okr_gridObjectives and KPI gridokrkpiNone
experiment_flowExperiment design flowexperimentexperiment, conditionNone
ablation_tableAblation tableablationmodel, dataset, eval, ablationNone
figureFree-form schematicschematicfigureNone
sceneIsometric 3-D scenescene3d, isometricscene, box3dNone
captableCapitalisation tablecap_table, captable_waterfallshareholderNone
risk_matrixRisk matrixstride, threat_matrixthreatNone
ce_planeCost-effectiveness planeicer, cost_effectivenessintervention (two or more)An econ_model id
item_mapInstrument item mapinstrument_map, survey_mapitemNone
fmea_tableFMEA risk-priority tablefmea, rpn_tablefailure_modeNone
supply_mapSupply-chain mapsupply_chain, supply_networksc_nodeNone
rubric_gridAssessment rubric gridrubric, criteria_gridcriterionNone
clause_mapContract clause mapagreement_map, contract_mapclauseNone
kmKaplan–Meier survival curveskaplan_meier, survivalsurvival, groupA survival id
rocROC curveauc, pr_curveroc, seriesA roc id
calibrationCalibration plotcalibration_plot, reliability_diagramcalibration, seriesA calibration id
decision_curveDecision curve (net benefit)dca, net_benefitdecision_curve, seriesA decision_curve id
forestForest plotforest_plotmeta, estimateA meta id
funnel_plotFunnel plot (small-study effects)small_study, publication_biasmeta, estimateA meta id
rob_traffic_lightRisk-of-bias traffic lightrob, robvis, risk_of_biasstudy, bias_domain, bias_assessmentAn instrument name
rob_summary_barRisk-of-bias summary barrob_summarystudy, bias_domain, bias_assessmentAn instrument name
grade_sofGRADE Summary of Findingssof, summary_of_findingsoutcome, estimate, grade_outcome, sof_rowA sof_row id
raincloudRaincloud plotdistribution, violindistribution, groupA distribution id
table_oneTable 1 — baseline characteristicsbaseline, characteristicstable_one, group, distributionA table_one id
panelMulti-panel figuremulti_panel, figure_panelview, panelThe container panel id
clinical_timelineClinical case timelinetimeline, case_timelinetimeline, timeline_eventA timeline or case_report id
theme_mapThematic map with quotationsthemes, qualitative_themes, coreqtheme, quotationA theme, study or qual_study id
spirit_scheduleSPIRIT schedule of assessmentsspirit, schedule_of_assessments, soaspirit_schedule, spirit_rowA spirit_schedule id
control_chartRun or control chartspc, run_chart, shewhartcontrol_chart, seriesA control_chart or series id
intervention_tableTIDieR intervention descriptiontidier, tidier_table, intervention_descriptiontidier_interventionstudy, tidier_intervention or arm ids
appraisal_tableCritical-appraisal table (AMSTAR 2)amstar, appraisal, checklist_tableappraisal, amstar_itemAn appraisal or study id, a block kind, or amstar2

Where a renderer takes an argument and you leave it out, it draws the first matching block in the document. Where an argument names nothing the renderer can use, the reporting-standard figures (ce_plane, theme_map, spirit_schedule, intervention_table, appraisal_table and similar) say so in a footnote and draw what they can, while the statistical figures (such as km, raincloud, table_one and grade_sof) draw a message naming the block they could not find.

A rule shared by the research figures

The renderers from km onwards, plus ce_plane and the reporting-standard figures, follow one rule: every statistic on the figure is computed from the data in your document. Attributes such as auc:, p_logrank:, median:, i2:, tau2:, egger_p:, slope:, certainty:, risk_difference: or mean: exist so you can transcribe a published result, but they are never printed in place of the computed value. When what you typed disagrees with what your data give, the figure prints the computed value and says so in a footnote. Colour is never the only channel: groups, judgements and phases also carry a symbol, a shape, a dash pattern or a word, so the figures survive greyscale printing and colour-vision deficiency.


Trial and review flow renderers

consort — CONSORT participant flow

Shows where every screened participant went (excluded, randomised, allocated, analysed) so a reader can check the trial's arithmetic before reading its result.

  • Built from: a chain of cohort blocks linked by from:. The root is the cohort with no from:. Each drop is accounted for in excluded: { reason: count, … }. study, arm and outcome are optional.
  • Argument: the study id, as in consort(trial).
  • How it draws: a vertical spine of cohort boxes with exclusion call-outs on the right (each reason with its count), and a row of arm boxes branching off the cohort each arm names in from: (an arm with no from: hangs off the last cohort). Each arm box shows its intervention: text beside its name. Any outcome blocks are summarised in a small results table underneath (events and n per control and treatment, the test and p). The validator checks the arithmetic, so a box whose numbers do not add up is flagged in your source. A cohort with no usable n is drawn as "n = —", never as 0. A number carrying an inline source (n: 420 source "Table 1") gets a small citation marker. An arrow is drawn only where you declared from:; two independent streams are drawn with a visible break rather than an invented arrow. A cohort reached twice, or a cycle of from: references, is drawn once.
  • Header: with a study block (the one named in the argument, or the first), the header is the study's id written as words, with its design: in capitals underneath. With no study block, the header is the title: of the document's first block with that block's kind underneath, or no header at all if the first block has no title. Nothing in this renderer prints the words CONSORT or PRISMA on its own.
  • Editing on the canvas: n values, box headings (when the cohort has a label:) and arm intervention text are click-to-edit; a corrected number is re-checked on the next compile.
  • Message: "Add a cohort block — e.g. cohort screened { n: 1500 }"
study trial {
  title: "Early mobilisation after hip fracture"
  design: "Randomised parallel-group trial"
}
cohort screened { n: 420 }
cohort randomised {
  n: 300
  from: screened
  excluded: { ineligible: 88, declined: 32 }
}
arm mobilisation { n: 150 from: randomised intervention: "Early mobilisation" }
arm usual_care { n: 150 from: randomised intervention: "Usual care" }
view flow: consort(trial)

prisma — PRISMA screening flow

Shows how a database search became an included set, with a reason and a count for every record dropped.

  • Built from: the same cohort chain as consort (identified, screened, full_text, included, each with from: and excluded:).
  • Important: prisma uses exactly the same drawing code as consort; choosing the prisma id does not change the output. A review normally declares no study block (in a review document a study is an included study), so the header comes from the title of the document's first block, as described under consort. The gallery card's note says the header reads PRISMA when there is no study block; the figure no longer prints that word itself, so name the review in the first block's title:.
  • Message: the same as consort.

Clinical, epidemiology and protocol renderers

km — Kaplan–Meier survival curves

Shows time to event by arm, with censoring marked and the numbers at risk underneath, computed from per-subject follow-up rather than a typed median.

  • Built from: a survival block with one nested group per arm. Each group carries times: (one follow-up time per subject) and a matching 0/1 events: list, plus an optional label:.
  • Life-table form: to digitise a published figure, add at_risk: to a group; times: then lists the distinct times and events: and censored: are counts. The life table goes through the same estimator, and a table whose at-risk column does not reconcile with its own counts is refused.
  • Argument: the survival id, as in km(os). Use it when a document has several survival blocks.
  • Options on the survival block:
AttributeEffect
time_unit:Label for the time axis, such as "months"
level:Confidence level as a fraction, such as 0.95 (the default). Never write 95
cumulative: trueDraw cumulative incidence (1 − survival) instead of survival
risk_table: falseSuppress the numbers-at-risk row. The figure's footnote states that it was suppressed
censor_marks: falseSuppress the censoring ticks. Also stated in the footnote
confidence_band:true or false. By default the band is on for a single curve and off when comparing arms
  • Computes: the product-limit curves, log–log confidence bands, numbers at risk, medians with their intervals, and the log-rank χ² and p. A typed p_logrank: that disagrees is reported in a footnote. Each arm gets a colour and a dash pattern; colours too pale to read against the background are adjusted, and the footnote says which.
  • Refuses: a curve with no events (it would assert 100% survival); competing_risks: true (1 − Kaplan–Meier overstates risk when competing events exist); a log-rank p for a single arm (the annotation explains why); a hazard ratio (put one in an estimate or effect block with its model stated); more arms than the palette can tell apart.
  • Messages: "Add a survival block with one group per arm …", "No survival block with id "x". …", "g has no subjects. Remove the group, or give it times.", "Zero subjects. …", "No events in N subject(s) — every follow-up ended without the outcome, …", and the competing_risks refusal.
survival os {
  title: "Overall survival by arm"
  time_unit: "months"
  group treated {
    label: "Treated"
    times: [4, 7, 9, 12, 12, 15, 18, 20, 24, 24]
    events: [1, 0, 1, 1, 0, 1, 0, 1, 0, 0]
  }
  group control {
    label: "Usual care"
    times: [2, 3, 5, 6, 8, 9, 11, 14, 16, 20]
    events: [1, 1, 1, 0, 1, 1, 1, 0, 1, 0]
  }
}
view survival: km(os)

table_one — Table 1, baseline characteristics

Describes the groups before anything was done to them, with the summary each variable's shape calls for.

  • Built from: a table_one block. A group directly inside it is a column (label:, n:). A distribution inside it is a row; a group inside that distribution is the row's cell, names its column with from: and carries the raw values:. A categorical row uses series blocks (with group:, labels: and counts in values:). Nesting decides meaning, so check it carefully.
  • Argument: the table_one id.
  • Options on the table_one block:
AttributeEffect
digits:Decimal places, a whole number from 0 to 6 (1 by default). A distribution row can set its own digits: (0 to 6), which overrides the table's for that row; the footnote names each row that does
p_values: trueAdd a p-value column. Honoured for any design. When the document describes a randomised design, the figure also prints an objection above the table and adds the standardised mean difference
overall: trueAdd a Total column
smd: trueAdd the standardised mean difference (two columns only)
continuous_summary:Table-wide summary for continuous rows: mean_sd, median_iqr, median_range, mean_ci or geometric_mean
categorical_summary:Table-wide summary for categorical rows: n_percent, percent or n

A row may declare its own summary: with the same words, which pre-specifies both the display and the test.

  • Computes: each summary from the observations (mean (SD) for symmetric data, median [IQR] for skewed data, n (%) for categorical), and says which rule chose it; missingness per cell as the column's denominator minus the observations present (never a typed missing:; when a column declares no n, the most complete row is used and a footnote says the denominator was inferred); tests for categorical rows by chi-squared, switching to Fisher's exact test for a 2×2 row with a small expected count; and adjusts the family of p-values for multiple comparisons by Holm's method. A row whose observations are all 0 or 1 is treated as a yes/no characteristic rather than summarised as a mean (SD).
  • Messages: "Add a table_one block with a group per arm and a distribution per characteristic …", "No table_one block with id "x". …", "t has no columns. Add a group per arm … — or list them with groups: ["Placebo", "Active"].", "t has no characteristics. …", and "No characteristic in t carries data. A row's cells are group blocks with from: naming a column and values: holding that column's observations."

clinical_timeline — Clinical case timeline (CARE item 7)

Lays one patient's episode of care against time, so a reader can see what happened, in what order, and how long each step took.

  • Built from: a timeline block (title:, origin: such as "Day 0 is the first presentation", optional orientation:) and one timeline_event per event with at: (such as "Day 26", "Week 11 after withdrawal" or a date), label:, and phase:. Optional detail goes in detail: (or details:, description:, note:, notes:, result:, findings:). An event whose text contains TODO is drawn as a placeholder.
  • Synonyms accepted: for the time, at, date, day, time, when, offset or t; for the text, label, title, text, name or event; for the phase, phase, category, type, stage, kind or status. If there is no timeline_event, an event block is read, and failing that a milestone.
  • Phases: presentation (sky blue, circle), diagnosis (orange, diamond), intervention (blue, square), adverse event (vermillion, inverted triangle) and outcome (bluish green, triangle). The phase is recognised from the word you write, so "adverse drug reaction" is an adverse event and "follow-up assessment" is an outcome. A phase outside these five gets its own open marker and colour. Each card also prints the phase name.
  • Header: the kicker reads CASE REPORT · CARE ITEM 7 TIMELINE when the document has a case_report block (or a guideline block naming CARE), and CLINICAL TIMELINE otherwise, followed by the number of events, the number of phases and the first and last times.
  • Time handling: events are spaced evenly in sequence (the footnote says so), and the interval since the previous event is printed on the axis whenever both times can be read in the same frame. A time relative to another event ("Week 11 after withdrawal") is resolved against that event. Intervals converted through months or years are marked ≈. An unreadable time gets no interval, never a guessed one. When every event resolves to one frame, events are drawn in chronological order; otherwise in document order.
  • Layout: horizontal while every card can be at least 150 units wide and there are no more than 12 events (at the default width that is up to nine events), vertical beyond that. orientation: "horizontal" or "vertical" (or layout:) on the timeline block overrides.
  • Argument: a timeline id, or a case_report id whose title heads the figure. With several timeline blocks, events attach to their timeline through timeline: or of:, or by being nested inside it.
  • Message: "Add timeline_event blocks to draw the case timeline — e.g. timeline_event onset { at: "Day 0", label: "Presenting symptoms", phase: "presentation" }."

spirit_schedule — SPIRIT schedule of enrolment, interventions and assessments

Shows a trial protocol's visit schedule on one page, as SPIRIT 2013 item 13 asks.

  • Built from: a spirit_schedule block whose periods: list is the columns, each led by its code ("-t1 Screening", "0 Allocation", "t1 Week 6", "Close-out"), and one spirit_row per procedure with section: (Enrolment, Interventions or Assessments), label: and at: (the period codes it happens at).
  • Matching: a row's at: entries are matched on the period's first word only, so at: ["-t1"] lands in the column "-t1 Screening (week −2)".
  • Placeholders: a row with placeholder: true, or whose label starts with TODO, is drawn faint and in italics until you write it, and a footnote counts them.
  • Missing pieces: with no spirit_schedule block, the columns are taken from the rows' at: lists and a footnote asks you to declare the periods; a row with no section: is drawn under "Unassigned rows".
  • Several schedules: a row with schedule: <id> belongs only to that schedule; a row without one belongs to whichever schedule is drawn. With no argument the first schedule is drawn and a footnote says so; an argument that names no spirit_schedule is reported in a footnote.
  • Header: read from study (title, registry) and protocol (version, allocation_ratio); summary chips from arm (n) and outcome (role).
  • Argument: the spirit_schedule id.
  • Message: "Declare a spirit_schedule with its periods, and one spirit_row { section, label, at } per procedure, to draw the SPIRIT schedule of enrolment, interventions and assessments."

Diagnostics and prediction renderers

These three renderers share one set of per-subject data: scores or predicted probabilities, and 0/1 outcomes. A prediction paper that shows discrimination should also show calibration and clinical usefulness, and these are built to sit side by side.

roc — ROC curve

Shows how well a score separates cases from non-cases across every threshold.

  • Built from: a roc block with a nested series. In the series, x: holds one score per subject and y: the matching 0/1 outcome.
  • Paired curves: a second series may omit y: to inherit the first one's labels. That makes the two curves paired, which is what allows the DeLong comparison between them.
  • Argument: the roc id.
  • Option: level: on the roc block sets the confidence level.
  • Computes: the curve, the area under it and its confidence interval, and the Youden-optimal cut-off (marked and labelled with its sensitivity and specificity, as the criterion's choice rather than a result). With two curves on the same subjects it runs DeLong's paired test; if the two series do not share one label vector, a note says the test was not run. A typed auc: is not what is drawn. The panel is square by construction so the chance diagonal stays a diagonal.
  • Refuses: a curve from one class (no positives or no negatives); a zero-width interval when the area is exactly 1.
  • Limitation: the alias pr_curve still draws the ROC curve. There is no precision–recall view today, even though the footnote on an ROC whose prevalence is below about 10% recommends one (and names a renderer that does not exist).
  • Messages: "Add a roc block — e.g. roc model_a { series subjects { x: [0.1, 0.8, …] y: [0, 1, …] } }.", "roc needs per-subject data — add series subjects { x: […] y: [0, 1, …] } inside it. …" and "No ROC curve is computable from this block. …"
  • Labels: the chance diagonal's name, the cut-off label and the statistics block are placed clear of every curve. On a narrow figure the statistics block may move below the x axis.

calibration — Calibration plot

Shows whether predicted risks match observed risks.

  • Built from: a calibration block with a nested series: x: must be predicted probabilities between 0 and 1 (not raw scores), y: the 0/1 outcome.
  • Options: bins: chooses the number of groups (a whole number of 2 or more; 10 by default); level: the confidence level.
  • Computes: observed versus predicted risk by bin (each dot at the bin's mean predicted risk), the calibration slope and intercept, the Brier score, and the integrated calibration index (ICI) with E90. A typed slope: is not drawn. The panel is square, with the ideal line drawn corner to corner. Only the first series is analysed.
  • Messages: "Add a calibration block — e.g. …" and, with no per-subject data, the same "needs per-subject data" message as roc followed by "x must be predicted PROBABILITIES in [0, 1], not scores."
  • Labels: the ideal (diagonal) line is named in the legend, which is placed clear of the points; on a narrow figure it may move below the x axis, and a very long series name may be shortened there (the full name stays in the figure description).

decision_curve — Decision curve (net benefit)

Shows whether acting on a model beats treating everyone or nobody across the threshold probabilities a clinician might use.

  • Built from: a decision_curve block with a nested series whose x: holds predicted probabilities and y: the 0/1 outcome.
  • Option: thresholds: is used only when every entry lies strictly between 0 and 1; otherwise the curve uses 0.01 to 0.50.
  • Computes: net benefit for the model, treat-all and treat-none, and the range of threshold probabilities over which the model beats both (or says that there is none). Unlike the other two, this panel is not square.
  • Messages: "Add a decision_curve block — e.g. …", the "needs per-subject data" message, and "A decision curve needs at least two threshold probabilities. Give thresholds: [0.05, 0.1, …], or leave it unset for 0.01 … 0.50."
  • Labels: the treat-none line is named in the legend, which is placed clear of the curves and may move below the x axis on a narrow figure.

Evidence synthesis renderers

forest — Forest plot

Shows every study's estimate beside the pooled result, with marker area proportional to weight and the prediction interval drawn apart from the confidence interval.

  • Built from: a meta block and its study rows: estimate, effect or contrast blocks nested inside the meta, or beside it carrying of:. Rows inside a subgroup block form subgroups (named by its category, stratum, label or id).
  • On the meta block: measure: (such as rr), scale: log for ratio measures (risk, odds, hazard ratios; a recognised ratio measure gets the log scale even if you leave scale: out, and scale: identity forces a linear axis), level: for the confidence level, title:, and model:. A weight_by: other than inverse_variance is noted and not honoured.
  • Where each row's numbers come from, in order of preference: counts on a contrast (events_a, n_a, events_b, n_b); an estimate with its interval (point, lo, hi); an estimate with a standard error (point, se). A published pooled summary is never used as a row.
  • Pooling (model: on the meta block):
You writeWhat is drawn
nothingRandom effects, DerSimonian–Laird τ²
fixed, fixed_effect, common_effect or inverse_varianceFixed effect, inverse variance
random, random_effects or dersimonian_lairdRandom effects, DerSimonian–Laird
paule_mandelRandom effects, Paule–Mandel τ²
reml or mlRandom effects, REML τ² (a note says REML is used when you wrote ml)
hartung_knapp or hksjRandom effects with the Hartung–Knapp interval
mantel_haenszelInverse-variance fixed effect, labelled as such, with a note that Mantel–Haenszel weights are not computed
petoInverse-variance fixed effect, with a note that Peto's one-step odds ratio is not computed
bayesianDerSimonian–Laird random effects, with a note that no posterior is computed
  • Computes: each study's weight, the pooled estimate and interval, τ², I², Q and its p, the prediction interval (which needs at least three studies; the row says why when it cannot be computed), and for subgroups their own diamonds and the between-subgroup test. Typed pooled values (point, i2, tau2, q, p_heterogeneity, prediction_lo, prediction_hi on the meta) are never printed; disagreements are footnoted.
  • Drawing: marker area (not side) is proportional to weight; ratio measures use a log axis with the null at 1; an interval that leaves the axis gets an arrowhead.
  • Refuses: a pool of one study; a row with no interval and no standard error (drawn as its own refusal row and left out of the pool, with the count in the footnote); a ratio at or below zero.
  • Argument: the meta id. Any other model: word than those in the table is read as DerSimonian–Laird random effects.
  • Messages: "Add a meta block with one estimate per study — e.g. …", "No meta block with id "x". …" and "pooled has no study rows. Add one estimate per study … inside the meta, or beside it with of: pooled."
meta pooled {
  title: "Antibiotic prophylaxis and surgical site infection"
  measure: rr
  scale: log
  estimate trial_a { label: "Ahmed 2019" point: 0.68 lo: 0.51 hi: 0.90 n: 412 }
  estimate trial_b { label: "Barros 2020" point: 0.81 lo: 0.62 hi: 1.06 n: 528 }
  estimate trial_c { label: "Chen 2021" point: 0.59 lo: 0.38 hi: 0.92 n: 244 }
  estimate trial_d { label: "Dubois 2022" point: 0.74 lo: 0.55 hi: 0.99 n: 366 }
}
view forest_plot: forest(pooled)
view small_study: funnel_plot(pooled)

funnel_plot — Funnel plot (small-study effects)

Plots effect against precision to look for small-study effects.

  • Built from: exactly the same meta and rows as forest. One meta serves both figures, so they can never disagree about which studies are in the review.
  • Draws: the standard-error axis inverted (0 at the top); shaded pseudo-confidence contours at 90, 95 and 99%; Egger's regression line with its test; trim-and-fill imputed studies as open downward triangles in their own colour and legend entry, with the pool printed before and after; and, below about ten studies, a statement in the panel that the funnel's shape is dominated by chance.
  • Refuses: a funnel over one study; Egger's test below three studies or when every study has the same precision; trim-and-fill when every standard error is identical. A typed egger_p: is never printed.
  • Reading it: asymmetry is not the same thing as publication bias, and with real heterogeneity studies fall outside the pseudo-limits for other reasons. The figure reprints those caveats.
  • Argument: the meta id.

rob_traffic_light — Risk-of-bias traffic light

Shows every study's risk-of-bias judgement domain by domain as a grid.

  • Built from: study blocks (the rows), bias_domain blocks (the columns: tool:, name:, label:, order:) and one bias_assessment per study per domain (study:, domain:, tool:, judgement:, optional support:). Both references must name blocks the document declares, and the domain ids must match the instrument's own domains. RoB 2 wants all five.
  • Argument: the instrument, not a block id: rob2, robins_i, robins_e, quadas2 or robis.
  • Instrument choice: with no tool: anywhere, the figure assumes RoB 2. If the document names two instruments and the view gives no argument, it refuses and asks you to draw one figure per instrument. AMSTAR 2 is not a grid and is refused here; use appraisal_table.
  • Judgement symbols:
SymbolJudgements
+Low; probably low
!Some concerns; moderate
?Unclear; no information
−Probably high; high; serious
×Critical
·Not assessed

Each cell carries the symbol, a silhouette (which only differs where two judgements share a symbol) and a colour-blind-safe fill.

  • Row labels: each row is labelled with the study's label:, else its title:, else its id written as words (smith_2019 reads "Smith 2019"). A label or title that is still a placeholder (containing TODO) is ignored.
  • Unrecognised judgements: a missing or misspelt judgement: is drawn as Not assessed (·), never guessed.
  • Overall column: an overall you recorded is what the cell shows; if your own domain judgements contradict it, a footnote says so and names the domains. When you recorded no overall, RoB 2 derives one by its own rule, and ROBINS-I and ROBINS-E by ROBINS-I's rule; a derived overall is drawn with a dashed border and a footnote says it is the tool's arithmetic, not the assessor's judgement. QUADAS-2 has no overall column at all (unless your document asserts one) and adds its applicability columns instead; ROBIS's overall is its phase-3 judgement and is never derived.
  • Before any judgement is recorded: a document that declares the instrument's bias_domain blocks and names its studies, but has no bias_assessment yet, draws the full grid with every cell "not yet judged" rather than a refusal.
  • Messages: "No risk-of-bias judgements for tool in this document. Add a bias_assessment per study and domain …", the two-instrument refusal ("This document assesses risk of bias with N different instruments … Draw one figure per instrument …"), and "x is not an instrument this figure can lay out as a studies × domains grid. …"

rob_summary_bar — Risk-of-bias summary bar

Shows the percentage of studies at each judgement, domain by domain, in the instrument's own domain order (never sorted by severity). Within each bar, segments stack by severity. It reads the same blocks and takes the same instrument argument as rob_traffic_light, with the same refusals, so one set of assessments serves both figures. When you recorded no overall judgement, the Overall bar counts the overalls RoB 2 or ROBINS-I derive by their own rules, exactly as the grid's overall column does, and is labelled Overall (derived), or Overall (k of n derived) when only some were derived.

grade_sof — GRADE Summary of Findings

Puts the certainty of the evidence, the relative effect and the absolute risks in one table a guideline panel can act on.

  • Built from: for each outcome, an outcome (metric:, role:, timepoint:), an estimate (the pooled relative effect with measure, scale, point, lo, hi), a grade_outcome rating the five downgrading domains (starting_certainty:, risk_of_bias:, inconsistency:, indirectness:, imprecision:, publication_bias:, plus studies:, participants:, design:) and a sof_row pointing at all three (outcome:, estimate:, grade:, risk_control:, participants:, studies:, importance:).
  • Write the comparator risk with its denominator: risk_control: 220 per 1000, or as a percentage (22%), or as a bare fraction between 0 and 1 (0.22). A bare 220 is refused, because it could be per 1000 or per 100 000, and a unit that is not a proportion is refused too.
  • Computes: the absolute risks per 1000, as whole people, from the comparator risk and the relative effect, worded "N fewer per 1000 (from A fewer to B more)"; and the certainty by GRADE's stepwise rule from the domain ratings. A typed certainty:, risk_intervention: or risk_difference: that disagrees is footnoted, not printed.
  • Refuses per cell: a row with no grade_outcome, or one that rates none of the five domains, gets a certainty cell that says so and names the fix. A reference that does not resolve turns that cell into a footnote rather than blanking the table.
  • Certainty display: the word plus the conventional circle glyphs (for example ⊕⊕⊕⊖ for moderate). No colour is used.
  • Argument: a sof_row id draws one row; with none, every row is drawn.
  • Messages: "Add a sof_row per outcome — e.g. … — and a grade_outcome rating the five downgrading domains." and "No sof_row with id "x" in this document."

appraisal_table — Critical-appraisal table (AMSTAR 2)

Appraises a systematic review item by item against AMSTAR 2, with the critical domains flagged, so the overall confidence can be traced to the answers.

  • Built from: an appraisal block (tool: amstar2, version:, review_question:, assessors:, disagreements:, optional confidence:), a study for the header, and one amstar_item per item with number: "1" to "16", answer: (yes, partial_yes, no or not_applicable) and note:.
  • Critical domains: items 2, 4, 7, 9, 11, 13 and 15 are flagged with a filled number, a CRITICAL DOMAIN chip and a rule down the row.
  • Overall confidence: shown only once all sixteen items are answered, computed by AMSTAR 2's critical-domain rule on the High / Moderate / Low / Critically low scale. Until then the panel reads Not yet rated with the number of items left. A confidence: you wrote on the appraisal is checked against the rule, not trusted.
  • Answers: an unanswered item, or one whose answer is only a TODO, is drawn as Not yet judged; an answer the figure cannot place is shown verbatim, labelled Unrecognised and counted as not yet judged. Neither is ever drawn as yes. Five tally tiles (Yes, Partial yes, No, Not applicable, Not yet judged) double as the legend, with Can't tell and Unrecognised tiles added when they occur.
  • Other checklists: any block carrying answer: or judgement:, such as casp_item q1 { question: "…" answer: cant_tell }, draws as the same table with a wider vocabulary (yes, partial, no, can't tell, not applicable). No published rule turns those into a rating, so the panel shows the overall judgement your appraisal states.
  • Arguments: each may name an appraisal, a study, a block kind to treat as the items (appraisal_table(casp_item)) or the tool amstar2. Arguments that name a kind or a tool rather than a block may draw an "argument names no block" warning in the checker; the figure still draws.
  • Width: below 700 px the support column folds under the question.
  • Messages: "Declare an appraisal block with tool: amstar2, or one block per appraisal item with a number, a question and an answer …" and "No x block carries an item to draw. Give each one a question and an answer."

intervention_table — TIDieR intervention description

Describes each intervention and its comparator item by item, the twelve TIDieR items down the side, so another team could deliver it again.

  • Built from: one tidier_intervention per column, the comparator included, with the twelve fields brief_name, why, materials, procedures, provider, mode, location, schedule, tailoring, modifications, fidelity_planned and fidelity_actual.
  • Pairing with arms: an arm whose intervention: text names a description's id pairs with it and lends the column its label and n.
  • Not reported versus not applicable: an empty field, or one containing only TODO, is marked Not reported. Item 12 is drawn as Not applicable only when item 11 says fidelity was not assessed.
  • Header: four tiles count what is reported, not reported and not applicable; each column has a twelve-segment completeness strip and a letter.
  • Arguments: each may name a study (the header), a tidier_intervention or an arm (draw only those columns, in that order).
  • Width: the figure widens rather than squeezing a column below its minimum; a cell may run to 28 lines before it is shortened.
  • Message: "Declare a tidier_intervention block per intervention — the comparator included — with the twelve TIDieR fields (…)."

Statistics and quality improvement renderers

raincloud — Raincloud plot

Shows the whole distribution (a half violin for its shape, a box for the robust summary and every raw observation as jittered points) instead of a mean and an error bar.

  • Built from: a distribution block (title:, unit:) with a nested group per condition, each with label: and raw values:, one entry per observation and null for a missing one.
  • Options on the distribution block: bandwidth_rule: silverman or scott chooses the kernel bandwidth rule; bandwidth: with a number fixes it. The rule and the numeric bandwidth are printed for every group.
  • Deterministic jitter: point offsets come from the data and the block ids, so the same data redraw identically in every export.
  • Computes: density, quartiles, Tukey whiskers, n, missing, mean and SD from the observations. Typed mean:, sd: or median: are footnoted when they disagree.
  • Refuses: a distribution that gives only summary statistics (mean: and sd:, or a five-number summary) and no observations. Use forest for an estimate or table_one for a baseline row instead. A group with no values: is left out of the figure.
  • Bandwidth notes: if you give both bandwidth: and bandwidth_rule:, the number wins and a footnote says so; an unknown rule name falls back to Silverman's, with a footnote. For data that are all non-negative, the drawn density is truncated at 0.
  • Argument: the distribution id.
  • Messages: "Add a distribution block holding the raw observations — …", "No distribution block with id "x". …", "x.values is not a list of numbers. Write values: [4, 6, 6, 9] …", "recovery gives mean, sd but no values. A raincloud needs the observations …", "recovery has no values. …", and "Every observation in recovery is missing or non-finite, so there is no distribution to draw. Check the column mapping — a text column read as numbers produces exactly this."

control_chart — Run or control chart (SQUIRE 2.0)

Tracks a measure over time against its own baseline, with the changes your team made marked and the special-cause signals computed rather than judged by eye.

  • Built from: a control_chart block (what counts as a signal) and a series (the points: values:, month labels: such as "2024-01", unit:). Link them with of: on the series when a document holds more than one chart.
  • On the control_chart block: metric:, chart: (free text naming a run chart, an I chart, or a p, u or c chart), baseline_period:, centre_line:, intervention_at: (each change becomes a numbered marker), rules:, limits: (such as "2 sigma") and annotations: (other events, lettered).
  • Denominators: a p or u chart needs each point's denominator in the series' n:.
  • Baseline: found, in order, from a date range in baseline_period matched to the labels; else every point before the first change in intervention_at; else a count in baseline_period ("the first 12 weeks"); else every point. The footnote says which.
  • Computes: the centre line from the baseline (median for a run chart unless centre_line says mean; mean for I; n-weighted mean for p and u; mean count for c), control limits for I, p, u and c charts (sigma multiplier from limits, default 3), re-based phases where the chart says it was re-based, and the signals: a shift (default 8 points on one side), a trend (default 6 points rising or falling) and points beyond a limit. Rule lengths are read from your rules text. A typed centre line that disagrees is reported. An aim line is drawn from a kpi whose title matches the metric.
  • Not computed: x̄–S limits (only the centre line is drawn, with a note), Laney p′ or u′ limits, "astronomical point" judgements, and any rule the figure cannot recognise, which is listed as not evaluated.
  • Argument: a control_chart or series id.
  • Message: "Declare a control_chart block (metric, chart, baseline_period, centre_line, intervention_at, rules) and a series with values and labels to draw the run or control chart."

Qualitative and survey renderers

theme_map — Thematic map with quotations

Shows the themes a qualitative analysis found, the sub-themes under each and the attributed quotations that ground them.

  • Built from: theme blocks (label:, description:, major:, and of: naming the parent for a sub-theme) and quotation blocks (text:, participant:, of: naming the theme).
  • Header and sample: a study or qual_study supplies the header. The cohort chain is printed as the sample line, and the participant count is the n of the cohort (or cohorts) at the end of the chain; with no cohort the PARTICIPANTS tile reads "—" and "no cohort declared". An instrument with its items is read as the topic guide.
  • Tiles: PARTICIPANTS (the sample size and the cohort it comes from), THEMES (with the number of major themes and sub-themes), QUOTATIONS (flagging quotations linked to no theme, or themes without one) and VOICES QUOTED (distinct participants quoted, as a share of the sample when the sample is known).
  • Counts per theme: quotations (sub-themes included), share of all quotations, and distinct voices. Voices are counted from the participant: identifiers, so keep them pseudonymised but consistent. A quotation with no participant is shown as "— unattributed".
  • Argument: a theme id (draw only that branch) or the study/qual_study the header should describe.
  • Message: "Declare theme blocks (sub-themes name their parent with of:) and quotation blocks with participant and of: to draw the thematic map."

item_map — Instrument item map

Shows which items measure which construct in a survey instrument, with reverse-coded items marked.

  • Built from: item blocks (text:, construct:, scale:, reverse: true). instrument and construct are optional. An item whose construct: matches no construct collects in an "Unassigned items" group.
  • Message: "Declare an instrument, at least one construct, and items."

Health economics renderer

ce_plane — Cost-effectiveness plane

Plots incremental cost against incremental effect for every strategy, with the full incremental analysis drawn on top.

  • Built from: at least two intervention or economic_strategy blocks with a numeric cost: and qalys: (or effect: with effect_unit:). An econ_model (title, currency, horizon, perspective, discount) is optional. A willingness-to-pay threshold: on an icer or psa block draws a dashed ray.
  • Reference: the strategy whose arm: names standard or usual care sits at the origin; otherwise a comparator or control arm; otherwise the cheapest.
  • Draws: the frontier as a solid line labelled with sequential ICERs; strongly dominated strategies as ×, extendedly dominated as ◇, the frontier as ●, the reference as ◎; and an incremental-analysis table beside the plane at widths of 760 px and above, underneath it below that.
  • Whose verdict: a status you declared (on_frontier, dominated, extendedly_dominated) is what is drawn; the computed analysis fills in strategies that declare none, and every disagreement is footnoted.
  • Argument: an econ_model id restricts the plane to strategies naming it in of: (plus those naming none).
  • Message: "Declare at least two economic_strategy (or intervention) blocks with a cost: and qalys: — one of them the comparator, arm: standard_of_care."

Composition and illustration renderers

panel — Multi-panel figure

Composes several views into one journal-ready plate, labelled a, b, c and aligned on their plot rectangles rather than their outer boxes.

  • Built from: panel blocks in two roles. A panel without view: is the container (rows:, cols:, width: in millimetres, height:, gutter:, gutter_x:, gutter_y:, share_x:, share_y:, label_style:, label_position:, title:). A panel with view: is a child naming a view your document declares (row:, col:, row_span:, col_span:, caption:, alt:, and label: or letter: to override its letter). A panel figure therefore needs everything its children's renderers need.
  • Argument: the container's id, as in panel(figure_1).
  • Width, from the strongest statement available: width: on the container; else the width_mm of a publish block for this panel; else the named journal's column measure; else a width supplied by the place the figure is drawn (converted at 96 dpi); otherwise an 85 mm single-column fallback. The footnote states which source was used.
  • Columns when you give none: one panel uses one column; at widths of 150 mm or more, up to three; otherwise up to two. Height is derived from what the panels need (capped at 297 mm unless the destination sets its own limit), unless you declare height:.
  • Letters: bold lower case, outside the panel above its top-left corner, assigned in reading order (top row left to right, then down). label_style: accepts a, A, (a), (A), a., A., 1, 1. or i. label_position: accepts top-left or inside-top-left, top-right or inside-top-right, top-center or above-center (outside, centred), and above, outside or outside-top-left (the convention). An unknown style or position falls back to the convention, with a note.
  • Shared axes: share_x and share_y are verified. Two panels on different scales under one shared axis are reported, never drawn as if they agreed.
  • Degrades gracefully: a child view that refuses, fails or does not exist becomes a labelled placeholder in its cell; the other panels still render.
  • Limitations: it cannot hide a child's duplicate axis, and it cannot restyle a child's type. Each child is drawn at its own cell's width to keep scaling near 1, and an effective point size far from the nominal one is reported.
  • Messages: "panel p has no panels to compose. Add panel { view: <view id> } blocks — one per panel — naming views this document declares." and "A panel figure is one or more panel { view: <view id> } blocks, optionally inside a panel { rows: 2 cols: 2 width: 88 mm } container. This document has none."
panel figure_1 { title: "Recovery and pooled effect" rows: 1 cols: 2 width: 180 mm }
panel panel_a { view: spread row: 1 col: 1 }
panel panel_b { view: pooled_effect row: 1 col: 2 }
view composite: panel(figure_1)

Here spread and pooled_effect are two other views the document declares (a raincloud and a forest).

figure — Free-form schematic

Draws a mechanism, apparatus or concept as a labelled schematic.

  • Built from: a figure block (title:, width:, height:) plus shape (kind: such as "rect" or "circle", position, size, fill:, stroke:, label:), label_2d, arrow_2d (from:, to:, label:), annotation and group_2d blocks.
  • Notes: a figure with no children draws an empty canvas at its declared size. Any other block kind inside is ignored without a message, and an arrow_2d whose endpoints do not resolve draws nothing.
  • Message: "No figure block — try figure my_diagram { width: 800, height: 500 … }"

scene — Isometric 3-D scene

Shows a three-dimensional arrangement as an isometric projection placed by coordinates.

  • Built from: a scene block (title:, projection:, width:, height:, grid:, axes:) and at least one primitive: box3d, sphere3d, cylinder3d, plane3d, edge3d or label3d.
  • Note: the canvas size comes from the scene block's own width and height; a width requested by the host is ignored when the block declares one.
  • Messages: "No scene block — try scene lattice { projection: isometric … }" and "Add at least one 3D primitive: box3d, sphere3d, cylinder3d, plane3d, or edge3d."

Machine learning and laboratory renderers

ablation_table — Ablation table

Ranks what each component of a system is worth by removing it.

  • Built from: model, dataset, one eval (the baseline) and ablation blocks (base:, change:, delta:). model: and dataset: are required references on eval, so an eval without them is a compile error ("eval is missing required attribute model"). An ablation with no delta: is read as zero, which is a claim, so write it.
  • Messages: "No eval block — declare one as the baseline." and "Add ablation blocks to compare against the baseline."

experiment_flow — Experiment design flow

Shows a bench experiment's design (samples, conditions, doses and readouts) at the level someone else would need to repeat it.

  • Built from: an experiment block (title:, model:) plus at least one sample (n:, replicates:) or one condition (title:, dose:, duration:). assay blocks (kind:, readout:) add the readout panel. Animal-study blocks are also read.
  • Messages: "No experiment block found — try experiment my_screen { … }" and "Add at least one sample and one condition."

Business, engineering and other renderers

RendererBuilt from, and what to watchMessage when something is missing
ganttA project (title, start, end) and task blocks (title, start, end, depends: [...]). A task is dropped silently unless both dates parse as YYYY-MM-DD, and a milestone unless its date: does. Milestones alone draw a plan with "0 tasks""No project block found — try project q3_launch { … }" and "Add a task or milestone to populate the timeline."
c4_containerA system and service, datastore or actor blocks with depends:. tier: decides the row: edge/frontend first, then core/backend, then data/store; anything else sorts last, alphabetically. With no tier:, a datastore goes in the data row and a service in the core row. An actor with depends: [...] gets one arrow to each container it names; an actor that names none gets a single dashed arrow to the first container of the top row, titled as an assumed entry point (declare depends: on the actor to replace it)"No system block found — try system saas_platform { … }" and "Add a service, datastore, or actor block."
funnelfunnel_step blocks (title, n) chained by from:, not by document order. The head is the step with no from:; pass its id as the argument, as in funnel(visited)"Add a chain of funnel_step blocks linked via from:."
okr_gridkpi blocks (title, baseline, target, unit). An initiative supplies the banner and segment blocks a customer-segment strip. A KPI missing a baseline or target prints a prompt instead of inventing numbers"Declare an initiative and at least one kpi."
captableshareholder blocks (name, shares, class, role) and optional option_pool (shares, granted; only the ungranted remainder is a bar), cap_table (title, currency, default USD) and round. Percentages are computed from share counts"Declare a cap_table and at least one shareholder." and "Total shares is 0 — fill shares on each shareholder."
risk_matrixthreat blocks (title, asset, category, likelihood, impact) on a 5×5 grid. Likelihood and impact default to 3 when absent, so state both. A control reduces the residual likelihood of each threat in its mitigates: list by its coverage:"Declare a threat_model and at least one threat."
fmea_tablefailure_mode blocks (component, mode, cause, effect, severity, occurrence, detection), ranked by RPN. Each rating defaults to 5, giving an RPN of 125, so state all three. A mitigation (mode, action, target_occurrence, target_detection) shows the residual risk"Declare an fmea and at least one failure_mode."
supply_mapsc_node blocks with role: of supplier, factory, warehouse, distributor or customer (anything else falls to the first column), and sc_link blocks (from, to, lead_time_days, cost_per_unit, mode). A link missing from or to is skipped without a message"Declare a supply_chain and at least two sc_node blocks."
rubric_gridcriterion blocks (name, weight, description) and level blocks (criterion, label, points, descriptor). Level columns are sorted by points, worst to best"Declare a rubric and at least one criterion."
clause_mapclause blocks (title, type, party, summary, section), optional party and agreement, and obligation blocks for the obligations strip. A clause whose party matches no party goes in an "Unassigned" column"Declare an agreement, parties, and at least one clause."

Messages you may see

MessageWhat it meansWhat to do
No view renderer named "x" — available: …The view names a renderer the Lab does not have. The checker also reports this as an errorCorrect the name; the checker's "Did you mean …?" usually has it
Add a view to draw itThe document compiles but declares no viewClick Add a view, use the Figures bench, or type a view line
Fix N errors to renderThe document has errors and nothing could be drawn from itClick Go to the first error
The "name" view couldn't be drawnThe renderer failed while drawing. Your source is fineSwitch to another view, or undo the last change to this one
A renderer's own explanation, such as "Add a survival block with one group per arm …"The blocks the figure is built from are missing, or the data cannot support the figureFollow the sentence; the renderer names the exact block or attribute it needs. The gallery card shows a working shape
The X could not be built from this document (…). Check that …Something in the document made the renderer stop; the message names what to checkFix the named attribute. The rest of the studio keeps working
A footnote saying a typed value disagrees with the computed oneYou transcribed a statistic that your own data do not giveCheck the transcription, or the data. The figure shows the computed value

Tips

  • Give every view a name and an argument when a document has more than one block of the same kind: view os_plot: km(os) rather than view : km.
  • Draw the forest plot and the funnel plot from one meta block. Both figures then always describe the same studies.
  • Use the Figures bench to learn a figure in a fresh document, then copy the blocks you need into your own. Starting from a worked example replaces whatever is open.
  • When a research figure footnotes a disagreement, read it before you submit. It is usually a transcription slip.
  • State the numbers that would otherwise default (likelihood and impact on threats; severity, occurrence and detection on failure modes; delta: on ablations).
  • Put a note with "Illustrative values" in its text into any document whose numbers are not real. Every view of it then says so.
  • To lay several figures out for a journal, compose them with panel rather than assembling exported images by hand; the letters, widths and alignment then update when your data change.

Limits and known constraints

  • There is no precision–recall view; pr_curve is an alias of roc.
  • prisma and consort draw the same figure; neither prints the name of the reporting standard in its header.
  • calibration and decision_curve analyse only the first series in their block.
  • forest pools by inverse variance only. Mantel–Haenszel, Peto and Bayesian pooling are declarable but not computed; the figure draws the nearest inverse-variance pool and labels it.
  • control_chart computes limits for I, p, u and c charts only. An x̄–S chart gets its centre line only.
  • km does not draw cumulative incidence under competing risks, does not print a hazard ratio, and does not print a log-rank p for a single arm.
  • panel cannot remove a child's duplicate axis or restyle a child's type.
  • rob_traffic_light and rob_summary_bar draw one instrument per figure: RoB 2, ROBINS-I, ROBINS-E, QUADAS-2 or ROBIS. AMSTAR 2 is drawn by appraisal_table.
  • gantt reads dates only in YYYY-MM-DD form.
  • The Insert flyout adds a view without an argument; add the argument by hand when the document has several candidate blocks.
  • Starting from a worked example replaces the open document's content and releases any data rows bound to it.

Troubleshooting

My Gantt chart shows fewer bars than tasks. A task is dropped unless both start: and end: are dates in YYYY-MM-DD form. Check the dates of the missing tasks.

The Kaplan–Meier view says there are no events. Every events: entry is 0, so the curve would claim 100% survival. Check that events are coded 1 and censorings 0, and that events: has one entry per entry in times:.

The raincloud refuses my group. It has mean: and sd: but no values:. A raincloud needs the raw observations. Add them, or draw the estimate with forest.

The risk-of-bias grid asks me to choose an instrument. Your document assesses studies with two tools. Draw one figure per tool, for example view rob_main: rob_traffic_light(rob2) and view rob_obs: rob_traffic_light(robins_i).

My multi-panel figure shows a placeholder in one cell. That child view failed or refuses to draw on its own. Open that view by itself to read its message, fix it, and the plate redraws.

The canvas says Example data — not real, but I replaced every number. The stamp follows the starter's "EXAMPLE text from a fictional …" comment line, not the numbers. Delete that line (and any other line that still contains those words).

I clicked Start a new document from this example and lost my work. Click Undo in the toast, or press ⌘Z. The previous content comes back.

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.