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(visual_mark) \
.render(w=..., h=...)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 widget |
Step 1: chart
chart(data) creates a ChartBuilder with your dataset. The data can be any list of dicts (or a pandas DataFrame):
data = [
{"category": "A", "value": 30},
{"category": "B", "value": 50},
{"category": "C", "value": 20},
]
chart(data)Chart-level options are passed as keyword arguments — including axes (see Step 4), a color scale, or a coordinate transform such as 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(by=..., dir=...)— divides space into separate regions for each groupstack(by=..., dir=...)— stacks items edge-to-edge along a shared scalescatter(by=..., x=..., y=...)— positions items by x/y coordinates
.flow(spread(by="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:
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, returning a widget that auto-displays in a notebook:
.render(w=400, h=300)Render options:
w— width in pixelsh— height in pixels
TIP
Axes are a chart() option in Python, not a render option (mirroring the JS chart(data, { axes: true })). Pass axes=... to chart(...):
chart(data, axes=True) # both axes, titles inferred
chart(data, axes=False) # no axes
chart(data, axes={"x": True, "y": False}) # x onlyOnly size (w/h) goes on .render(). See chart for the full axes shape.
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:
from gofish import chart, spread, stack, rect
chart(seafood, axes=True).flow(
spread(by="lake", dir="x"),
stack(by="species", dir="y"),
).mark(rect(h="count", fill="species")).render(w=400, h=300)The first operator (spread) creates separate regions for each lake along the x-axis. The second operator (stack) stacks the species vertically within each region.
Complete examples
Basic bar chart
A simple bar chart with one bar per category:
from gofish import chart, spread, rect
chart(seafood, axes=True).flow(spread(by="lake", dir="x")).mark(
rect(h="count")
).render(w=400, h=300)Grouped bar chart
To group bars side-by-side instead of stacking, use spread for both levels (same direction):
from gofish import chart, spread, rect
chart(seafood, axes=True).flow(
spread(by="lake", dir="x"),
spread(by="species", dir="x", spacing=0),
).mark(rect(h="count", fill="species")).render(w=400, h=300)Stacked bar chart
To stack bars, use spread then stack (perpendicular directions):
from gofish import chart, spread, stack, rect
chart(seafood, axes=True).flow(
spread(by="lake", dir="x"),
stack(by="species", dir="y"),
).mark(rect(h="count", fill="species")).render(w=400, h=300)