# Line charts in your AI client

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

Updated: 2026-10-12

Bonnard draws a line chart to show a trend over time or along another ordered axis.

[Image: A chat with the question "Monthly revenue for the last 12 months, as a line chart.", three tool calls, and the line chart Bonnard drew: monthly revenue from October 2025 to September 2026, highest in December]

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` 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 date_trunc('month', order_date) AS month, SUM(revenue) / 1000 AS revenue FROM orders WHERE order_date >= DATE '2025-10-01' AND order_date < DATE '2026-10-01' GROUP BY 1 ORDER BY 1",
      "chartType": "line",
      "xAxisType": "categorical",
      "title": "Revenue by month (£k)",
      "encode": { "x": "month", "y": "revenue" },
      "fields": [
        { "name": "month", "label": "Month" },
        { "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/line`.

## One line per region

```prompt
Weekly revenue by region since July, one line per region.
```

[Image: Weekly revenue since July as five lines, one per region, the UK highest every week]

```json
{
  "sql": "SELECT week_start AS week, region, revenue / 1000 AS revenue FROM weekly_region_revenue WHERE week_start >= DATE '2026-06-29' ORDER BY week_start",
  "chartType": "line",
  "xAxisType": "categorical",
  "title": "Weekly revenue by region (£k)",
  "encode": { "x": "week", "y": "revenue", "series": "region" },
  "fields": [
    { "name": "week", "label": "Week" },
    { "name": "revenue", "label": "Revenue (£k)", "format": "number" }
  ]
}
```

A split draws one line per value of a column, each in its own colour, with a legend below.

## One line per measure

```prompt
Monthly revenue against budget for the last 12 months, with the budget dashed.
```

[Image: Monthly revenue as a solid line and the budget as a dashed line, close together all year]

```json
{
  "sql": "SELECT month, revenue / 1000 AS revenue, budget / 1000 AS budget FROM monthly_revenue_budget WHERE month >= DATE '2025-10-01' AND month < DATE '2026-10-01' ORDER BY month",
  "chartType": "line",
  "xAxisType": "categorical",
  "title": "Revenue against budget, by month",
  "encode": { "x": "month", "y": ["revenue", "budget"] },
  "fields": [
    { "name": "month", "label": "Month" },
    { "name": "revenue", "label": "Revenue", "format": "number" },
    { "name": "budget", "label": "Budget", "format": "number" }
  ],
  "axes": { "y": { "title": "Revenue (£k)" } },
  "series": { "Budget": { "line": "dashed" } }
}
```

Each measure is its own line on one shared axis, which the call titles. "Dashed" styles one line; dotted lines, markers and colours work the same way.

## A second axis

```prompt
Weekly orders since July, with the conversion rate on a second axis.
```

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

```json
{
  "sql": "SELECT week_start AS week, orders, conversion FROM weekly_orders WHERE week_start >= DATE '2026-06-29' ORDER BY week_start",
  "chartType": "line",
  "xAxisType": "categorical",
  "title": "Weekly orders, with conversion",
  "encode": { "x": "week", "y": "orders", "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, with its own scale and format. A target line can sit on either axis.

## A moving average

```prompt
Daily orders since July, with a 7-day average.
```

[Image: Daily orders as a faded line with a peak every weekend, and a dashed 7-day average over it, rising slowly]

```json
{
  "sql": "SELECT order_date AS day, COUNT(*) AS orders FROM orders WHERE order_date >= DATE '2026-07-01' GROUP BY 1 ORDER BY 1",
  "chartType": "line",
  "title": "Daily orders",
  "encode": { "x": "day", "y": "orders" },
  "fields": [
    { "name": "day", "label": "Day" },
    { "name": "orders", "label": "Orders", "format": "number" }
  ],
  "overlay": { "kind": "movingAverage", "window": 7 }
}
```

The dashed line averages the last 7 points, with the daily line faded behind it. "A trend line" fits a straight line instead.

## A break for missing days

```prompt
Daily conversion since August, with a gap where tracking was down.
```

[Image: Daily conversion around 3% as a line that breaks for three days in mid-September]

```json
{
  "sql": "SELECT day, orders * 1.0 / sessions AS conversion FROM daily_sessions WHERE day >= DATE '2026-08-01' ORDER BY day",
  "chartType": "line",
  "title": "Daily conversion since August",
  "encode": { "x": "day", "y": "conversion" },
  "fields": [
    { "name": "day", "label": "Day" },
    { "name": "conversion", "label": "Conversion", "format": "percent" }
  ],
  "fillGaps": "gap"
}
```

By default the line joins across days with no row. A break suits a rate like this one; counts can fill missing days with 0, and balances with the last value.

## Options and limits

Table: What a line chart takes

| Ask for | What Bonnard draws |
| --- | --- |
| "by region" or "one line per channel" | One line per value of a column |
| "revenue against budget" | One line per measure, on one axis |
| "on a second axis" | A right axis for a measure in other units |
| "stacked" or "as a share of the total" | Each line stacked on the one below, or as shares of 100% |
| "a gap where data is missing" | Missing periods left as a break, filled with 0, or held at the last value |
| "a target line" or "the average" | Reference lines and bands, up to six |
| "a 7-day average" or "a trend line" | A moving average over 2 to 52 points, or a least-squares line |
| "dashed", "dotted" or "with markers" | A line style, width and marker per line |
| "make the UK stand out" | Up to three lines in colour, the rest grey |
| "on a timeline" or "evenly spaced" | Dates spaced by the time between them, or one slot per row |
| "start the axis at 100" | A fixed axis range, or one fitted to the data |

- There is no cap on lines.
- A chart query returns up to 5,000 rows by default.
- Dates sit on a timeline unless the chart is stacked or the call asks for one slot per row. The weekly and monthly examples above ask for slots.
- A 7-day average has no value for the first 6 days, or for any window that holds a gap.
- A 100% stack takes no moving average or trend line, and a line on the right axis gets none.
- Gap filling stops after 10,000 periods.
- Labels and axis titles run to 60 characters.
- A line chart draws no data labels or smoothed lines. No chart draws a log scale, custom hex colours or zoom.

## When Bonnard draws something else

- Text on the x axis implies an order that may not exist. For categories, the product suggests a bar chart.
- A target that changes each period, such as a monthly budget, is a measure. The agent draws it as its own line, as in the budget example.
