Statement report
Build a report that summarises a month of activity. You use line, pie and donut charts in one document, and learn number formatting and automatic height.
What this teaches
Building it in the editor
- Add a chart and set it to line. Three values are all it needs: the array path, the label expression and the value expression.
- Add two more charts as pie and donut. They read the same array in a different shape, so the value expression stays the same.
- Pie and donut show proportions. Past about eight slices they become unreadable, so switch to bar at that point.
- Write the summary figures as labels: {{ format(sum(data.daily, "amount"), "number", "0,0", "en-US") }} can never disagree with the table.
Building it with the schema and API
- A chart picks its kind with chartKind: "bar" (the default), "line", "pie" or "donut".
- The data shape is the table one: bind is the array, columns[0].cell is the label expression and columns[1].cell is the value expression. chartKind is the only new key.
- A value expression that is not a number contributes 0. It is the same reason currency formatting shows NaN for a string — send numbers.
- format(value, "number", "0,0", locale) adds thousand separators. Leaving the pattern empty defaults to 0,0.
The finished document
The JSON below is exactly the document those two routes produce. Our tests validate it and check that it renders without warnings, so you can paste it and use it as is.
{
"v": 1,
"unit": "px",
"page": {
"size": "a4",
"orientation": "portrait",
"margin": {
"t": 48,
"r": 48,
"b": 56,
"l": 48
},
"header": "{{ data.company }} · {{ data.period }}",
"footer": "[[page]] / [[pages]]"
},
"fonts": [],
"styles": [
{
"id": "s_h1",
"fontFamily": "Liberation Sans",
"fontSize": 22,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_l",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#333333",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_big",
"fontFamily": "Liberation Sans",
"fontSize": 28,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_cap",
"fontFamily": "Liberation Sans",
"fontSize": 11,
"fontWeight": 400,
"italic": false,
"color": "#666666",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
}
],
"nodes": [
{
"id": "n_title",
"parent": "",
"order": 0,
"type": "label",
"x": 0,
"y": 0,
"w": 697,
"h": 28,
"show": "",
"styleId": "s_h1",
"props": {
"text": "Monthly statement",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Title"
},
{
"id": "n_sum",
"parent": "",
"order": 1,
"type": "label",
"x": 0,
"y": 40,
"w": 340,
"h": 36,
"show": "",
"styleId": "s_big",
"props": {
"text": "{{ format(sum(data.daily, \"amount\"), \"number\", \"0,0\", \"en-US\") }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Total"
},
{
"id": "n_sum_l",
"parent": "",
"order": 2,
"type": "label",
"x": 0,
"y": 78,
"w": 340,
"h": 0,
"show": "",
"styleId": "s_cap",
"props": {
"text": "Total this month",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Total caption"
},
{
"id": "n_line_l",
"parent": "",
"order": 3,
"type": "label",
"x": 0,
"y": 116,
"w": 697,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Daily amount",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Line heading"
},
{
"id": "n_line",
"parent": "",
"order": 4,
"type": "chart",
"x": 0,
"y": 140,
"w": 697,
"h": 200,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.daily",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Day",
"cell": "{{ item.day }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "line",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Daily trend"
},
{
"id": "n_pie_l",
"parent": "",
"order": 5,
"type": "label",
"x": 0,
"y": 364,
"w": 340,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Share by product group",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Pie heading"
},
{
"id": "n_pie",
"parent": "",
"order": 6,
"type": "chart",
"x": 0,
"y": 388,
"w": 340,
"h": 220,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.mix",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Group",
"cell": "{{ item.name }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "pie",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Share pie"
},
{
"id": "n_donut_l",
"parent": "",
"order": 7,
"type": "label",
"x": 357,
"y": 364,
"w": 340,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Share by channel",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Donut heading"
},
{
"id": "n_donut",
"parent": "",
"order": 8,
"type": "chart",
"x": 357,
"y": 388,
"w": 340,
"h": 220,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.channel",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Channel",
"cell": "{{ item.name }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "donut",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Share donut"
}
]
}The request body. Put the document above into template and the data below into data.
{
"template": "(the document above)",
"data": {
"company": "brewmypdf",
"period": "2026-08",
"daily": [
{
"day": "1",
"amount": 1200
},
{
"day": "8",
"amount": 1850
},
{
"day": "15",
"amount": 1400
},
{
"day": "22",
"amount": 2100
},
{
"day": "29",
"amount": 1650
}
],
"mix": [
{
"name": "Subscription",
"amount": 4200
},
{
"name": "One-off",
"amount": 2600
},
{
"name": "Consulting",
"amount": 1400
}
],
"channel": [
{
"name": "Direct",
"amount": 5100
},
{
"name": "Partner",
"amount": 3100
}
]
}
}