stack
Stacks groups edge-to-edge along an axis with no gap between them — spread without the spacing. The basis for stacked bar charts and pie charts.
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=500, h=300)Signature
stack(children=None, *, by=None, dir, **options) -> Operator | MarkLike spread, stack is polymorphic: called with no positional argument it returns an operator for use inside .flow(); called with a positional list of marks it returns a combinator-form mark that stacks those explicit children (the low-level form behind the stackX/stackY operators).
Parameters
stack — Operator form
spread({ glue: true }) under its own wire tag — children glued together (touching, no gaps).
| Option | Type | Default | Description |
|---|---|---|---|
by | str | Any | Field to partition rows by; also accepts a field(...) accessor carrying domain ops (sort/reverse/bin). | |
dir | str | Axis to stack along: x, y, or an axis name the enclosing coordinate space declares (polar theta/r, geo lon/lat). | |
spacing | float | Forwarded to the underlying spread. Glue semantics force the effective gap to 0; accepted for spread-parity. | |
glue | bool | Spread-parity passthrough; stack always glues regardless. | |
alignment | str | "baseline" | Cross-axis alignment ("start" | "middle" | "end" | "baseline"). |
shared_scale | bool | False | Share one scale across all children. |
anchor | str | "edge" | Whether spacing is measured between facing edges (edge), or as a fixed pitch between the named anchor point on each child. |
reverse | bool | False | Reverse the children's order along dir. |
axes | Any | ||
x | int | float | str | Left edge of this operator's box, in the parent's space (pixels). Omitted, the parent places it. | |
y | int | float | str | Start edge on y (top where y reads top-down, bottom where it grows upward) of this operator's box, in the parent's space (pixels). Omitted, the parent places it. | |
w | int | float | str | Data-driven cross-axis extent (field/datum-sized children). | |
h | int | float | str | Data-driven cross-axis extent (field/datum-sized children). | |
size | int | float | str | Per-entry stack-axis extent (field/datum-sized children); a field(...).normalize() accessor makes it a space-filling spine. |
stack — Combinator form
Low-level combinator form of stack. Same fields as the operator form (OPERATORS.stack) plus key and the full box-dims group.
| Option | Type | Default | Description |
|---|---|---|---|
x | int | float | str | Left edge of this operator's box, in the parent's space (pixels). Omitted, the parent places it. | |
w | int | float | str | Data-driven cross-axis extent (field/datum-sized children). | |
y | int | float | str | Start edge on y (top where y reads top-down, bottom where it grows upward) of this operator's box, in the parent's space (pixels). Omitted, the parent places it. | |
h | int | float | str | Data-driven cross-axis extent (field/datum-sized children). | |
by | str | Any | Field to partition rows by; also accepts a field(...) accessor carrying domain ops (sort/reverse/bin). | |
dir | str | Axis to stack along: x, y, or an axis name the enclosing coordinate space declares (polar theta/r, geo lon/lat). | |
spacing | float | Forwarded to the underlying spread. Glue semantics force the effective gap to 0; accepted for spread-parity. | |
glue | bool | Spread-parity passthrough; stack always glues regardless. | |
alignment | str | "baseline" | Cross-axis alignment ("start" | "middle" | "end" | "baseline"). |
shared_scale | bool | False | Share one scale across all children. |
anchor | str | "edge" | Whether spacing is measured between facing edges (edge), or as a fixed pitch between the named anchor point on each child. |
reverse | bool | False | Reverse the children's order along dir. |
axes | Any | ||
size | int | float | str | Per-entry stack-axis extent (field/datum-sized children); a field(...).normalize() accessor makes it a space-filling spine. | |
key | str | Internal per-node key override. |
Box dimensions
| Option | Type | Default | Description |
|---|---|---|---|
cx | int | float | str | Center x. | |
x2 | int | float | str | Right edge position. | |
em_x | bool | Embed x in the parent's x space. | |
cy | int | float | str | Center y. | |
y2 | int | float | str | Other y edge position. | |
em_y | bool | Embed y in the parent's y space. | |
dims | dict | Box dimensions by axis name: x/y, or a name the enclosing coordinate space declares (polar theta/r, geo lon/lat). Each value is a position (like x) or an interval {min, center, max, size, embedded}. |
Returns an Operator for use inside .flow().
dir takes "x", "y", or an axis name the enclosing coordinate space declares, such as "theta" under polar; see spread → naming the axis.
Signed parts
stack places its parts end to end, in order. Each part starts where the one before it ends, and the first part starts at 0. A negative part goes back, so the stack ends at the sum of its parts, and parts that cancel overlap. Parts (+100, −30, +20, −50, +10) rise to 100, step back and forth, and end at 50.
To pile positive parts up from 0 and negative parts down from 0 (a diverging stacked bar), group by sign first, so each stack holds one sign:
# `direction` is "Inflow" for positive amounts and "Outflow" for negative.
chart(cash_flows).flow(
spread(by="quarter", dir="x"),
group(by="direction"),
stack(by="flow", dir="y"),
).mark(rect(h="amount", fill="flow"))Centered stacks
When the chart's schema gives the by column a midpoint (Schema.ordered(levels).diverging()), the stack's 0 is the midpoint of that order instead of the start of its first part. The parts must be nonnegative. This draws Likert charts and population pyramids:
chart(
survey, schema={"response": Schema.ordered(LEVELS).diverging()}
).flow(
spread(by="question", dir="y"),
stack(by="response", dir="x"),
).mark(rect(w="count", fill="response"))Examples
# Stacked bars: lakes across x, species stacked up y
chart(seafood).flow(
spread(by="lake", dir="x"),
stack(by="species", dir="y"),
).mark(rect(h="count", fill="species"))
# Grouped bars: stack along x instead
chart(seafood).flow(
spread(by="lake", dir="x"),
stack(by="species", dir="x"),
).mark(rect(h="count", fill="species"))