render

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package render lowers a resolved chart into IR.

This is the one place that knows the drawing order of a chart — background, grid, axes, data, guides — and the one place that turns a layout rectangle and a set of scales into actual primitives. Geoms emit their own marks; everything around them is built here.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Draw

func Draw(b ir.Backend, c Chart) error

Draw lowers c into b. It does not call Flush: the caller owns the backend's lifecycle.

The order is fixed here and nowhere else: background, then every panel's grid and axes, then the titles, then every panel's data inside its own clip, then the guides. Data is drawn after the furniture so that a mark is never hidden by a grid line, and the guides last because they sit outside every panel and must not be clipped by one.

Types

type Chart

type Chart struct {
	Width, Height int
	DPR           float64
	Theme         theme.Theme

	Title  string
	XTitle string
	YTitle string

	X, Y scale.Scale

	// Coord is the stage between the scales and the IR: what the interval a
	// scale maps into means. Nil is [coord.Cartesian], which is the identity,
	// so a chart that names no coord draws exactly what it always drew.
	//
	// It belongs to the chart rather than to a panel: the panels of a facet are
	// the same plot over different rows, and one of them in a different
	// coordinate system would be a different chart.
	Coord coord.Coord

	Layers []geom.Geom

	// ShowLegend requests a legend. Entries come from the layers.
	ShowLegend bool

	// Description is what the chart says about itself in words, for a backend
	// that can carry it — see [ir.Semantics]. It is announced before anything
	// is drawn and never affects what is.
	Description ir.Description

	// Math typesets the notation in this chart's labels. It is nil for a chart
	// whose labels are text, which is the default and costs nothing: the
	// backend is wrapped only when there is a typesetter to wrap it with.
	Math mathtext.Typesetter

	// Panels, Rows and Cols describe a multi-panel chart: subplots, or the
	// facets of one plot. When Panels is empty the chart is the single panel
	// described by X, Y and Layers.
	Panels     []Panel
	Rows, Cols int

	// Serial draws the panels one at a time. The zero value builds them
	// concurrently where that is possible and worth it — see [drawData] — and
	// produces the same output either way.
	Serial bool

	// Observer is told which panel and which layer is drawing, so that a
	// caller watching the backend can attribute a mark to the layer that made
	// it. It is nil for an ordinary render, and setting it forces the serial
	// path: the observer is told things in order, and two panels drawing at
	// once have no order to be told in.
	Observer Observer

	// RowSink, when non-nil, collects which source row is behind each mark. It
	// is separate from Observer because it is a separate cost: a layer does
	// the bookkeeping only when someone is listening, so this is what turns it
	// on. See [geom.Rows].
	//
	// It is not called Rows because that name is already the facet grid's.
	RowSink geom.Rows
}

Chart is a fully specified chart, ready to be drawn.

type Observer added in v0.5.0

type Observer interface {
	// Panel opens a panel: its index in the chart, the rectangle it occupies,
	// the scales that place values in it, and the coord that turns a pair of
	// mapped positions into a point there. The scales are ranged for this
	// panel and must not be modified; the coord is framed for it and is what
	// turns a device position back into a pair — which is the only way a
	// tooltip over a pie slice names a value rather than a pixel.
	Panel(i int, area ir.Rect, x, y scale.Scale, cd coord.Coord)

	// Layer opens a layer within the panel just announced: its index among
	// that panel's layers, and its legend label if it has one.
	Layer(i int, label string)
}

Observer is told the structure a render is drawing, as it draws it.

It is how hit-testing gets built without widening the IR. A backend sees primitives — a polyline, some markers — and nothing about which layer of which panel emitted them; an Observer is told that separately, so a caller wrapping the backend can tag what it sees. Nothing here draws, and nothing here can change what is drawn.

The calls come in paint order: one Panel, then a Layer for each of its layers, then the next Panel. Only the data pass is announced — the grid, the axes and the guides are furniture, and a pointer landing on a grid line has not landed on anything.

type Panel added in v0.3.0

type Panel struct {
	// Row and Col place the panel in the grid.
	Row, Col int
	// Strip and RightStrip are the labels naming the panel, above it and
	// beside it.
	Strip, RightStrip string

	// X and Y are this panel's scales. Panels sharing an axis share the scale
	// object, which is what makes the axis shared rather than merely similar.
	X, Y scale.Scale

	// Coord overrides the chart's coordinate system for this panel, and is nil
	// for the panels that use it — which is every panel of a facet, because
	// the panels of a facet are one plot over different rows and one of them
	// in a different coordinate system would be a different chart.
	//
	// A grid of subplots is the case that needs it: those panels are separate
	// plots that happen to share a canvas, each with its own scales and its
	// own axes, so a pie beside a bar chart is two coords beside each other.
	Coord coord.Coord
	// Layers are this panel's marks.
	Layers []geom.Geom

	// ShowX and ShowY report whether this panel writes its own tick labels. A
	// panel that shares an axis with its neighbour leaves the labels to the
	// edge of the grid.
	ShowX, ShowY bool
}

Panel is one Cartesian area of a multi-panel chart.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL