---
title: Chart a table
tag: charts
summary: >-
  Plot the rows of a table on a Pegboard, and understand the one mapping that
  every chart kind shares.
---

# Chart a table

A Chart widget plots the rows of one table. This guide covers the mapping every chart kind shares,
which is what lets you bind a chart once and then try it as a line, a bar, or a pie without
re-entering anything.

## Prerequisites

A table whose rows carry the values you want to plot: one column to split the data by, and at least
one numeric column to measure. If the table holds readings at a finer grain than you intend to chart,
a workflow should aggregate it to that grain before it is written.

## The mapping

A chart is a query and a mapping. The query decides which rows are read; the mapping decides what
becomes of them. The mapping has exactly two parts, and they are the same two for all six kinds:

- **x** is what splits the data — the column whose values become points along an axis, bars, or
  wedges.
- **y** is what is measured — a numeric column, or several.

These are roles, not screen positions. A horizontal bar chart draws its measure across and its
domain down the side; the measure is still `y`. That is why changing the kind keeps the bindings:
nothing about `x` and `y` depends on where the drawing puts them.

Three things follow from the mapping having exactly this shape:

1. **A second measure makes a multi-series chart.** Adding `y` columns is the whole mechanism —
   there is no separate mode to choose.
2. **Splitting one measure does the same job from long-form data.** Where a wide table has one
   column per series, a long one has a column naming the series; **Series grouping field** reads
   that column. It applies to a single measure, because splitting several would need a third
   dimension the plot does not have.
3. **Round kinds take one measure and no split.** A pie has one wedge per `x` value and nowhere to
   lay a second dimension.

The axis kind — time, numeric, category — is read from the column's declared kind, so a Date column
plots as time without being told. Everything else has a default worth having: linear scale, plain
numbers, ordered by `x` ascending.

## Build one

**1. Add a Chart widget to a Pegboard.** Open **Edit widget** from its context menu.

**2. Choose the table** under **Table**, at the top of the editor.

**3. Bind the two columns** under **Plot fields**. For a line chart, choose the numeric column in
**Values (vertical axis)** and its time or category column in **Horizontal axis field**.
The live **Preview** below the settings reads real rows.

**4. Try the other kinds.** Use the dropdown under **Plot** to switch between them. Compatible
bindings survive the switch.

**Note**: a chart reads at most 1,000 rows. Use search, filters and the limit under **Rows**
to choose the returned window. A limit outside 1–1,000 stays visible with an error instead
of being changed to another number.

### Which observations are retained

A chart with a time-based horizontal axis keeps the **latest** observations by default.
Under **Rows**, **Truncate** chooses which end of the history is discarded:

- **Oldest observations (keep latest)** retains the newest N observations.
- **Newest observations (keep earliest)** retains the oldest N observations.

The horizontal date/time column determines age, without a separate source sort. **Offset**
counts from the retained end: with the default choice, offset 10 skips the ten newest observations.
**Ordering** only controls how the retained points are drawn; changing its direction does not
change which dates survive the limit. Non-time charts use their explicit source **Order** instead.

## Beyond the two bindings

The groups below the bindings start shut and print what they currently hold, so a chart with nothing
unusual set stays short:

- **Appearance** names a series and gives it one of the chart palettes, and chooses how
  numbers read — plain, compact, percent, currency, bytes, or a duration.
- **Scale and range** switches to a logarithmic axis and pins a minimum or maximum. Line charts
  fit their automatic range to the displayed values; linear bars and areas retain a zero baseline.
  Set a minimum of 0 for a zero-based linear line chart. With more than one series this group
  also offers stacking.
- **Ordering** sorts by `x`, by `y`, or by whatever order the query returned. Ordering by `y` on a
  pie is what "largest wedge first" means.

## Candles and session gaps

Choose **Candles**, then bind Open, High, Low and Close to numeric columns. Volume is available
for tooltips. A time column on the horizontal axis preserves elapsed time by default.

**Ignore session gaps** spaces the observed candles evenly. Dashed purple lines mark intervals
longer than 1.5 times the typical observed spacing, between the candles on either side of a gap.
This is inferred from the observations, not an exchange calendar; fewer than three candles
cannot establish a typical interval. Timestamps and prices in tooltips remain unchanged.

## One chart per group

A **Chart group** partitions a table by a column and draws each group in its own chart.
Use it for one price chart per ticker, or one sales chart per product. **Series grouping field**
still works inside scalar charts: grouping by product and splitting by region gives each product
its own chart containing the regions.

**1. Add a Chart group widget and choose its table.** The table comes before any
column selectors.

**2. Choose Group by** under **Grouping**. Text, select, integer, decimal, boolean, date and
date-and-time columns can group rows, and so can the row id. Empty text, the text `null`, and an
unspecified value remain three distinct groups.

**3. Set Sort groups by and Direction.** **Group key** orders the keys themselves. Another column
uses the smallest non-null value across all matching rows in each group; descending reverses
those same minima. Ties use the group key ascending, and nulls stay last.

**4. Set First N groups if you want a total cap.** Leave it blank to make all matching groups
reachable with **Load more groups**. Groups load in pages rather than all at once.

**5. Configure the plot** below Grouping, using the same columns and appearance controls as an
ordinary Chart.

**6. Choose the row window under Rows.** Time-based charts use **Truncate** independently
within each group; other charts use **Row order**. **Rows per group** caps each chart at
1–1,000 rows, and **Skip rows per group** moves that window from the selected end.
Search and filters apply before grouping. The separate **Ordering** settings only arrange points
already returned, so changing plot order cannot recover a row outside the window.

Automatic scales fit each chart independently. An explicit minimum or maximum applies to every
chart. A header such as **2 of 600 rows** means the chart shows a window, not the group's complete
history. Skipping beyond the available rows leaves a named empty chart; one group's malformed
candles do not hide its neighbours.

## When a chart will not draw

A chart says why rather than drawing an empty frame. The three it reports are worth knowing in
advance:

Rows missing a value for `x` or `y` are skipped, so one gap does not take the chart down. If every
row is missing one, the chart says so and names the columns — check that the table declares them
and that the workflow writing the rows fills them.

Two rows sharing an `x` value cannot both be plotted in one series. Aggregate to the grain you are
charting, or split by the column that distinguishes them.

A logarithmic axis cannot plot negative values. Zero values are drawn just above zero and still
read as `0` in tooltips. Explicit logarithmic bounds must be positive. A wedge cannot be sized
by a negative number.

## Next steps

[Build Data Views from your tables](/guides/verdalia-data-views) covers the other way to put a table
on a Pegboard: tables, cards, and checklists, for when the rows are things to read rather than values
to plot.
