display_chart tool from a previous execute_sql result, and both can be adjusted afterwards without re-running the query.
Chart types
The agent picks a chart type from the result set, and you can change it later from the edit dialog.
Stacked bar and stacked area charts also have a normalized variant that plots each series as a share of its category total on a 0-100% axis. See Normalize to 100 percent below.
For large numeric values, nao shortens Y-axis labels to values such as
100K, 1.5M, or 2B to keep charts readable.
Pie and donut charts
Pie and donut charts take exactly one series. Categories are shown in a legend rather than as labels drawn on the slices, and slices are separated by a small gap so adjacent categories stay distinguishable. When a result set has more than 10 categories, nao keeps the 10 largest slices by value and sums the remainder into a single Other slice. If the data already contains a category called “Other”, the remainder is merged into it rather than creating a duplicate.Editing a chart
Click the pencil icon next to a chart’s download button to open the edit dialog. Changes apply to the existing chart config, so the query is not re-run. The dialog lets you set:- Title
- Chart type
- X-axis type:
Auto,Category,Date, orNumber - X-axis column
- X-axis label: an optional custom label drawn under the axis
- Series: for each series, the data column, an optional label, a color, a value format (number format, unit, and placement), and - on mixed charts - a series type and Y-axis side. Use Add series to plot another column, or the bin icon to remove one (at least one series is required).
- Y-axis range
- Show data labels
Normalize to 100 percent
When the selected chart type is a stacked bar or stacked area chart, the dialog shows a Normalize to 100% toggle. Turning it on switches the chart to its 100% stacked variant: each series is drawn as a share of the category total and the axis runs from 0 to 100%. Tooltips show percentages instead of absolute values. Use it when the composition matters more than the absolute totals. Turning the toggle off returns the chart to absolute stacking.Y-axis range
By default the Y axis adapts to the values in the result set. Line and scatter charts auto-scale to a readable range rather than forcing a zero baseline. To pin the scale, enter a Min, a Max, or both in the Y-axis range fields. Leaving a field on itsAuto placeholder keeps that bound automatic. The minimum must be lower than the maximum, otherwise the dialog rejects the change.
The Y-axis range fields are not shown for pie, KPI card, and radar charts, which have no Y axis.
Data labels
The Show data labels toggle prints the numeric value of each data point directly on the chart, instead of requiring a hover. You can also ask the agent for it in plain English (for example: “show the values on the chart”). On line and area charts, labels are limited to the most significant points so a dense series stays legible.Combo charts and a second Y-axis
Pick the Mixed chart type to draw several series with different shapes in one chart - for example bars for revenue and a line for a conversion rate. Each series then gets two extra controls in its row of the edit dialog:- Series type - draw that series as a
bar,line, orarea, independent of the others. - Y-axis side - plot the series against the
leftorrightaxis. A right axis appears as soon as any series uses it, which is what lets you compare metrics on very different scales or units in a single chart.
KPI comparison pills
A KPI card can show a small change pill under its number, comparing the latest value to the previous period. Turn it on with the Comparison pill control in the edit dialog (it appears only for KPI cards), or ask the agent for it. There are three styles:- Percentage - the signed percentage change, colored green or red with an arrow.
- Variation - the signed absolute change, colored green or red with an arrow.
- Absolute - just the magnitude of the change, with no color or arrow.
Hiding the tooltip total
When a chart stacks several series, the tooltip shows a Total row by default. That total is meaningless when the series can’t be meaningfully added up - unrelated metrics, or different units or currencies. The agent can set a chart-widehide_total option to drop the Total row in those cases; additive charts still show it, and percentage charts still show 100%.
Value formatting
By default chart values render as plain numbers. Value formatting lets you show a currency symbol, a%, or any unit (V, kg, GB, …) and control how numbers are rounded and abbreviated. Formatting is set per series, so a chart can mix, for example, a dollar series and a percentage series.
A format applies everywhere the series’ value appears: the value axis, tooltips, data labels, and KPI cards. It also carries through into stories, including their HTML and PDF exports. The value axis automatically widens to fit longer labels (such as $1,000,000) so they don’t clip.
A value format has three parts:
- A number format - a d3-format specifier that controls rounding, thousands separators, and abbreviation of the raw number.
- A unit - free text such as a currency symbol (
$,€,¥,£), a%, or a unit likeV,kg,GB. - A placement - whether the unit sits before the number (Prefix, for currencies) or after it (Suffix, for
%and most units).
Setting it in the editor
In the chart edit dialog, each series row has a Number format, a Unit, and a Placement (Prefix or Suffix). Any part can be left blank.Asking the agent
You usually don’t need to open the editor - ask in plain English and the agent sets the format for you:“Format revenue as US dollars.” “Show the conversion rate as a percentage with one decimal.” “Label the storage column in GB.”
d3-format number cheat sheet
The number format field takes a raw d3-format specifier and applies it to the value as-is (it does not multiply or divide). Copy-paste one of these:
The pattern is
[,][.precision][type]: a leading , adds thousands separators, .N sets precision, and the trailing letter is the type - f for fixed decimals or s for SI-prefix abbreviation. See the full d3-format docs for more.
Copy-paste recipes (format + unit)
Percentages
Do not use d3’s% format type - it multiplies the value by 100. If your data is already stored as a percentage (for example 42.5 meaning 42.5%), use a plain number format (.1f) with a % unit set to Suffix placement. That renders 42.5 as 42.5%.
Abbreviating large numbers
The.2s (SI-prefix) number format abbreviates large numbers. How the abbreviation letters display depends on the series’ compact mode, which the agent picks based on the kind of value:
- Financial (the default) is meant for money and counts:
kbecomesKandGbecomesB, whileMandTare unchanged - so you get1.2K,3.4M,5.6B. - SI keeps d3’s scientific letters unchanged, which is what you want for scientific units such as bytes (
1.2k,3.4M,5.6G).
The editor accepts number formats that render identically in the interactive chart and in static story exports - the
f and s types, a bare ,, and a precision (for example ,.2f, .2f, ,, and .2s). If you enter a format that would export differently, the dialog shows a warning and blocks saving until you adjust it. The agent is not limited to these when it sets a format directly.Viewing the SQL and data behind a chart
Every chart is backed by a SQL query and its result set. Click the View SQL query and data action (the<> icon) on the chart toolbar to open a side panel with the execute_sql query on top and the result rows below, so you can verify exactly how a chart was built.
Tables
Ask for a table instead of a chart and the agent renders the result set withdisplay_chart using chart_type: "table".
Tables include:
- Right-aligned numeric columns with tabular figures, so digits line up.
- Sortable columns - click a column header to sort by it. Each click cycles through ascending, descending, and back to the original order (the chevron shows the current direction). Column widths stay stable across sorting and paging. This works on tables in chat, in stories, and on
execute_sqlresults.
Exporting table data
Any table - in a chat thread, in a story, or from anexecute_sql result - can be downloaded from its toolbar. The export menu offers two formats:
- CSV - a plain comma-separated file.
- Excel (
.xlsx) - a native spreadsheet file.
Conditional formatting
Numeric, boolean, and text columns can be colored by rule. Open the Edit table formatting dialog from the table toolbar and pick a rule per column - columns default to None. Available rules depend on the column type:Numeric
Color scale shades each cell on a gradient between the column minimum and maximum. Threshold colors cells matching a comparison (
≥, >, ≤, <, =) against a value.Boolean
Boolean sets a background color for true cells, false cells, or both. Leave a color unset to skip that case.
Text
String colors cells that match an operator:
equals for an exact match, in list for one of several values, or contains for a case-insensitive substring.“Show revenue by region as a table and highlight anything under 10k in red.” “Put a color scale on the conversion rate column.”The agent is instructed to use real conditional formatting for these requests rather than faking it with emoji or by adding an extra status column to the data.
Date format
Dates rendered by nao follow a project-level setting rather than each viewer’s locale, so everyone on the project reads the same format. Set it in Settings -> Project on the Date format card. This is an admin setting.
European is the default. Choosing Custom lets you compose a pattern from the supported tokens:
YYYY, YY, MMMM, MMM, MM, M, DD, D, dddd, and ddd. The card previews the result on a sample date as you type.
The setting applies to chart axes, tooltips, legends, and KPI cards, to SQL result tables, and to the charts and tables inside stories and their PDF and HTML exports.
Maps
When a query returns geographic points (latitude/longitude), the agent can plot them on an interactive map instead of a chart, using thedisplay_map tool. The map renders point data over an OpenStreetMap-based basemap, and you can pan and zoom it like any web map. Ask in plain English: “map our customers by city.”
Maps are experimental and off by default. An admin enables them under Settings -> Agent -> Experimental. Until then the agent won’t offer the map tool.
Custom charts
Beyond the built-in chart types, a project can ship its own custom charts - browser-rendered visualizations authored as small JavaScript modules inagent/charts/. Use them when a question needs a visual that nao’s built-in types don’t cover.
Each custom chart is a file agent/charts/<type>.js that exports a render function:
<type>must start with a lowercase letter and must not collide with a built-in type (bar,line,pie,table, …); names that break the rules are ignored.contextcarries thedatarows from the referencedexecute_sqlresult, the chartconfig, the naocolorsandtheme, and a set of chartinglibs.- Charts render in the browser only. Stories, exports, automations, MCP embeds, and messaging previews keep using the built-in chart types.
build-custom-charts skill in your project for the full authoring reference.