typed-xlsx
Charts and Pivots

Marks

Bars, lines, areas, scatter plots, pies and doughnuts, with one or many series and dynamic columns.

A mark is one layer of a chart. Create it from a table with refs.table(id), then name the table's columns: x for categories and y for the values to plot. y only accepts columns that hold numbers.

Bar

createWorkbook
()
.
sheet
("Sales")
.
table
("sales", {
schema
:
sales
,
rows
: [] })
.
chart
("grouped", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
bar
({
x
: "month",
y
: ["revenue", "cost"] })],
})) .
chart
("stacked", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
bar
({
x
: "month",
y
: ["revenue", "cost"],
stack
: true })],
})) .
chart
("ranked", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
bar
({
x
: "month",
y
: "revenue",
horizontal
: true })],
}));
OptionEffect
stacktrue stacks the series, "percent" stacks them as shares of 100%
horizontalDraws bars sideways, first row on top. Horizontal bars cannot share a chart with other marks.
gapSpace between bar groups, as a percentage of a bar's width (0-500, default 150)

Line and area

createWorkbook
()
.
sheet
("Sales")
.
table
("sales", {
schema
:
sales
,
rows
: [] })
.
chart
("trend", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
line
({
x
: "month",
y
: "revenue",
smooth
: true }),
refs
.
table
("sales").
line
({
x
: "month",
y
: "cost",
dashed
: true,
markers
: false }),
], })) .
chart
("composition", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
area
({
x
: "month",
y
: ["cost", "margin"],
stack
: true })],
}));

Lines take smooth, markers (on by default), dashed, width (in points) and stack. Areas take stack.

Scatter

A scatter mark places each row by two numbers, so its x must be numeric too.

createWorkbook
()
.
sheet
("Deals")
.
table
("deals", {
schema
:
deals
,
rows
: [] })
.
chart
("discounts", ({
refs
}) => ({
title
: "Discount vs win rate",
marks
: [
refs
.
table
("deals").
scatter
({
x
: "discount",
y
: "winRate" })],
}));

Pass lines: true to join the points. Scatter marks cannot share a chart with other marks.

Pie and doughnut

Pies take label and value instead of x and y. A pie or doughnut is the only mark of its chart.

createWorkbook
()
.
sheet
("Regions")
.
table
("regions", {
schema
:
regions
,
rows
: [] })
.
chart
("share", ({
refs
}) => ({
marks
: [
refs
.
table
("regions").
pie
({
label
: "region",
value
: "revenue",
labels
: {
percent
: true } }),
], })) .
chart
("shareRing", ({
refs
}) => ({
marks
: [
refs
.
table
("regions").
doughnut
({
label
: "region",
value
: "revenue",
hole
: 60 })],
}));

colors sets the slice colors in row order.

Several series

y takes one column or a list. Use { column, name, color } to label or color one series of a list; name and color on the mark itself only apply when y is a single column.

createWorkbook
()
.
sheet
("Sales")
.
table
("sales", {
schema
:
sales
,
rows
: [] })
.
chart
("series", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
bar
({
x
: "month",
y
: ["revenue", {
column
: "cost",
name
: "Costs",
color
: "#94A3B8" }],
}), ], }));

Dynamic columns

Columns generated by a dynamic block can be plotted in two directions.

createWorkbook
()
.
sheet
("Territories")
.
table
("territories", {
schema
:
territories
,
rows
: [],
context
: {
months
: ["Jan", "Feb"] } })
// Months on the x axis, one line per territory row .
chart
("trend", ({
refs
}) => ({
marks
: [
refs
.
table
("territories").
line
({
x
: {
dynamic
: "months" },
series
: "territory" })],
})) // Territories on the x axis, one stacked series per month column .
chart
("mix", ({
refs
}) => ({
marks
: [
refs
.
table
("territories").
bar
({
x
: "territory",
y
: {
dynamic
: "months" },
stack
: true }),
], }));

With x: { dynamic }, each row becomes a series named by the series column, so a chart holds at most 255 rows.

Combining marks

Bars, lines and areas can share a chart when their x columns hold the same kind of value. Marks are drawn in order, and axis: "y2" puts a mark on a second value axis on the right.

createWorkbook
()
.
sheet
("Sales")
.
table
("sales", {
schema
:
sales
,
rows
: [] })
.
chart
("combo", ({
refs
}) => ({
marks
: [
refs
.
table
("sales").
bar
({
x
: "month",
y
: "revenue" }),
refs
.
table
("sales").
line
({
x
: "month",
y
: "marginRate",
axis
: "y2" }),
],
axes
: {
y2
: {
format
: "0%" } },
}));
Copyright © 2026 Cyprien Thao. Released under the MIT License.