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 |
::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.
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 |
::chart{title="Longest review threads (min)"}
| 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 |
::Data
| team | sunny | rainy |
|---|---|---|
| frontend | 12 | 31 |
| backend | 16 | 40 |
| design | 2 | 9 |
::chart{title="Tabs-vs-spaces arguments per month"}
| team | sunny | rainy |
| --- | --: | --: |
| frontend | 12 | 31 |
| backend | 16 | 40 |
| design | 2 | 9 |
::Data
| day | work | weekend | pigeons |
|---|---|---|---|
| Monday | 4 | 11 | 2 |
| Wednesday | 6 | 1 | 3 |
| Friday | 2 | 14 | 7 |
::chart{type="stacked" title="Standup by topic (min)"}
| day | work | weekend | pigeons |
| --- | --: | --: | --: |
| Monday | 4 | 11 | 2 |
| Wednesday | 6 | 1 | 3 |
| Friday | 2 | 14 | 7 |
::Data
| month | thumbs up | eyes |
|---|---|---|
| 2026-06 | 40 | 20 |
| 2026-07 | 46 | 24 |
| 2026-08 | 52 | 28 |
| 2026-09 | 58 | 32 |
| 2026-10 | 64 | 36 |
::chart{type="area" title="Emoji reactions in team chat (hundreds)"}
| month | thumbs up | eyes |
| --- | --: | --: |
| 2026-06 | 40 | 20 |
| 2026-07 | 46 | 24 |
| 2026-08 | 52 | 28 |
| 2026-09 | 58 | 32 |
| 2026-10 | 64 | 36 |
::Data
| pigeons | failed deploys | rollbacks |
|---|---|---|
| 2 | 1 | 0 |
| 5 | 3 | 1 |
| 9 | 4 | 2 |
| 14 | 7 | 3 |
| 21 | 9 | 5 |
::chart{type="scatter" title="Failed deploys against pigeons on the roof (r = 0.99)"}
| pigeons | failed deploys | rollbacks |
| --: | --: | --: |
| 2 | 1 | 0 |
| 5 | 3 | 1 |
| 9 | 4 | 2 |
| 14 | 7 | 3 |
| 21 | 9 | 5 |
::Data
| reason | share |
|---|---|
| the pigeons | 58 |
| cat on the keyboard | 24 |
| it's Friday | 12 |
| the code | 6 |
::chart{type="pie" title="Why the build failed, according to the team (%)"}
| reason | share |
| --- | --: |
| the pigeons | 58 |
| cat on the keyboard | 24 |
| it's Friday | 12 |
| the code | 6 |
::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" }
}
}
```
::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.
:::
::| 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.