Charts
A chart element draws a bar, line, pie or donut chart from your data, as vector graphics in the PDF. It takes width × height points at the cursor, plus an optional title above it, and moves the cursor below itself.
{ "type": "chart", "kind": "bar", "title": "Revenue by month",
"data": "months", "label": "name", "value": "revenue",
"width": 481, "height": 180, "axis": true, "gridlines": true }
data = {
'months' => [
{ 'name' => 'Jan', 'revenue' => 42_000 },
{ 'name' => 'Feb', 'revenue' => 38_500 },
{ 'name' => 'Mar', 'revenue' => 51_200 }
]
}
Soli::PDF.render(template: template, data: data)
See them in the annual report (bar, line and pie) and the subscription invoice (donut).
#Kinds
kind | Draws | Useful options |
|---|---|---|
bar | Vertical bars, one per point, or grouped and stacked with several series | axis, gridlines, mode |
line | A line through the points, one line per series | axis, gridlines |
pie | Slices proportional to the values | legend |
donut | A pie with a ring cut out: whatever is behind the chart shows through the hole | legend |
#Options
| Option | Type | Meaning |
|---|---|---|
kind | String | bar, line, pie or donut. |
width, height | Number (pt) | The size of the plot area. |
title | String | A caption drawn above the chart. |
data | String | The name of an array in the data document. |
label | String | The field of each item that holds the category label. |
value | String | The field of each item that holds the number (single series). |
values | Array | Several series: [{ "field", "name"?, "color"? }]. Replaces value. |
points | Array | Inline points [{ "label", "value" }] instead of data. |
colors | Array of hex | Colours cycled across points (or series). A built-in palette is used without it. |
legend | Bool | Pie and donut: a swatch list with each slice's percentage. |
axis | Bool | Bar and line: axis lines and category labels. |
gridlines | Bool | Bar and line: horizontal gridlines with value labels. |
mode | String | Bar with several series: "stacked". The default is grouped. |
Warning Values must be JSON numbers:
42000or42000.5, not"42,000"or"€42k". Format the labels as you like, but send the figures raw. Everywhere else in a template you send pre-formatted strings, so this is easy to miss.
#Data-bound or inline
Bind to an array in the data (data + label + value), or write the points into the template when they never change:
{ "type": "chart", "kind": "pie", "width": 300, "height": 150, "legend": true,
"points": [
{ "label": "Rent", "value": 1200 },
{ "label": "Payroll", "value": 3400 },
{ "label": "Cloud", "value": 800 }
] }
#Several series
Give values instead of value. Each series reads its own field from every item, and a legend shows the series names:
{ "type": "chart", "kind": "bar", "data": "quarters", "label": "q",
"gridlines": true, "axis": true, "width": 481, "height": 170,
"values": [
{ "field": "fy24", "name": "FY 2024", "color": "94a3b8" },
{ "field": "fy25", "name": "FY 2025", "color": "0f766e" }
] }
'quarters' => [
{ 'q' => 'Q1', 'fy24' => 120, 'fy25' => 150 },
{ 'q' => 'Q2', 'fy24' => 135, 'fy25' => 162 },
{ 'q' => 'Q3', 'fy24' => 128, 'fy25' => 171 },
{ 'q' => 'Q4', 'fy24' => 160, 'fy25' => 198 }
]
Bars are grouped side by side. Add "mode": "stacked" to stack them. With kind: "line", each series is its own line.
#A donut with a legend
{ "type": "chart", "kind": "donut",
"data": "spend", "label": "name", "value": "amount",
"width": 210, "height": 106, "legend": true,
"colors": ["312E81", "5B54C4", "8B84E8", "C3BEF6"] }
#Placing charts
A chart flows like a paragraph: it starts at the cursor and pushes what follows down. To put two charts side by side, use columns or place each with an at element. Charts also flow inside columns, and a chart inside a repeat still reads its data from the current item first. See Data binding.