# Bar charts in your AI client

> The words that change a bar chart in Bonnard, and the options and limits the product enforces.

Updated: 2026-10-12

Bonnard draws a bar chart to compare categories or periods.

[Image: A chat with the question "Revenue by region last quarter, as a bar chart.", three tool calls, and the bar chart Bonnard drew: revenue by region for Q3 2026, the UK highest]

The examples use Acme, a demo retailer that reports in pounds. Each variant is a few words in the question. A follow-up changes a chart already drawn.

## How an agent draws it

The chat above ran three tools, in this order:

1. `explore_schema` finds the tables and their columns: here `orders`, with `order_date`, `region` and `revenue`.
2. `sql_query` runs a read-only query, so the agent can check the numbers first.
3. `render_chart` takes the SQL and the chart options. It runs the query and returns the chart the chat draws.

The `render_chart` call behind the chart above:

```json
{
  "charts": [
    {
      "sql": "SELECT region, SUM(revenue) / 1000 AS revenue FROM orders WHERE order_date >= DATE '2026-07-01' AND order_date < DATE '2026-10-01' GROUP BY region ORDER BY revenue DESC",
      "chartType": "bar",
      "title": "Revenue by region, Q3 2026 (£k)",
      "encode": { "x": "region", "y": "revenue" },
      "fields": [
        { "name": "region", "label": "Region" },
        { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
      ]
    }
  ]
}
```

A call takes up to 10 charts, shown as a carousel. Each example below shows its one entry. A connected agent reads the full option reference with `explore_docs`, topic `charts/bar`.

## Stacked bars

```prompt
Revenue by channel for the last 12 months, stacked.
```

[Image: Monthly revenue as stacked bars, one colour per channel]

```json
{
  "sql": "SELECT date_trunc('month', order_date) AS month, channel, SUM(revenue) / 1000 AS revenue FROM orders WHERE order_date >= DATE '2025-10-01' GROUP BY 1, 2 ORDER BY 1",
  "chartType": "bar",
  "stacking": "stacked",
  "title": "Revenue by channel, by month (£k)",
  "encode": { "x": "month", "y": "revenue", "series": "channel" },
  "fields": [
    { "name": "month", "label": "Month" },
    { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
  ]
}
```

Each bar is the month's total, split by channel. "As a share of the total" stacks each bar to 100%.

## Side by side

```prompt
Revenue by channel for the last four months, side by side.
```

[Image: Four months of revenue, with one bar per channel in each month]

```json
{
  "sql": "SELECT date_trunc('month', order_date) AS month, channel, SUM(revenue) / 1000 AS revenue FROM orders WHERE order_date >= DATE '2026-06-01' GROUP BY 1, 2 ORDER BY 1",
  "chartType": "bar",
  "stacking": "grouped",
  "title": "Revenue by channel, June to September (£k)",
  "encode": { "x": "month", "y": "revenue", "series": "channel" },
  "fields": [
    { "name": "month", "label": "Month" },
    { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
  ]
}
```

Each channel gets its own bar. Bonnard draws a split this way unless the question says otherwise.

## Horizontal bars

```prompt
Revenue by product category in September.
```

[Image: September revenue by category as horizontal bars, outerwear first]

```json
{
  "sql": "SELECT category, SUM(revenue) / 1000 AS revenue FROM order_lines WHERE order_date >= DATE '2026-09-01' AND order_date < DATE '2026-10-01' GROUP BY category ORDER BY revenue DESC",
  "chartType": "bar",
  "title": "Revenue by category, September 2026 (£k)",
  "encode": { "x": "category", "y": "revenue" },
  "fields": [
    { "name": "category", "label": "Category" },
    { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
  ]
}
```

Bars turn sideways on their own when a label runs past 12 characters, as "Tops and T-shirts" does. Say "horizontal" or "upright" to choose.

## A second axis

```prompt
Weekly orders stacked by channel, with the conversion rate as a line on the right.
```

[Image: Weekly orders as stacked bars, with conversion as a line on a percentage axis at the right]

```json
{
  "sql": "SELECT week_label AS week, channel, orders, conversion FROM weekly_channel_orders WHERE week_start >= DATE '2026-06-29' ORDER BY week_start",
  "chartType": "bar",
  "stacking": "stacked",
  "xAxisType": "categorical",
  "title": "Weekly orders by channel, with conversion",
  "encode": { "x": "week", "y": "orders", "series": "channel", "y2": "conversion" },
  "fields": [
    { "name": "week", "label": "Week" },
    { "name": "orders", "label": "Orders", "format": "number" },
    { "name": "conversion", "label": "Conversion", "format": "percent" }
  ]
}
```

A measure in other units goes on a right axis, drawn as a line outside the stack.

## A target line

```prompt
UK weekly revenue since July, with a line at the £150K target.
```

[Image: UK weekly revenue as bars, with a dashed line at the £150K target]

```json
{
  "sql": "SELECT week_label AS week, revenue / 1000 AS revenue FROM weekly_region_revenue WHERE region = 'UK' AND week_start >= DATE '2026-06-29' ORDER BY week_start",
  "chartType": "bar",
  "xAxisType": "categorical",
  "title": "UK weekly revenue against target (£k)",
  "encode": { "x": "week", "y": "revenue" },
  "fields": [
    { "name": "week", "label": "Week" },
    { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
  ],
  "reference": [
    { "y": 150, "label": "Target £150K" }
  ]
}
```

Targets, budgets, shaded bands and average or median lines work the same way, up to six on one chart.

## Options and limits

Table: What a bar chart takes

| Ask for | What Bonnard draws |
| --- | --- |
| "stacked" | Series stacked in each bar |
| "as a share of the total" | A 100% stack, each series as its share of the bar |
| "side by side" | One bar per series, the default for a split |
| "horizontal" or "upright" | Bars turned sideways, or kept upright |
| "with the forecast as a line" | A measure drawn as a line on the same axis, outside the stack |
| "on the right" | A second axis for a measure in other units |
| "a target line" or "the average" | Reference lines and bands, up to six |
| "make outerwear stand out" | Up to three bars or series highlighted |
| "on a timeline" | Dates spaced by the time between them |
| "with a moving average" or "a trend line" | A dashed line computed over each series, the bars faded behind it |
| "missing months as zero" | Periods with no row drawn as 0, carried forward, or left empty |
| "start the axis at 100" | A fixed axis range, or one fitted to the data |

- There is no cap on bars or series.
- A chart query returns up to 5,000 rows by default.
- A line over the bars or a second axis keeps the chart upright.
- A 100% stack and horizontal bars keep one slot per row, never a timeline.
- Labels and axis titles run to 60 characters. When bars cannot turn sideways, category labels over 11 characters are cut short and tilted.
- A bar chart draws no data labels. No chart draws a log scale, custom hex colours or zoom.

## When Bonnard draws something else

- A histogram is a bar chart over buckets. The agent computes the buckets in SQL, then draws the bars.
- Many categories: the agent keeps the top rows, or groups the rest as "Other" in SQL.
