Built-in charting: multi-series

The same charting prop, now multi-series: Group by Region, Split by Product, and toggle Stacked for a stacked / grouped chart. Change the pickers or filter a column and every series re-aggregates from the live grid rows.

A live, editable Svelte 5 data grid example from the SvGrid gallery (Charts). See the SvGrid documentation for the full API.

What this example shows

The `charting` prop isn't just one bar per group - point it at a `series` (split-by) column and it draws one series per distinct value, grouped or stacked. Everything is still one prop; the panel's Split by / Stacked / Value controls stay live, and filtering the grid re-aggregates the chart.

Imports, features and API used

Imports: @svgrid/grid

Table features registered: rowSortingFeature, columnFilteringFeature

Columns: region (Region), product (Product), quarter (Quarter), channel (Channel), revenue (Revenue), margin (Margin), units (Units)

Source code (354-charting-multi-series.svelte)

<!-- Documented in: docs/help/charts.md -->
<script lang="ts">
  /**
   * 354. Built-in charting: split-by + stacked
   * ------------------------------------------
   * The `charting` prop isn't just one bar per group - point it at a `series`
   * (split-by) column and it draws one series per distinct value, grouped or
   * stacked. Everything is still one prop; the panel's Split by / Stacked /
   * Value controls stay live, and filtering the grid re-aggregates the chart.
   */
  import {
    SvGrid,
    tableFeatures,
    rowSortingFeature,
    columnFilteringFeature,
    type GridColumns,
  } from '@svgrid/grid'

  const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })

  type Sale = {
    id: number
    region: string
    product: string
    quarter: string
    channel: string
    revenue: number
    units: number
    margin: number
  }
  const REGIONS = ['Americas', 'EMEA', 'APAC']
  const PRODUCTS = ['PLC', 'Drivers', 'Rivets']
  const QUARTERS = ['Q1', 'Q2', 'Q3', 'Q4']
  const CHANNELS = ['Direct', 'Partner', 'Online']
  let seed = 0x5a1e5
  const rnd = () => ((seed = (seed * 1103515245 + 12345) >>> 0) / 0xffffffff)
  const rows: Sale[] = []
  let id = 0
  for (const region of REGIONS)
    for (const product of PRODUCTS)
      for (const quarter of QUARTERS) {
        const revenue = Math.round(20_000 + rnd() * 80_000)
        rows.push({
          id: id++,
          region,
          product,
          quarter,
          channel: CHANNELS[id % 3]!,
          revenue,
          units: Math.round(40 + rnd() * 560),
          margin: Math.round(revenue * (0.12 + rnd() * 0.28)),
        })
      }

  const money = { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } as const
  const columns: GridColumns<Sale> = [
    { field: 'region', header: 'Region', width: 120 },
    { field: 'product', header: 'Product', width: 120 },
    { field: 'quarter', header: 'Quarter', width: 100 },
    { field: 'channel', header: 'Channel', width: 110 },
    { field: 'revenue', header: 'Revenue', width: 140, align: 'right', cellDataType: 'number', format: money },
    { field: 'margin', header: 'Margin', width: 130, align: 'right', cellDataType: 'number', format: money },
    { field: 'units', header: 'Units', width: 100, align: 'right', cellDataType: 'number' },
  ]
</script>

<div class="demo-page" style="height: 620px; display: flex; flex-direction: column;">
  <p class="demo-hint" style="margin: 0 0 8px;">
    One <code>charting</code> prop: <strong>Group by</strong> Region, <strong>Split by</strong> Product,
    <strong>Stacked</strong> - a multi-series chart. Change the pickers, toggle Stacked, or filter a column.
  </p>
  <div style="flex: 1; min-height: 0;">
    <SvGrid
      columnResize
      data={rows}
      {columns}
      {features}
      sortable
      filterable
      filterMode="row"
      selectionMode="both"
      containerHeight="100%"
      charting={{
        defaultOpen: true,
        width: 480,
        dimension: 'region',
        series: 'product',
        measures: 'revenue',
        stacked: true,
      }}
    />
  </div>
</div>

View this example on GitHub

Related documentation

Related articles

More Charts examples

  • Chart a selection (context menu) - With integrated charting enabled, the right-click menu gains a Chart selected range item: select a block of cells, right-click, and the chart panel opens scoped to that range - the Excel chart-this gesture, built in. The item appears only when charting is on and is appended to the default context menu automatically.
  • Chart view of the grid - The `chart` prop turns the same <SvGrid> into a chart, driven by the grid’s filtered + sorted rows (search + sort flow through). A view of the grid like board and scheduler, but the renderer is free: the grid lazy-loads a built-in view wrapping the standalone SvChart via rowsToChartSpec. Flip Table <-> Chart (bar / line / area) over one source of truth.
  • Candlestick / OHLC - Candlestick and OHLC price marks with an ordinal date axis. ChartSeries.ohlc carries the four prices while values keeps the closes, so the CSV export, the screen-reader table and a 10-day moving average all work with no candle-specific code. Toggle the axis: a real time axis opens a gap over every weekend, an ordinal one spaces sessions evenly and still labels them by date. The strip under the plot is the chart brush: drag its window to pan, drag an edge to resize.
  • Integrated charts (no deps) - Chart the grid data with no external charting library. SvGridChart renders a ChartSpec; rowsToChartSpec aggregates the grid current (filtered/sorted) rows into one. Bar, line, area, pie - plus 100% stacked, top-N + Other, an average reference line, and double-click-to-isolate a series. Filter the grid and the chart re-aggregates live.
  • Scatter / bubble chart - A scatter plot maps two numeric measures (x vs y); a bubble chart adds a third via dot radius. type: scatter with series points [{ x, y, r }]. Spend vs revenue, sized by deals, coloured by region, with an average-revenue reference line. Filter the grid and the cloud re-plots.