Skip to content

Blocks

The base

Block dataclass

Block(
    *, key: str | None = None, grow: bool = False, width: float | None = None
)

A thing that can state its height and then draw itself into a box.

key class-attribute instance-attribute

key: str | None = field(default=None, kw_only=True)

grow class-attribute instance-attribute

grow: bool = field(default=False, kw_only=True)

width class-attribute instance-attribute

width: float | None = field(default=None, kw_only=True)

measure abstractmethod

measure(width: float, theme: Theme) -> float

How tall this block is when set to width.

render abstractmethod

render(canvas: Canvas, box: Rect) -> None

Draw into box, the rectangle the parent gave this block.

draw

draw(canvas: Canvas, box: Rect) -> None

Place the block and record where it landed, for connectors.

named

named(key: str) -> Self

Record this block under key, so a connector can find its box.

Text

Span dataclass

Span(
    text: str,
    size: float | None = None,
    weight: int | None = None,
    italic: bool | None = None,
    fill: str | None = None,
    tracking: float | None = None,
    face: Font | None = None,
)

A stretch of a paragraph with a weight, colour or size of its own.

Everything left as None is inherited from the Text it sits in, so a span says only what it changes.

text instance-attribute

text: str

size class-attribute instance-attribute

size: float | None = None

weight class-attribute instance-attribute

weight: int | None = None

italic class-attribute instance-attribute

italic: bool | None = None

fill class-attribute instance-attribute

fill: str | None = None

tracking class-attribute instance-attribute

tracking: float | None = None

face class-attribute instance-attribute

face: Font | None = None

resolve

resolve(base: TextStyle, theme: Theme) -> TextStyle

This span's style, with the paragraph's filling in the rest.

Text dataclass

Text(
    text: str | Sequence[str | Span],
    size: float | None = None,
    weight: int = 400,
    italic: bool = False,
    fill: str = "ink",
    align: str = "left",
    leading: float | None = None,
    tracking: float = 0.0,
    wrap: bool = True,
    hyphenate: Callable[[str], Sequence[str]] | None = None,
    face: Font | None = None,
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

A paragraph, broken by total-fit and set at the requested alignment.

style

style(theme: Theme) -> TextStyle

line_height

line_height(theme: Theme) -> float

lines

lines(width: float, theme: Theme) -> tuple[Line, ...]

The broken lines this text makes at width.

measure

measure(width: float, theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Containers

Stack

Stack(
    *children: Block,
    gap: float | None = None,
    grow: bool = False,
    width: float | None = None,
)

Children laid out top to bottom, each as tall as it asked to be.

children instance-attribute

children = children

gap instance-attribute

gap = gap

measure

measure(width: float, theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Row

Row(
    *children: Block,
    gap: float | None = None,
    weights: Sequence[float] | None = None,
    grow: bool = False,
    width: float | None = None,
)

Children side by side, all stretched to the height of the tallest.

children instance-attribute

children = children

gap instance-attribute

gap = gap

weights instance-attribute

weights = tuple(weights) if weights else (1.0,) * len(children)

measure

measure(width: float, theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Frame dataclass

Frame(
    child: Block,
    fill: str = "page",
    stroke: str = "rule",
    pad: float | None = None,
    radius: float | None = None,
    stroke_width: float = 1.0,
    height: float | None = None,
    accent: str = "none",
    valign: str = "top",
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

A padded panel around one child: the card, the band, the callout.

child instance-attribute

child: Block

fill class-attribute instance-attribute

fill: str = 'page'

stroke class-attribute instance-attribute

stroke: str = 'rule'

pad class-attribute instance-attribute

pad: float | None = None

radius class-attribute instance-attribute

radius: float | None = None

stroke_width class-attribute instance-attribute

stroke_width: float = 1.0

height class-attribute instance-attribute

height: float | None = None

accent class-attribute instance-attribute

accent: str = 'none'

valign class-attribute instance-attribute

valign: str = 'top'

measure

measure(width: float, theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Atoms

Spacer dataclass

Spacer(
    height: float = 8.0,
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

height class-attribute instance-attribute

height: float = 8.0

measure

measure(_width: float, _theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Nothing to draw — a spacer only reserves height.

Rule dataclass

Rule(
    color: str = "rule",
    stroke_width: float = 1.0,
    height: float = 9.0,
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

color class-attribute instance-attribute

color: str = 'rule'

stroke_width class-attribute instance-attribute

stroke_width: float = 1.0

height class-attribute instance-attribute

height: float = 9.0

measure

measure(_width: float, _theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Draw dataclass

Draw(
    height: float,
    paint: Callable[[Canvas, Rect], None],
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

The escape hatch: reserve height, then draw into the box yourself.

height instance-attribute

height: float

paint instance-attribute

paint: Callable[[Canvas, Rect], None]

measure

measure(_width: float, _theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Image dataclass

Image(
    source: Path | str,
    height: float = 48.0,
    align: str = "left",
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

A picture, embedded in the figure and keeping its own proportions.

Give it a height; the width follows from the image. align places it across the box it was given, which matters in a row or a wide column.

source instance-attribute

source: Path | str

height class-attribute instance-attribute

height: float = 48.0

align class-attribute instance-attribute

align: str = 'left'

measure

measure(_width: float, _theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Bars dataclass

Bars(
    items: Sequence[tuple[str, float]],
    color: str = "accent",
    top: float | None = None,
    bar_height: float = 18.0,
    gap: float = 9.0,
    label_fraction: float = 0.34,
    fmt: str = "{:,.0f}",
    *,
    key: str | None = None,
    grow: bool = False,
    width: float | None = None,
)

A labelled bar chart, the workhorse of an infographic.

items instance-attribute

items: Sequence[tuple[str, float]]

color class-attribute instance-attribute

color: str = 'accent'

top class-attribute instance-attribute

top: float | None = None

bar_height class-attribute instance-attribute

bar_height: float = 18.0

gap class-attribute instance-attribute

gap: float = 9.0

label_fraction class-attribute instance-attribute

label_fraction: float = 0.34

fmt class-attribute instance-attribute

fmt: str = '{:,.0f}'

measure

measure(_width: float, _theme: Theme) -> float

render

render(canvas: Canvas, box: Rect) -> None

Composites

These return ordinary blocks assembled from the primitives above.

card

card(
    title: str, body: str, *, accent: str = "none", key: str | None = None
) -> Frame

A titled panel whose height follows its text.

band

band(title: str, *children: Block, key: str | None = None) -> Frame

A section container: tinted ground, tracked-out title, then content.

heading

heading(
    text: str,
    *,
    size: float | None = None,
    fill: str = "ink",
    align: str = "left",
) -> Text

Bold text at the theme's body size unless told otherwise.

eyebrow

eyebrow(text: str, *, fill: str = 'accent') -> Text

The small tracked-out capitals that label a band.

grid

grid(
    children: Sequence[Block], columns: int, *, gap: float | None = None
) -> Stack

Children wrapped into rows of columns.

A short last row is padded with empty cells, so its blocks keep the column width of the rows above instead of spreading out to fill the line.