Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Bar chart

chart.bar

ProductionBounded custom (Class B)Deterministicstrictfastv1.0.0
No network

Overview

Pass category labels and one or more numeric series — we draw grouped or stacked bars in vertical or horizontal orientation. Defaults include canvas 800×400, grouped mode, and a visible legend. Too many categories for the canvas are refused rather than shrunk until the bars are unreadable. Do not use for ordered time series (use chart.line), part-of-whole shares, or weighted flows between stages (use chart.sankey). svg is a complete static, script-free chart. Mark highlight, the dotted guide, and the value panel are not in that SVG, and entry motion, focus, and updates stay inactive there. Pass the entire output.behavior.artifact unchanged to SquillifyChartRuntime.mount(container, artifact, options), then call the returned handle's replay() once to play the entry. A later value change uses update(nextArtifact, {intent}). Injecting svg directly leaves hover and motion off. Interaction is on by default for every host chart: after mount, pointer and keyboard focus open the value panel and the dotted guide. Set behavior.interaction.enabled to false to turn that off. motion.preset accepts only the family's entrance.

Hand-built bar SVG is inconsistent and hard to embed reliably. We emit identical, allowlist-checked markup every time and refuse overcrowded input instead of drawing unreadable bars.

Reliability

Identical input always produces the same bars, colours, and SVG. Declared failures: CHART_CAPACITY_EXCEEDED — trigger: too many categories or series for the canvas at the chosen size, bar mode, and density; retryable: no; unchanged input: will not succeed; next: follow the recovery intent in the error details. CHART_BEHAVIOR_CAPACITY_EXCEEDED — trigger: see the error details for this code; retryable: no; unchanged input: will not succeed; next: follow the recovery intent in the error details. CHART_DIMENSIONS_TOO_SMALL — trigger: see the error details for this code; retryable: no; unchanged input: will not succeed; next: follow the recovery intent in the error details. CHART_OUTPUT_TOO_LARGE — trigger: the inline SVG byte budget would be exceeded at the requested size and data density; retryable: no; unchanged input: will not succeed; next: follow the recovery intent in the error details. CHART_THEME_UNKNOWN — trigger: theme or surface names a visual language we do not register for this chart family; retryable: no; unchanged input: will not succeed; next: follow the recovery intent in the error details. CHART_UNSAFE_OUTPUT — trigger: the finished SVG failed our final safety re-validation (this is on us, not your data); retryable: no; unchanged input: will not succeed; next: contact support with the request id — retrying the same input will not help. CHART_OUTPUT_TOO_COMPLEX — trigger: the render hit a structural complexity ceiling (elements, depth, text volume, or path commands) separate from the byte budget; retryable: no; unchanged input: will not succeed; next: contact support with the request id — retrying the same input will not help.

Context footprint

Prefer descriptor.contractSections.recommendedRendering. Pass output.behavior.artifact unchanged to SquillifyChartRuntime.mount; resolve artifact.runtimeRequirement and every resourceRequirements item first. motionPlan.requiredRuntime is not a resolver input. A successful call costs 3 execution credits.

When to use it

When you need to compare values across a modest set of named categories.

When the x axis is ordered time, the data is a flow graph, or there are too many categories for the canvas.

Scope

Note
Categorical bar charts — grouped or stacked, vertical or horizontal — from category labels and one or more numeric series.

Non-goals

  • Ordered trends over time (use chart.line)
  • Part-of-whole shares (use a pie or donut chart)
  • Weighted flows between stages (use chart.sankey)

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

generationimage-processing

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call3 credits

File handling

Accepts file_refProduces file_refMax input195.3 KB

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
categoriesarrayYesCategory labels along the categorical axis (required). One string per bar group; order defines left-to-right or bottom-to-top placement depending on orientation.
seriesarrayYesNumeric series (required). Objects with id (default series-1, series-2, …), name (default "Series N", required once there are two or more series), visible (default true) and exactly one of values, points or ranges. values holds numbers or null; points holds {value, label, metadata} or null; ranges holds {start, end, label, metadata} or null and requires variation 'range'. Whichever you use carries exactly one entry per category, and a null entry means a value you do not have — see dataPolicy.missingValues.
orientationstringNoBar orientation: vertical or horizontal (default vertical).
variationstringNoPoint shape: 'standard' (default) reads values or points and measures each bar from zero; 'range' reads ranges and draws each bar between the two endpoints you supplied, on a domain that need not include zero. Range accepts mode 'grouped' only, and cannot be combined with category reduction.
modestringNoHow several visible series relate (default grouped). 'grouped' places them side by side from zero. 'stacked' accumulates them, positives and negatives away from zero on their own side. 'normalized' stacks each sign side as a share of its own total, so a positive side fills 100% and a negative side -100%; a side with no total contributes no segment and a category with neither follows dataPolicy.normalizedZeroTotal. 'diverging' keeps the raw values and centres the axis on zero so the two directions are comparable. Normalized and diverging are standard variation only.
seriesOrderobjectNoPresentation order, which never changes series identity or palette slot. seriesOrder.group lists every visible series id exactly once and orders grouped or diverging bars within a category; seriesOrder.stack does the same from the baseline outwards for stacked or normalized bars. Omit them and series are drawn in input order. An unknown, repeated, hidden or omitted visible id is rejected.
dataPolicyobjectNoWhat to do with data that cannot simply be drawn. dataPolicy.missingValues treats a null point as 'gap' (default — that bar is not drawn, no other bar moves), 'zero' (drawn as a measured zero and reported) or 'reject' (refused, naming the points). dataPolicy.normalizedZeroTotal ('gap' by default, or 'reject') covers a normalized category whose totals are zero. dataPolicy.categoryReduction keeps the best-ranked categories and aggregates the rest into one: .keep (required, at least 1) is how many survive as themselves, .by ranks them on 'sum' (default), 'average', 'minimum', 'maximum' or 'series', .series names the ranked series and is required by — and accepted only with — by 'series', .direction keeps the 'highest' (default) or 'lowest' of that ranking, .other (default true) aggregates the remainder instead of dropping it, .otherLabel is the aggregate's label (default "Other") and .otherPosition places it 'last' (default) or 'first' after sorting. Omit the object and excess density is refused, not quietly reduced.
widthintegerNoCanvas width in pixels, 100..1600 (optional; default 800). Outside that range the request is refused as invalid input rather than clamped. The ceiling is the size a chart is read at — a full-HD dashboard or a report page; beyond it the canvas stops being what limits how much fits, and type sized for the canvas is illegible once the export is displayed smaller. It applies per side, so a tall portrait canvas for a long horizontal ranking is allowed.
heightintegerNoCanvas height in pixels, 100..1600 (optional; default 400). Outside that range the request is refused as invalid input rather than clamped. The ceiling is the size a chart is read at — a full-HD dashboard or a report page; beyond it the canvas stops being what limits how much fits, and type sized for the canvas is illegible once the export is displayed smaller. It applies per side, so a tall portrait canvas for a long horizontal ranking is allowed.
themestringNoVisual language: basic, modern or squillify (optional; default squillify). An unregistered value is rejected with the registered names listed — we never substitute silently.
surfacestringNoSurface the theme renders on: dark or light (optional; default light).
densitystringNoHow tightly the chrome is packed: compact, standard or spacious (optional; default standard). Density scales spacing only — it never lowers a legibility minimum.
visualProfilestringNoWhat the SVG promises about the host font: portable or certified (optional; default portable). The default is layout-deterministic and tolerates substitution; certified refuses text the certified metrics cannot fully measure.
categoryAxisobjectNoThe axis the bars are named along. categoryAxis.visible, .title, .position (top/bottom when vertical, left/right when horizontal), .reversed, .sort ({by 'input' (default), 'label', 'series', 'sum', 'average', 'minimum', 'maximum' or 'custom'; direction 'ascending' (default) or 'descending'; series, required by — and accepted only with — by 'series'; order, the category ids required by — and accepted only with — by 'custom'}), .labels ({visible; rotation -90..90 or 'auto' (default); showEvery 1 or more, or 'auto' (default); maxLines 1..5 (default 2); overflow 'auto' (default), 'wrap', 'truncate', 'hide' or 'reject'}) and .ticks/.grid ({visible}). Omit it and the axis is drawn below a vertical chart in input order, with labels that wrap to two lines and adapt when space runs short. overflow 'auto' wraps, then uses your shortLabel, then thins the labels — it never reorders or drops a bar, and every hidden or substituted label is reported.
valueAxisobjectNoThe axis the bars are measured against. valueAxis.visible, .title, .position, .scale ({type, minimum, maximum, includeZero, nice, reversed}), .ticks ({visible, mode auto/count/interval/values, count 2..20, interval, values, minorVisible}), .grid ({visible, minorVisible}), .baseline ({visible, default true}) and .format ({style, notation, currency, unit, minimumFractionDigits, maximumFractionDigits, useGrouping, prefix, suffix}). Omit it and the axis is drawn on the left of a vertical chart with a zero-based domain, automatic ticks, major grid lines and two-decimal numbers. A bound that would cut a bar off is refused, not clipped. .baseline is the zero line the bars are measured from and has its own switch on purpose: valueAxis.visible false removes the ticks, labels, grid and title but leaves it standing, because when your values straddle zero it floats inside the plot instead of sitting under the axis. Set valueAxis.baseline.visible false to drop it, which is what a chart stripped to its marks and its data labels wants.
barsobjectNoBar thickness and spacing. bars.width is 'auto' (default — bars fill their band) or a 0.05..1 share of the band, centred. bars.categoryGap (0..0.9, default 0.2) is the empty share between categories and bars.groupGap (0..0.9, default 0.08) the empty share between the bars of one grouped category. bars.minimumWidth (1..200 px) is the narrowest bar you accept: ask for more than fits and the request is refused with the width it would have had, never silently thinned. bars.maximumWidth (1..500 px) caps a needlessly wide bar. Fill and stroke belong to style, not here.
dataLabelsobjectNoNumbers on the bars. Off unless dataLabels.visible. content: 'value' (default), 'percent', 'valueAndPercent', 'category', 'series', 'pointLabel', 'stackTotal'; the percent forms need mode 'normalized' and stackTotal needs a stack. position: 'auto' (default), 'insideStart', 'insideCenter', 'insideEnd', 'outsideEnd'. format is the number-format object, defaulting to valueAxis.format. showZero (default false) and showNegative (default true) choose which bars are labelled. overflow: 'hide' (default), 'outside', 'reject'.
localizationobjectNolocalization.locale (a supported BCP 47 tag, default 'en') selects the frozen number-format table, so the same request formats identically on every host. .otherLabel names a reduced category; .direction accepts 'auto' or 'leftToRight'. Omit it and numbers are written the 'en' way, with a comma between thousands and a dot before decimals.
titlestringNoHeading drawn above the plot (optional; at most 1024 code points). Omit it and the chart renders untitled — we never invent a title from your data. One code point past that ceiling is refused as TOOL_INPUT_INVALID.
subtitlestringNoSecond line under the title, useful for the period covered or the unit (optional; at most 1024 code points). Omit it and no second line is drawn.
legendobjectNoThe series key. legend.visible defaults to true for several series, false for one; with several it may only be false when identity stays visible another way (dataLabels.content 'series'), else refused. legend.title heads the items. position: 'auto' (default), 'top', 'right', 'bottom', 'left'. orientation: 'auto' (default), 'horizontal', 'vertical'. alignment: 'start' (default), 'center', 'end'. order: 'series' (default), 'reverse', or an array naming every visible series id once. wrap (default true) allows extra rows.
referenceLinesarrayNoValue-axis marks to read the bars against. Each entry: value (required, finite, and inside the drawn domain or the render is refused), label, labelPosition ('auto' default, 'start', 'center', 'end'), layer ('behind' default, 'front'), meaning ('reference' default, 'target', 'warning', 'critical', published as data-sq-meaning). Omitted draws none; at most 24 lines and bands together.
referenceBandsarrayNoShaded value ranges. Each entry: from and to (both required and finite, from below to, both inside the drawn domain or the render is refused), label, meaning ('reference' default, 'target', 'warning', 'critical'). Bands are drawn behind the bars. Omitted draws none; at most 24 lines and bands together.
annotationsarrayNoNotes anchored to the data, not to canvas coordinates. Each entry: text (required, non-blank), category (required, an existing category id), series (optional, a visible series id; omitted anchors the whole group), position ('auto' default, 'above', 'below', 'before', 'after', 'inside'), connector (defaults true unless position is 'inside'). A note that cannot be placed is refused with CHART_LABEL_CAPACITY_EXCEEDED. Omitted draws none.
accessibilityobjectNoWhat a reader who cannot see the chart is told. accessibility.title is the accessible name, defaulting to the visible title and then to a generated one. accessibility.description is your business context, placed ahead of the generated data summary and never replacing it. Each is limited to 256 code points, and both share the summary's 1000-character budget: a long context makes the generated summary step down to a coarser rung. accessibility.patterns (default false) draws each series with a redundant texture as well as its colour, so the series stay separable in greyscale or with a colour-vision deficiency; it also satisfies the rule that several series may not be told apart by colour alone, which is what lets legend.visible be false on a multi-series chart. There are 8 distinct motifs, so beyond that many visible series the legend or series data labels must carry the identity. Omitted adds no context and no textures.
layoutobjectNoSpace around the chart and what to do when there is not enough. layout.margin is 'auto' (default), a whole number of pixels, or an object of top, right, bottom and left, each 0..1000. layout.plotPadding is a number or the same four-sided object, each 0..200, and defaults to the design profile. layout.insufficientSpace is 'reject' (default) or 'hideOptionalLabels': 'reject' refuses a canvas too small for the requested chrome with CHART_DIMENSIONS_TOO_SMALL rather than returning an unreadable chart, and 'hideOptionalLabels' drops the category labels to make it fit, reporting them in BAR_OPTIONAL_LABELS_HIDDEN. Neither ever hides the title, the value axis, the legend or the bars.
captionstringNoReading note printed under the chart. Omitted or empty reserves no space.
sourcestringNoData attribution printed under the caption. Omitted or empty reserves no space.
periodstringNoCovered period printed under the source. Omitted or empty reserves no space.
styleobjectNoOptional bounded paint and typography styling; omit it to use the selected theme defaults. text.size is expressed in normalized design pixels at an 800-pixel reference width, so equivalent roles match at equal CSS width. It never changes data or accessibility. 'contract' selects the published semantics. 'tokens' sets design tokens; 'rules' applies typed properties to a role and optional series/category facets; 'palette' accepts a digest-checked palette; 'css' is a bounded post-layout stylesheet. The styleCapabilities section publishes this family's accepted roles, properties and copyable examples. For Bar, target one mark with role 'bar' plus seriesIndex and categoryIndex; categoryIndex alone targets that category across series. A minimal rule is {"target":{"role":"bar"},"set":{"paint.fill":"#2563eb"}}. Unsupported typed rules are refused; unsupported CSS is dropped and reported. Do not discover the grammar through trial calls: style validation failures are currently billable. Before calling, read this contract's styleSurface and styleCapabilities sections for the complete rule shape, accepted roles and properties, limits, and copyable examples.
behaviorobjectNoOptional host-behavior request; omit it for canonical static SVG. behavior.motion.preset is only 'enter_grow' (default) or legacy 'enter'. 'enter_grow' is the entrance replay() plays after mount. 'enter' is a legacy opacity fade in the SVG. behavior.interaction defaults to enabled with capability 'focus_compare': hover, focus, the dotted guide and the value panel. Set enabled to false to turn interaction off. update_values and reorder_categories are update() intents, not presets. svg is a complete static, script-free chart. Mark highlight, the dotted guide, and the value panel are not in that SVG, and entry motion, focus, and updates stay inactive there. Pass the entire output.behavior.artifact unchanged to SquillifyChartRuntime.mount(container, artifact, options), then call the returned handle's replay() once to play the entry. A later value change uses update(nextArtifact, {intent}). Injecting svg directly leaves hover and motion off. Interaction is on by default for every host chart: after mount, pointer and keyboard focus open the value panel and the dotted guide. Set behavior.interaction.enabled to false to turn that off. motion.preset accepts only the family's entrance.
outputobjectNoOutput scoping. output.idNamespace ([a-z][a-z0-9-]{0,31}) is prefixed onto every generated element id so several charts can share one host document without colliding; omit it for a standalone chart. An invalid value is rejected, never corrected. output.includeTransformationDetails (default false) adds the item-level transformationDetails object; transformationSummary is always returned and cannot be switched off.

Output schema

FieldTypeRequiredDescription
svgstringYesAllowlist-checked script-free SVG. svg is a complete static, script-free chart. Mark highlight, the dotted guide, and the value panel are not in that SVG, and entry motion, focus, and updates stay inactive there. Pass the entire output.behavior.artifact unchanged to SquillifyChartRuntime.mount(container, artifact, options), then call the returned handle's replay() once to play the entry. A later value change uses update(nextArtifact, {intent}). Injecting svg directly leaves hover and motion off. Interaction is on by default for every host chart: after mount, pointer and keyboard focus open the value panel and the dotted guide. Set behavior.interaction.enabled to false to turn that off. motion.preset accepts only the family's entrance.
widthintegerYesRendered width in pixels.
heightintegerYesRendered height in pixels.
viewBoxstringYesSVG viewBox string (for example "0 0 800 400").
behaviorobjectNoPresent for an explicit motion request. Reports the selected preset, reduced-motion policy and static-equivalent final state. svg is a complete static, script-free chart. Mark highlight, the dotted guide, and the value panel are not in that SVG, and entry motion, focus, and updates stay inactive there. Pass the entire output.behavior.artifact unchanged to SquillifyChartRuntime.mount(container, artifact, options), then call the returned handle's replay() once to play the entry. A later value change uses update(nextArtifact, {intent}). Injecting svg directly leaves hover and motion off. Interaction is on by default for every host chart: after mount, pointer and keyboard focus open the value panel and the dotted guide. Set behavior.interaction.enabled to false to turn that off. motion.preset accepts only the family's entrance.
styleReportobjectNoPresent only when a 'style' input was supplied. Reports tokensApplied, rulesApplied, typedRulesApplied, typedAssignmentsApplied, rulesDropped, declarationsDropped and, when anything was dropped, a bounded list of reasons — so a stylesheet that was modified never looks like one that was applied whole.
warningsarrayNoPresent when the render succeeded with a known degradation. Each entry is an object with a stable code, a message and details. Every chart can emit FONT_SUBSTITUTION_POSSIBLE under visualProfile 'portable', FONT_GLYPH_UNMEASURED when a code point falls outside the certified metrics, and CHART_STYLE_PARTIALLY_APPLIED when part of your styling was dropped — styleReport then names which part and why. Codes are stable for agent routing. Adaptations to your data or labels add BAR_MISSING_AS_ZERO, BAR_NORMALIZED_CATEGORY_EMPTY, BAR_CATEGORIES_REDUCED, BAR_CATEGORY_LABELS_ADAPTED, BAR_DATA_LABELS_HIDDEN or BAR_OPTIONAL_LABELS_HIDDEN, each naming the categories, points or counts it affected.
accessibilityobjectYesAlways present. 'title' is the accessible name, 'description' the generated data summary with any caller context ahead of it, and 'detail' the rung it reached: 'full' names every value, 'grouped' gives per-series extent and total, 'shape' the chart-level extremes. The rung is chosen as the richest that fits a 1000-character budget, so a bigger chart returns a coarser summary rather than a truncated one.
renderSummaryobjectYesAlways present. What was actually drawn: variation, orientation, mode, categoryCount (after any reduction), seriesCount (visible only), visibleBarCount and missingPointCount. Scalars only, so the object does not grow with the data.
transformationSummaryobjectYesAlways present. States whether the picture differs from the data you sent — 'applied', the operations that ran, and how many categories, points and labels they touched. 'applied: false' is the common answer and is the point: a faithful render says so rather than staying silent.
transformationDetailsobjectNoPresent only when 'output.includeTransformationDetails' is true. The item-level version of the summary, in your own category and series IDs. Bounded: a request whose details would exceed the response limit is refused rather than truncated.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"skillKey":"chart.bar","input":{"categories":["Q1","Q2"],"series":[{"name":"Revenue","values":[120,150]}],"title":"Quarterly revenue vs cost","behavior":{"motion":{"enabled":true,"preset":"enter_grow","reducedMotion":"respect"}}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("chart.bar", {"categories":["Q1","Q2","Q3","Q4"],"title":"Quarterly revenue vs cost","subtitle":"in thousands (USD)","density":"compact","surface":"light","series":[{"values":[120,150,90,210],"name":"Revenue"},{"values":[80,95,70,130],"name":"Cost"}]});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
CHART_CAPACITY_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
CHART_BEHAVIOR_CAPACITY_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
CHART_DIMENSIONS_TOO_SMALL429NoA size, quota, rate, or time limit was exceeded.
CHART_OUTPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
CHART_THEME_UNKNOWN400NoThe request payload failed this skill's input validation.
CHART_UNSAFE_OUTPUT500NoThe skill encountered an unexpected execution failure.
CHART_OUTPUT_TOO_COMPLEX500NoThe skill encountered an unexpected execution failure.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Ordered trends over time (use chart.line)
  • Part-of-whole shares (use a pie or donut chart)
  • Weighted flows between stages (use chart.sankey)
  • Continuous time series (use chart.line)
  • Hundreds of categories — we refuse those
  • Drill-down or brushing

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "chart.bar",
  "input": {
    "categories": [
      "Q1",
      "Q2",
      "Q3",
      "Q4"
    ],
    "title": "Quarterly revenue vs cost",
    "subtitle": "in thousands (USD)",
    "density": "compact",
    "surface": "light",
    "series": [
      {
        "values": [
          120,
          150,
          90,
          210
        ],
        "name": "Revenue"
      },
      {
        "values": [
          80,
          95,
          70,
          130
        ],
        "name": "Cost"
      }
    ]
  }
}

Examples

Quarterly revenue vs cost at compact density

Inputjson
{
  "categories": [
    "Q1",
    "Q2",
    "Q3",
    "Q4"
  ],
  "title": "Quarterly revenue vs cost",
  "subtitle": "in thousands (USD)",
  "density": "compact",
  "surface": "light",
  "series": [
    {
      "values": [
        120,
        150,
        90,
        210
      ],
      "name": "Revenue"
    },
    {
      "values": [
        80,
        95,
        70,
        130
      ],
      "name": "Cost"
    }
  ]
}
Expected outputjson
{
  "accessibility": {
    "title": "Quarterly revenue vs cost",
    "detail": "full",
    "description": "Bar chart. 2 series across 4 categories, grouped, vertical. Revenue: Q1 120, Q2 150, Q3 90, Q4 210. Cost: Q1 80, Q2 95, Q3 70, Q4 130. All values are listed."
  },
  "transformationSummary": {
    "applied": false,
    "operations": [],
    "affectedCategoryCount": 0,
    "affectedPointCount": 0,
    "affectedLabelCount": 0
  },
  "viewBox": "0 0 800 400",
  "height": 400,
  "svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"800\" height=\"400\" viewBox=\"0 0 800 400\" role=\"img\" class=\"sq-chart sq-chart--bar sq-family--cartesian sq-theme--squillify sq-surface--light sq-density--compact\" data-sq-style-contract=\"CHART_STYLE@1\" data-sq-chart=\"bar\" data-sq-family=\"cartesian\" data-sq-theme=\"squillify\" data-sq-theme-version=\"1\" data-sq-surface=\"light\" data-sq-density=\"compact\" data-sq-a11y-detail=\"full\" aria-labelledby=\"sq-baa1904c6d7b-title-7 sq-baa1904c6d7b-desc-8\"><title id=\"sq-baa1904c6d7b-title-7\">Quarterly revenue vs cost</title><desc id=\"sq-baa1904c6d7b-desc-8\">Bar chart. 2 series across 4 categories, grouped, vertical. Revenue: Q1 120, Q2 150, Q3 90, Q4 210. Cost: Q1 80, Q2 95, Q3 70, Q4 130. All values are listed.</desc><style>.sq-chart{--sq-chart-axis:#c9d1df;--sq-chart-font-family:'Squillify Mono', 'IBM Plex Mono', monospace;--sq-chart-grid:#d8dee9;--sq-chart-surface:#ffffff;--sq-chart-text-muted:#667085;--sq-chart-text-primary:#101828;--sq-series-1:#2563eb;--sq-series-2:#6d5ce7;--sq-series-3:#168a5b;--sq-series-4:#c45412;--sq-series-5:#d92d20;--sq-series-6:#667085;font-family:var(--sq-chart-font-family);font-weight:500;}.sq-chart .sq-background{fill:var(--sq-chart-surface);}.sq-chart .sq-grid{stroke:var(--sq-chart-grid);}.sq-chart .sq-axis{stroke:var(--sq-chart-axis);}.sq-chart .sq-title{fill:var(--sq-chart-text-primary);}.sq-chart .sq-subtitle{fill:var(--sq-chart-text-muted);}.sq-chart .sq-tick-label{fill:var(--sq-chart-text-muted);}.sq-chart .sq-category-label{fill:var(--sq-chart-text-muted);}.sq-chart .sq-legend-label{fill:var(--sq-chart-text-primary);}</style><defs><linearGradient id=\"sq-baa1904c6d7b-fh-6\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#f0f5fe\"/><stop offset=\"0.54\" stop-color=\"#ffffff\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-0\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#6f9bff\"/><stop offset=\"1\" stop-color=\"#c9d8ff\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-1\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#a99cf8\"/><stop offset=\"1\" stop-color=\"#ded9ff\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-2\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#54bc8b\"/><stop offset=\"1\" stop-color=\"#c8ebda\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-3\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#f09a5b\"/><stop offset=\"1\" stop-color=\"#f7d4ba\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-4\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#426cad\"/><stop offset=\"1\" stop-color=\"#b7c8e3\"/></linearGradient><linearGradient id=\"sq-baa1904c6d7b-gradient-5\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#98a2b3\"/><stop offset=\"1\" stop-color=\"#e4e7ec\"/></linearGradient></defs><rect x=\"0\" y=\"0\" width=\"800\" height=\"400\" fill=\"#ffffff\" class=\"sq-background\" data-sq-role=\"background\"/><g class=\"sq-plot\" data-sq-role=\"plot\"><rect x=\"0\" y=\"0\" width=\"800\" height=\"74\" fill=\"url(#sq-baa1904c6d7b-fh-6)\" class=\"sq-brand-band\"/><rect x=\"0\" y=\"74\" width=\"800\" height=\"326\" fill=\"#f8fafd\" class=\"sq-plot\" data-sq-role=\"plot\"/><line x1=\"0\" y1=\"74\" x2=\"800\" y2=\"74\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-card-frame\"/><text x=\"8\" y=\"16\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"600\" letter-spacing=\"1.2\" textLength=\"65\" lengthAdjust=\"spacing\" fill=\"#2563eb\" class=\"sq-caption\" data-sq-role=\"caption\">BAR CHART</text><text x=\"8\" y=\"39\" font-size=\"16\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"600\" letter-spacing=\"-0.32\" textLength=\"234\" lengthAdjust=\"spacing\" fill=\"#101828\" class=\"sq-title\" data-sq-role=\"title\">Quarterly revenue vs cost</text><text x=\"8\" y=\"54\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"500\" textLength=\"109\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-subtitle\" data-sq-role=\"subtitle\">in thousands (USD)</text><g class=\"sq-legend\" data-sq-role=\"legend\"><g class=\"sq-legend-item\"><g transform=\"translate(687.4 26.8) rotate(45)\"><rect x=\"-3.4\" y=\"-3.4\" width=\"6.8\" height=\"6.8\" fill=\"#6f9bff\" stroke=\"#2563eb\" stroke-width=\"0.8\" class=\"sq-legend-swatch\" data-sq-role=\"legend-swatch\" data-sq-series-index=\"0\"/></g><text x=\"698\" y=\"30.2\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"500\" textLength=\"43\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-legend-label\" data-sq-role=\"legend-label\" data-sq-series-index=\"0\">Revenue</text></g><g class=\"sq-legend-item\"><g transform=\"translate(756.4 26.8) rotate(45)\"><rect x=\"-3.4\" y=\"-3.4\" width=\"6.8\" height=\"6.8\" fill=\"#a99cf8\" stroke=\"#6d5ce7\" stroke-width=\"0.8\" class=\"sq-legend-swatch\" data-sq-role=\"legend-swatch\" data-sq-series-index=\"1\"/></g><text x=\"767\" y=\"30.2\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"500\" textLength=\"25\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-legend-label\" data-sq-role=\"legend-label\" data-sq-series-index=\"1\">Cost</text></g></g><rect x=\"0.5\" y=\"0.5\" width=\"799\" height=\"399\" fill=\"none\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-card-frame\"/><line x1=\"37\" y1=\"368\" x2=\"792\" y2=\"368\" stroke=\"#d8dee9\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"37\" y1=\"273.667\" x2=\"792\" y2=\"273.667\" stroke=\"#d8dee9\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"37\" y1=\"179.333\" x2=\"792\" y2=\"179.333\" stroke=\"#d8dee9\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"37\" y1=\"85\" x2=\"792\" y2=\"85\" stroke=\"#d8dee9\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"33\" y1=\"368\" x2=\"37\" y2=\"368\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"33\" y1=\"273.667\" x2=\"37\" y2=\"273.667\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"33\" y1=\"179.333\" x2=\"37\" y2=\"179.333\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"33\" y1=\"85\" x2=\"37\" y2=\"85\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><text x=\"32.5\" y=\"371.5\" font-size=\"10\" text-anchor=\"end\" textLength=\"24\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">0.00</text><text x=\"32.5\" y=\"277.167\" font-size=\"10\" text-anchor=\"end\" textLength=\"36\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">100.00</text><text x=\"32.5\" y=\"182.833\" font-size=\"10\" text-anchor=\"end\" textLength=\"36\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">200.00</text><text x=\"32.5\" y=\"88.5\" font-size=\"10\" text-anchor=\"end\" textLength=\"36\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">300.00</text><rect x=\"87.625\" y=\"254.8\" width=\"12\" height=\"113.2\" fill=\"url(#sq-baa1904c6d7b-gradient-0)\" stroke=\"#2563eb\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-df8fe9d904ca2211\" data-sq-series-index=\"0\" data-sq-category-index=\"0\" data-sq-palette-index=\"0\"/><rect x=\"163.125\" y=\"292.533\" width=\"12\" height=\"75.467\" fill=\"url(#sq-baa1904c6d7b-gradient-1)\" stroke=\"#6d5ce7\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-369690d06de7404a\" data-sq-series-index=\"1\" data-sq-category-index=\"0\" data-sq-palette-index=\"1\"/><rect x=\"276.375\" y=\"226.5\" width=\"12\" height=\"141.5\" fill=\"url(#sq-baa1904c6d7b-gradient-0)\" stroke=\"#2563eb\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-f4f9e0127f5a61a5\" data-sq-series-index=\"0\" data-sq-category-index=\"1\" data-sq-palette-index=\"0\"/><rect x=\"351.875\" y=\"278.383\" width=\"12\" height=\"89.617\" fill=\"url(#sq-baa1904c6d7b-gradient-1)\" stroke=\"#6d5ce7\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-bfae00328cc3aafe\" data-sq-series-index=\"1\" data-sq-category-index=\"1\" data-sq-palette-index=\"1\"/><rect x=\"465.125\" y=\"283.1\" width=\"12\" height=\"84.9\" fill=\"url(#sq-baa1904c6d7b-gradient-0)\" stroke=\"#2563eb\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-eb54878b687af9b9\" data-sq-series-index=\"0\" data-sq-category-index=\"2\" data-sq-palette-index=\"0\"/><rect x=\"540.625\" y=\"301.967\" width=\"12\" height=\"66.033\" fill=\"url(#sq-baa1904c6d7b-gradient-1)\" stroke=\"#6d5ce7\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-c2a515fdf6aae525\" data-sq-series-index=\"1\" data-sq-category-index=\"2\" data-sq-palette-index=\"1\"/><rect x=\"653.875\" y=\"169.9\" width=\"12\" height=\"198.1\" fill=\"url(#sq-baa1904c6d7b-gradient-0)\" stroke=\"#2563eb\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-4849b4bf48c4235d\" data-sq-series-index=\"0\" data-sq-category-index=\"3\" data-sq-palette-index=\"0\"/><rect x=\"729.375\" y=\"245.367\" width=\"12\" height=\"122.633\" fill=\"url(#sq-baa1904c6d7b-gradient-1)\" stroke=\"#6d5ce7\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-5d2bf12bf75dc5dc\" data-sq-series-index=\"1\" data-sq-category-index=\"3\" data-sq-palette-index=\"1\"/><line x1=\"37\" y1=\"368\" x2=\"792\" y2=\"368\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-axis\" data-sq-role=\"axis-line\"/><line x1=\"131.375\" y1=\"368\" x2=\"131.375\" y2=\"372\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"320.125\" y1=\"368\" x2=\"320.125\" y2=\"372\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"508.875\" y1=\"368\" x2=\"508.875\" y2=\"372\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"697.625\" y1=\"368\" x2=\"697.625\" y2=\"372\" stroke=\"#c9d1df\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><text x=\"131.375\" y=\"382.5\" font-size=\"10\" text-anchor=\"middle\" textLength=\"12\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"0\">Q1</text><text x=\"320.125\" y=\"382.5\" font-size=\"10\" text-anchor=\"middle\" textLength=\"12\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"1\">Q2</text><text x=\"508.875\" y=\"382.5\" font-size=\"10\" text-anchor=\"middle\" textLength=\"12\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"2\">Q3</text><text x=\"697.625\" y=\"382.5\" font-size=\"10\" text-anchor=\"middle\" textLength=\"12\" lengthAdjust=\"spacing\" fill=\"#667085\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"3\">Q4</text></g></svg>",
  "width": 800,
  "renderSummary": {
    "variation": "standard",
    "orientation": "vertical",
    "mode": "grouped",
    "categoryCount": 4,
    "seriesCount": 2,
    "visibleBarCount": 8,
    "missingPointCount": 0
  }
}

Stacked horizontal bars on a dark surface

Inputjson
{
  "categories": [
    "Jan",
    "Feb",
    "Mar"
  ],
  "orientation": "horizontal",
  "title": "Monthly units by product",
  "mode": "stacked",
  "surface": "dark",
  "series": [
    {
      "values": [
        40,
        55,
        48
      ],
      "name": "Product A"
    },
    {
      "values": [
        25,
        30,
        35
      ],
      "name": "Product B"
    }
  ]
}
Expected outputjson
{
  "accessibility": {
    "title": "Monthly units by product",
    "detail": "full",
    "description": "Bar chart. 2 series across 3 categories, stacked, horizontal. Product A: Jan 40, Feb 55, Mar 48. Product B: Jan 25, Feb 30, Mar 35. All values are listed."
  },
  "transformationSummary": {
    "applied": false,
    "operations": [],
    "affectedCategoryCount": 0,
    "affectedPointCount": 0,
    "affectedLabelCount": 0
  },
  "viewBox": "0 0 800 400",
  "height": 400,
  "svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"800\" height=\"400\" viewBox=\"0 0 800 400\" role=\"img\" class=\"sq-chart sq-chart--bar sq-family--cartesian sq-theme--squillify sq-surface--dark sq-density--standard\" data-sq-style-contract=\"CHART_STYLE@1\" data-sq-chart=\"bar\" data-sq-family=\"cartesian\" data-sq-theme=\"squillify\" data-sq-theme-version=\"1\" data-sq-surface=\"dark\" data-sq-density=\"standard\" data-sq-a11y-detail=\"full\" aria-labelledby=\"sq-120410e5d0ec-title-7 sq-120410e5d0ec-desc-8\"><title id=\"sq-120410e5d0ec-title-7\">Monthly units by product</title><desc id=\"sq-120410e5d0ec-desc-8\">Bar chart. 2 series across 3 categories, stacked, horizontal. Product A: Jan 40, Feb 55, Mar 48. Product B: Jan 25, Feb 30, Mar 35. All values are listed.</desc><style>.sq-chart{--sq-chart-axis:#475467;--sq-chart-font-family:'Squillify Mono', 'IBM Plex Mono', monospace;--sq-chart-grid:#344054;--sq-chart-surface:#101828;--sq-chart-text-muted:#aab4c5;--sq-chart-text-primary:#f7f9fc;--sq-series-1:#79a2ff;--sq-series-2:#b6a8ff;--sq-series-3:#5ed5a0;--sq-series-4:#ffad71;--sq-series-5:#f87171;--sq-series-6:#aab4c5;font-family:var(--sq-chart-font-family);font-weight:500;}.sq-chart .sq-background{fill:var(--sq-chart-surface);}.sq-chart .sq-grid{stroke:var(--sq-chart-grid);}.sq-chart .sq-axis{stroke:var(--sq-chart-axis);}.sq-chart .sq-title{fill:var(--sq-chart-text-primary);}.sq-chart .sq-tick-label{fill:var(--sq-chart-text-muted);}.sq-chart .sq-category-label{fill:var(--sq-chart-text-muted);}.sq-chart .sq-legend-label{fill:var(--sq-chart-text-primary);}</style><defs><linearGradient id=\"sq-120410e5d0ec-fh-6\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#172237\"/><stop offset=\"0.54\" stop-color=\"#101828\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-0\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#4779ec\"/><stop offset=\"1\" stop-color=\"#1d386f\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-1\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#7b6ddb\"/><stop offset=\"1\" stop-color=\"#322b68\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-2\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#27966a\"/><stop offset=\"1\" stop-color=\"#153e32\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-3\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#c66b2e\"/><stop offset=\"1\" stop-color=\"#512f22\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-4\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#476ea8\"/><stop offset=\"1\" stop-color=\"#243650\"/></linearGradient><linearGradient id=\"sq-120410e5d0ec-gradient-5\" gradientUnits=\"objectBoundingBox\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#667085\"/><stop offset=\"1\" stop-color=\"#344054\"/></linearGradient></defs><rect x=\"0\" y=\"0\" width=\"800\" height=\"400\" fill=\"#101828\" class=\"sq-background\" data-sq-role=\"background\"/><g class=\"sq-plot\" data-sq-role=\"plot\"><rect x=\"0\" y=\"0\" width=\"800\" height=\"60\" fill=\"url(#sq-120410e5d0ec-fh-6)\" class=\"sq-brand-band\"/><rect x=\"0\" y=\"60\" width=\"800\" height=\"340\" fill=\"#151f33\" class=\"sq-plot\" data-sq-role=\"plot\"/><line x1=\"0\" y1=\"60\" x2=\"800\" y2=\"60\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-card-frame\"/><text x=\"12\" y=\"16\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"600\" letter-spacing=\"1.2\" textLength=\"65\" lengthAdjust=\"spacing\" fill=\"#79a2ff\" class=\"sq-caption\" data-sq-role=\"caption\">BAR CHART</text><text x=\"12\" y=\"43\" font-size=\"16\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"600\" letter-spacing=\"-0.32\" textLength=\"225\" lengthAdjust=\"spacing\" fill=\"#f7f9fc\" class=\"sq-title\" data-sq-role=\"title\">Monthly units by product</text><g class=\"sq-legend\" data-sq-role=\"legend\"><g class=\"sq-legend-item\"><g transform=\"translate(641.4 29.8) rotate(45)\"><rect x=\"-3.4\" y=\"-3.4\" width=\"6.8\" height=\"6.8\" fill=\"#4779ec\" stroke=\"#79a2ff\" stroke-width=\"0.8\" class=\"sq-legend-swatch\" data-sq-role=\"legend-swatch\" data-sq-series-index=\"0\"/></g><text x=\"652\" y=\"33.2\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"500\" textLength=\"55\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-legend-label\" data-sq-role=\"legend-label\" data-sq-series-index=\"0\">Product A</text></g><g class=\"sq-legend-item\"><g transform=\"translate(722.4 29.8) rotate(45)\"><rect x=\"-3.4\" y=\"-3.4\" width=\"6.8\" height=\"6.8\" fill=\"#7b6ddb\" stroke=\"#b6a8ff\" stroke-width=\"0.8\" class=\"sq-legend-swatch\" data-sq-role=\"legend-swatch\" data-sq-series-index=\"1\"/></g><text x=\"733\" y=\"33.2\" font-size=\"10\" text-anchor=\"start\" font-family=\"&#39;Squillify Mono&#39;, &#39;IBM Plex Mono&#39;, monospace\" font-weight=\"500\" textLength=\"55\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-legend-label\" data-sq-role=\"legend-label\" data-sq-series-index=\"1\">Product B</text></g></g><rect x=\"0.5\" y=\"0.5\" width=\"799\" height=\"399\" fill=\"none\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-card-frame\"/><line x1=\"37\" y1=\"38.8\" x2=\"37\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"187.2\" y1=\"38.8\" x2=\"187.2\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"337.4\" y1=\"38.8\" x2=\"337.4\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"487.6\" y1=\"38.8\" x2=\"487.6\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"637.8\" y1=\"38.8\" x2=\"637.8\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"788\" y1=\"38.8\" x2=\"788\" y2=\"334\" stroke=\"#344054\" stroke-width=\"1\" stroke-dasharray=\"3 3\" stroke-linecap=\"butt\" class=\"sq-grid\" data-sq-role=\"grid-line\"/><line x1=\"37\" y1=\"334\" x2=\"37\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"187.2\" y1=\"334\" x2=\"187.2\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"337.4\" y1=\"334\" x2=\"337.4\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"487.6\" y1=\"334\" x2=\"487.6\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"637.8\" y1=\"334\" x2=\"637.8\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"788\" y1=\"334\" x2=\"788\" y2=\"338\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><text x=\"37\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"24\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">0.00</text><text x=\"187.2\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"30\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">20.00</text><text x=\"337.4\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"30\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">40.00</text><text x=\"487.6\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"30\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">60.00</text><text x=\"637.8\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"30\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">80.00</text><text x=\"788\" y=\"350\" font-size=\"10\" text-anchor=\"middle\" textLength=\"36\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-tick-label\" data-sq-role=\"tick-label\">100.00</text><rect x=\"37\" y=\"76\" width=\"300.4\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-0)\" stroke=\"#79a2ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-5b86198fc083ff2e\" data-sq-series-index=\"0\" data-sq-category-index=\"0\" data-sq-palette-index=\"0\"/><rect x=\"337.4\" y=\"76\" width=\"187.75\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-1)\" stroke=\"#b6a8ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-5b52e9508649b340\" data-sq-series-index=\"1\" data-sq-category-index=\"0\" data-sq-palette-index=\"1\"/><rect x=\"37\" y=\"174.4\" width=\"413.05\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-0)\" stroke=\"#79a2ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-d2eedfebb26c9b31\" data-sq-series-index=\"0\" data-sq-category-index=\"1\" data-sq-palette-index=\"0\"/><rect x=\"450.05\" y=\"174.4\" width=\"225.3\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-1)\" stroke=\"#b6a8ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-28e8cc4ae25b470a\" data-sq-series-index=\"1\" data-sq-category-index=\"1\" data-sq-palette-index=\"1\"/><rect x=\"37\" y=\"272.8\" width=\"360.48\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-0)\" stroke=\"#79a2ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-0443a8b5e5c64471\" data-sq-series-index=\"0\" data-sq-category-index=\"2\" data-sq-palette-index=\"0\"/><rect x=\"397.48\" y=\"272.8\" width=\"262.85\" height=\"24\" fill=\"url(#sq-120410e5d0ec-gradient-1)\" stroke=\"#b6a8ff\" stroke-width=\"1\" class=\"sq-mark sq-bar\" data-sq-role=\"bar\" data-sq-target-key=\"t-bar-a7b0b3a19a0c6e17\" data-sq-series-index=\"1\" data-sq-category-index=\"2\" data-sq-palette-index=\"1\"/><line x1=\"37\" y1=\"38.8\" x2=\"37\" y2=\"334\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-axis\" data-sq-role=\"axis-line\"/><line x1=\"33\" y1=\"88\" x2=\"37\" y2=\"88\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"33\" y1=\"186.4\" x2=\"37\" y2=\"186.4\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><line x1=\"33\" y1=\"284.8\" x2=\"37\" y2=\"284.8\" stroke=\"#475467\" stroke-width=\"1\" class=\"sq-tick\" data-sq-role=\"tick\"/><text x=\"31\" y=\"91.5\" font-size=\"10\" text-anchor=\"end\" textLength=\"18\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"0\">Jan</text><text x=\"31\" y=\"189.9\" font-size=\"10\" text-anchor=\"end\" textLength=\"18\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"1\">Feb</text><text x=\"31\" y=\"288.3\" font-size=\"10\" text-anchor=\"end\" textLength=\"18\" lengthAdjust=\"spacing\" fill=\"#aab4c5\" class=\"sq-label sq-category-label\" data-sq-role=\"category-label\" data-sq-category-index=\"2\">Mar</text></g></svg>",
  "width": 800,
  "renderSummary": {
    "variation": "standard",
    "orientation": "horizontal",
    "mode": "stacked",
    "categoryCount": 3,
    "seriesCount": 2,
    "visibleBarCount": 6,
    "missingPointCount": 0
  }
}
  • Use the published full rendering profile for the best result: Squillify styling, certified enter-grow motion and a mountable host artifact
  • Compare a metric across a few named categories
  • Show grouped or stacked series side by side
  • Export the canonical static SVG when a host runtime is unavailable

Avoid for

  • Continuous time series (use chart.line)
  • Hundreds of categories — we refuse those
  • Drill-down or brushing

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

visualizationsvgchartbar-chart