How to create a chart
GoFish uses a builder pattern to create charts. You chain four methods together: Chart, flow, mark, and render.
Basic pattern
Chart(data)
.flow(operators...)
.mark(visualMark)
.render(container, options)Each method has a specific role:
| Method | Purpose |
|---|---|
Chart(data) | Creates a builder with your dataset |
.flow(...) | Applies layout operators to position data |
.mark(...) | Sets the visual representation |
.render(...) | Renders the chart to a DOM element |
Step 1: Chart
Chart(data) creates a ChartBuilder with your dataset. The data can be any array of objects:
const data = [
{ category: "A", value: 30 },
{ category: "B", value: 50 },
{ category: "C", value: 20 },
];
Chart(data)You can also pass options for coordinate transforms (like polar coordinates for pie charts):
Chart(data, { coord: clock() })Step 2: flow
.flow() accepts one or more operators that determine how data is laid out spatially. The main operators are:
spread(field, options)— divides space into separate regions for each groupstack(field, options)— stacks items edge-to-edge along a shared scalescatter(field, options)— positions items by x/y coordinates
.flow(spread("category", { dir: "x" }))The dir option specifies the direction: "x" for horizontal, "y" for vertical.
See How to pick a layout operator for guidance on choosing between them.
Step 3: mark
.mark() specifies how each data item should appear visually. Common marks include:
rect()— rectangles (bars)circle()— circlesline()— connecting linearea()— filled area
Mark options can use fixed values or reference data fields:
.mark(rect({ h: "value", fill: "category" }))Here h: "value" means the rectangle height comes from each item's value field, and fill: "category" maps the fill color to the category field.
Step 4: render
.render() renders the chart into a DOM element:
.render(container, { w: 400, h: 300, axes: true })Options:
w— width in pixelsh— height in pixelsaxes— whether to show axes (boolean)
Composing operators
You can pass multiple operators to .flow() to create nested layouts. Operators apply in order—the first groups and positions the data, then subsequent operators work within those groups.
Example: Stacked bar chart
To create a stacked bar chart, use spread to separate categories horizontally, then stack to stack items within each category:
const data = [
{ category: "A", group: "X", value: 30 },
{ category: "A", group: "Y", value: 20 },
{ category: "B", group: "X", value: 50 },
{ category: "B", group: "Y", value: 35 },
{ category: "C", group: "X", value: 20 },
{ category: "C", group: "Y", value: 15 },
];
gf.Chart(data)
.flow(
gf.spread("category", { dir: "x" }),
gf.stack("group", { dir: "y" })
)
.mark(gf.rect({ h: "value", fill: "group" }))
.render(root, { w: 400, h: 300, axes: true });The first operator (spread) creates separate regions for each category along the x-axis. The second operator (stack) stacks the groups vertically within each region.
Complete examples
Basic bar chart
A simple bar chart with one bar per category:
gf.Chart(seafood)
.flow(gf.spread("lake", { dir: "x" }))
.mark(gf.rect({ h: "count" }))
.render(root, { w: 400, h: 300, axes: true });Grouped bar chart
To group bars side-by-side instead of stacking, use spread for both levels (same direction):
gf.Chart(seafood)
.flow(
gf.spread("lake", { dir: "x" }),
gf.spread("species", { dir: "x", spacing: 0 })
)
.mark(gf.rect({ h: "count", fill: "species" }))
.render(root, { w: 400, h: 300, axes: true });Stacked bar chart
To stack bars, use spread then stack (perpendicular directions):
gf.Chart(seafood)
.flow(
gf.spread("lake", { dir: "x" }),
gf.stack("species", { dir: "y" })
)
.mark(gf.rect({ h: "count", fill: "species" }))
.render(root, { w: 400, h: 300, axes: true });