Charts
Scatter and bubble charts in your AI client
Bonnard draws a scatter chart to plot one measure against another, one point per row, and a bubble chart when a third measure sets each point’s size.


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:
explore_schemafinds the tables and their columns: hereweekly_store_sales, withweek_start,store,footfallandorders.sql_queryruns a read-only query, so the agent can check the numbers first.render_charttakes 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 store, ROUND(AVG(footfall)) AS footfall, SUM(orders) * 1.0 / SUM(footfall) AS conversion FROM weekly_store_sales WHERE week_start >= DATE '2026-06-29' GROUP BY store",
"chartType": "scatter",
"title": "Footfall against conversion by store, Q3 2026",
"encode": { "x": "footfall", "y": "conversion" },
"fields": [
{ "name": "footfall", "label": "Weekly footfall", "format": "number" },
{ "name": "conversion", "label": "Conversion", "format": "percent" }
]
}
]
}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/scatter.
Bubbles
Footfall against conversion for each store last quarter, with bubbles sized by revenue.


JSON
{
"sql": "SELECT store, ROUND(AVG(footfall)) AS footfall, SUM(orders) * 1.0 / SUM(footfall) AS conversion, SUM(revenue) / 1000 AS revenue FROM weekly_store_sales WHERE week_start >= DATE '2026-06-29' GROUP BY store",
"chartType": "scatter",
"title": "Footfall against conversion, sized by revenue, Q3 2026",
"encode": { "x": "footfall", "y": "conversion", "size": "revenue" },
"fields": [
{ "name": "footfall", "label": "Weekly footfall", "format": "number" },
{ "name": "conversion", "label": "Conversion", "format": "percent" },
{ "name": "revenue", "label": "Revenue (£k)", "format": "number" }
]
}A third measure sets each point’s size, scaled to the largest value on the chart. The chart names that measure under its title.
Colour by group
Footfall against conversion for each store last quarter, coloured by region.


JSON
{
"sql": "SELECT store, region, ROUND(AVG(footfall)) AS footfall, SUM(orders) * 1.0 / SUM(footfall) AS conversion FROM weekly_store_sales WHERE week_start >= DATE '2026-06-29' GROUP BY store, region",
"chartType": "scatter",
"title": "Footfall against conversion by region, Q3 2026",
"encode": { "x": "footfall", "y": "conversion", "series": "region" },
"fields": [
{ "name": "footfall", "label": "Weekly footfall", "format": "number" },
{ "name": "conversion", "label": "Conversion", "format": "percent" }
]
}A text column splits the points into groups, one colour each, and the legend lists the largest group first. The store, the other text column, names each point in its tooltip.
Quadrants
Footfall against conversion for each store last quarter, split at the median footfall and our 4% conversion target.


JSON
{
"sql": "SELECT store, ROUND(AVG(footfall)) AS footfall, SUM(orders) * 1.0 / SUM(footfall) AS conversion FROM weekly_store_sales WHERE week_start >= DATE '2026-06-29' GROUP BY store",
"chartType": "scatter",
"title": "Stores against median footfall and the conversion target",
"encode": { "x": "footfall", "y": "conversion" },
"fields": [
{ "name": "footfall", "label": "Weekly footfall", "format": "number" },
{ "name": "conversion", "label": "Conversion", "format": "percent" }
],
"reference": [
{ "y": 0.04, "label": "Target 4%" },
{ "x": "median", "label": "Median footfall" }
]
}Only a scatter takes a vertical line. With one vertical and one horizontal line the points fall into quadrants, each line at a number, the average or the median.
Axis ranges
Footfall against conversion for each store last quarter, with footfall from zero and the conversion axis fitted to the data.


JSON
{
"sql": "SELECT store, ROUND(AVG(footfall)) AS footfall, SUM(orders) * 1.0 / SUM(footfall) AS conversion FROM weekly_store_sales WHERE week_start >= DATE '2026-06-29' GROUP BY store",
"chartType": "scatter",
"title": "Footfall against conversion by store, Q3 2026",
"encode": { "x": "footfall", "y": "conversion" },
"fields": [
{ "name": "footfall", "label": "Weekly footfall", "format": "number" },
{ "name": "conversion", "label": "Conversion", "format": "percent" }
],
"axes": { "x": { "min": 0 }, "y": { "min": "auto" } }
}By default the x-axis fits the data and the y-axis starts at zero. Each end of either axis takes a number, or a fit to the data.
Options and limits
| Ask for | What Bonnard draws |
|---|---|
| ”as a scatter plot” or “footfall against conversion” | One point per row, from two numeric columns |
| ”sized by revenue” | A bubble chart, a third measure setting each point’s size |
| ”coloured by region” | One colour per group, with a legend |
| ”France in amber” | A named colour per group, from eight colours and grey |
| ”make the UK stand out” | Up to three groups in colour, the rest in grey |
| ”the UK as triangles” | A point shape per group |
| ”split at the median” | Vertical and horizontal lines that make quadrants |
| ”a target line” or “the average” | Reference lines and bands, up to six |
| ”start footfall at zero” | A fixed range on either axis, or one fitted to the data |
| ”legend at the top” | The legend at the top or bottom, or hidden |
- One row is one point, and the chart sums nothing: the query does any grouping.
- Both axes take numeric columns only, and the x-axis is always a number line.
- The colour split takes a text column and ignores a numeric one. The size takes a numeric column.
- A chart query returns up to 5,000 rows by default, so up to 5,000 points.
- Points turn more translucent past 150 and again past 400, so overlaps read as density.
- A fixed axis end wins over a reference line, which is then not drawn.
- A scatter takes no trend line or moving average: those are for line, bar and area charts.
- Labels and axis titles run to 60 characters.
- A scatter chart draws no data labels. No chart draws a log scale, custom hex colours or zoom.