Esc

comark-charts

Syntax

The table each chart type reads, Vega-Lite specs for any other chart, and the marks you can draw on a chart.

::chart{type="line" x="month" y="coffee cups, commits" title="Coffee cups and commits"}
| month | coffee cups | commits |
| --- | --: | --: |
| 2026-04 | 820 | 610 |
::
md

Put one table between ::chart and ::: a header row, then one row per bar, point, or step. The first column is x, and every other column is a series of numbers, named by its header. Rows are drawn in table order.

Prop What it does
type The chart type, from the table below. Without it, dates on x make a line and anything else makes bars.
x The column along the x axis. Default the first.
y The columns to draw, separated by commas. Default every column but x.
title The chart's caption, and its name for screen readers.

Cells hold plain numbers, with commas between thousands if you like, such as 1,200; put units in the header or the title, such as size (kB). x values in the form 2026, 2026-04, 2026-04-15, or an ISO date and time sit on a time axis, and numbers on a number axis, except on bars, steps, and dumbbells, which give each value its own row.

Chart types

type Use it for Table
bar One or more numbers per name: sizes, counts, timings. Names, then one column per series. Several series make grouped bars.
stacked Parts that add up to a total per name. Names, then one column per part.
line A trend over time or over a number. Dates or numbers, then one column per series. Each line is labelled at its end.
area Totals over time that add up. Dates, then one column per part, stacked.
scatter One measure against another. Numbers, then one column per series.
dumbbell Before and after for several metrics. Metric names, then two or more columns, such as before and after.
waterfall How changes add up to a total. The starting total, then each change, negative for a drop, then the end total, all in one column.
pie Shares of one whole. Names, then one column of numbers that aren't negative.

Bars turn sideways when their labels are long or there are many of them, so file paths and test names stay whole. In a waterfall, the first row is a total, and so is the last when it equals the running sum; the others are changes, green up and red down.

Playground
Longest review threads (min)
minutesnit: this file uses tabs and the rest of the repo uses spacescould we call this something other than data2why does the deploy script check for pigeonsis the rubber duck in this screenshot load-bearing51472284
Data
first comment minutes
nit: this file uses tabs and the rest of the repo uses spaces 84
could we call this something other than data2 51
why does the deploy script check for pigeons 47
is the rubber duck in this screenshot load-bearing 22

Any chart

For a chart the types don't cover, such as a box plot, a heatmap, or error bands, put a Vega-Lite spec after the table in a vega-lite block. The table is still its data, so it stays in the page: each row becomes one data point, with a field per column named by its header.

::chart{title="Latency per request (ms)"}
| endpoint | ms |
| --- | --: |
| /search | 120 |
| /search | 410 |
| /login | 40 |
| /login | 61 |

```vega-lite
{
  "mark": "boxplot",
  "encoding": {
    "x": { "field": "endpoint", "type": "nominal" },
    "y": { "field": "ms", "type": "quantitative" }
  }
}
```
::
md

Leave data out of the spec; the table replaces it. Cells that read as numbers become numbers, empty ones null, and the rest stay text. The chart takes the same colors and type as the others wherever the spec sets none, and its own config wins. type, x, y, and marks don't apply: name the columns in the spec's encoding, and draw notes with a text or rule layer. The plugin reports a spec that isn't JSON, a data it replaced, and a field that's neither a column nor made by a transform. The spec can't load files or URLs, and links in it are dropped.

Marks

Point at data with comark-annotate's marks: put an ::annotation inside the chart, after the table, and name the row it marks with at, the row's x value as the table writes it. Add series to mark one column's value rather than the whole row.

::chart{title="Rubber ducks bought, by team"}
| team | ducks |
| --- | --: |
| backend | 41 |
| frontend | 18 |
:::annotation{at="backend" color="red"}
Bought in bulk after the Tuesday incident.
:::
::
md
Prop What it does
at Required. The x value of the row to mark, copied from the table.
series The column to mark in that row. Without it, the mark covers every series in the row.
mark, color, side As on a screenshot: box, circle, underline, highlight, cross, check, or none; a named or hex color; and left, right, or top for a side note with an arrow.

The renderer finds the shape it draws for that value, a bar, a point, a slice, or a step, and draws the mark around it, so marks stay on their data when the numbers change. Notes are numbered under the chart, as under a screenshot, and a marked chart zooms like one. comark-annotate comes with comark-charts, and checks the marks the same way.