Documentation
¶
Overview ¶
Package marks holds the per-mark encoders that turn rows of a materialised table into scene.Mark entries with pixel-resolved geometry. P05 supports five marks: bar (Rect), line, area, point, rule. Other types (arc/text/path/image, plus composite/specialty) emit a PRISM_WARN_MARK_NOT_IMPLEMENTED warning.
Index ¶
- Constants
- func AttachDatum(marks []scene.Mark, layerID string, rowCount int)
- func AttachKeys(marks []scene.Mark, tbl *table.Table, field string)
- func AttachTooltips(marks []scene.Mark, tooltips []*scene.Tooltip)
- func BuildTooltips(tbl *table.Table, ch *spec.TooltipChannel, rowCount int) []*scene.Tooltip
- func Encode(markType string, in Inputs) ([]scene.Mark, *scene.Warning, error)
- func Quantile(sorted []float64, q float64) float64
- func SequentialColor(v, mn, mx float64) *scene.Color
- func SkipNullRows(tbl *table.Table, fields ...string) (kept []int, dropped int, offending []string)
- type BandScaler
- type BoxplotSummary
- type Channel
- type ColorChannel
- type HistogramResult
- type Inputs
- type SankeyLayout
- type SankeyLink
- type SankeyNode
- type Scale
Constants ¶
const ViolinResolution = 64
ViolinResolution is the default sample count along the value axis per violin group. See D061.
Variables ¶
This section is empty.
Functions ¶
func AttachDatum ¶
AttachDatum stamps a *scene.Datum back-reference on the first rowCount marks in the slice. layerID identifies the SceneLayer the marks belong to (defaults to "layer-0" for flat specs; composite encoders override via Inputs.LayerID).
Per D077, only the (layer_id, row_id) pair is populated by default. The Fields bag stays nil to keep the JSON payload small; tooltip channels already carry pre-formatted field values via D063. Composite encoders that emit aggregation rows (boxplot whiskers, histogram bin edges) can call AttachDatum on the appropriate prefix and leave the trailing helper marks without a Datum — the JS hit-test silently ignores marks without the data-prism-datum-row attribute.
rowCount typically equals the number of rows in the upstream table (the per-row encoders produce one mark per row). When rowCount is larger than len(marks), the helper stops at the end of the marks slice — both bounds are respected.
func AttachKeys ¶
AttachKeys stamps Mark.Key on per-row marks for use by the client-side animator. The key string format is "<field>=<value>"; missing or out-of-range rows yield an empty key (mark falls back to positional matching at tween time).
Like AttachDatum, only the leading rowCount marks are stamped; composite encoders that emit trailing helper marks (boxplot whiskers, histogram bin edges) are left untouched.
func AttachTooltips ¶
AttachTooltips attaches tooltips[i] to marks[i].Tooltip in 1:1 order. When len(tooltips) != len(marks), attaches as far as the shorter slice allows (single-mark types like line/area receive tooltips[0]; per-row types receive 1:1). Mutates marks in place.
func BuildTooltips ¶
BuildTooltips materialises one *scene.Tooltip per row from a TooltipChannel binding. Returns nil when ch is nil (caller leaves Mark.Tooltip nil — per-mark renderers skip the <title> child).
Each TooltipLine is formatted as "<field>: <formatted_value>" where the formatter is the channel's `format` specifier through encode/format (matching axis-label formatting), falling back to fmt.Sprintf("%v", value) when no format is set.
Single tooltip: 1 line per row. Multi tooltip: N lines per row (one per Multi entry).
Missing fields render as "<field>: <missing>" — tooltips are diagnostic, never blocking. See D063.
func Encode ¶
Encode dispatches markType to its per-mark helper. Returns the generated marks + an optional warning (for unsupported types). Errors bubble PRISM_ENCODE_001 or PRISM_RENDER_001 from the helpers.
P10: tooltip materialisation runs post-dispatch. When in.Tooltip != nil, BuildTooltips walks the upstream table once and AttachTooltips attaches the *scene.Tooltip to each mark in per-row order (single-mark types receive row 0's tooltip).
func Quantile ¶
Quantile returns the q-th quantile (q in [0, 1]) of a sorted slice via linear interpolation between order statistics. Matches Pulse's AGG_PERCENTILE convention (R-7 quantile algorithm).
func SequentialColor ¶
SequentialColor returns a color along a light-blue → dark-blue gradient for v in [min, max]. Degenerate range (min == max) returns the mid-tone anchor. P10 keeps the gradient hardcoded; theme-level sequential palettes land in P12 alongside richer color tooling.
func SkipNullRows ¶
SkipNullRows returns the indices of rows in tbl where every named field is non-null. Encoders that consume `fields` per-row use this to drop rows where any required channel is null so geometries don't render at zero positions or default colors.
The skipped count + offending field names are reported back so the caller can surface PRISM_WARN_NULL_DROPPED. See `.planning/tier1-02-hash-join-null-bitmap-plan.md`.
Types ¶
type BandScaler ¶
type BandScaler interface {
BandWidth() float64
}
BandScaler is the optional capability bar marks ask for to size rect widths. Implemented by encode.BandScale.
type BoxplotSummary ¶
type BoxplotSummary struct {
Group string
Q1 float64
Median float64
Q3 float64
Min float64
Max float64
ReachLow float64
ReachHi float64
Outliers []float64
}
BoxplotSummary holds per-group statistics computed by the boxplot encoder. Exposed for parity tests (see boxplot_parity_test.go).
func ComputeBoxplotSummaries ¶
func ComputeBoxplotSummaries(in Inputs) ([]BoxplotSummary, error)
ComputeBoxplotSummaries partitions the table by the category axis (in.X.Field) and computes q1/median/q3/min/max + whisker reach + outliers per group. Exposed so the parity test can compare summaries directly against Pulse-mapped quantiles.
type Channel ¶
Channel binds an encoding channel to a resolved Scale and the field name on the upstream table. Created by encode.Encode and handed to each mark encoder.
type ColorChannel ¶
ColorChannel binds a color encoding (categorical field + palette).
type HistogramResult ¶
type HistogramResult struct {
Marks []scene.Mark
XScale *scale.LinearScale
YScale *scale.LinearScale
BinEdges []float64
Counts []int
}
HistogramResult bundles the encoded marks with the synthetic scales the histogram encoder builds inline. The encode.go path uses XScale / YScale to build axes; standard callers via marks.Encode read only Marks. See D060.
XScale / YScale are exported as concrete *scale.LinearScale so callers can hand them to encode.BuildAxisWithOpts (which expects the richer encode.Scale interface, not the minimal marks.Scale).
func EncodeHistogram ¶
func EncodeHistogram(in Inputs) (*HistogramResult, error)
EncodeHistogram builds bins inline, counts rows per bin, then emits one RectGeom per bin. Defaults to Sturges' rule (ceil(log2(n) + 1)) for bin count; honors mark_def.maxbins when set.
Bin edges use the nice-step algorithm from compile/inmem/bin.go (duplicated here per D060; cross-package re-export was rejected to keep encode/marks dependency-free of compile/).
type Inputs ¶
type Inputs struct {
Table *table.Table
X Channel
Y Channel
Color *ColorChannel
Layout scene.Rect // the Plot region
Style scene.Style
Mark *spec.MarkDef // mark-level overrides; nil ok
Tooltip *spec.TooltipChannel // encoding.tooltip binding; nil ok
Source Channel // sankey source-node field (no scale)
Target Channel // sankey target-node field (no scale)
Value Channel // sankey flow-magnitude field (no scale)
// Feature (P18) is the geoshape feature-id binding — the table
// column whose values are geodata IDs (USA, US-CA, …).
Feature Channel
// Longitude / Latitude (P18) are geopoint bindings; field-only.
Longitude Channel
Latitude Channel
// Projection (P18) maps lon/lat → pixel space for geoshape and
// geopoint marks. Nil for non-geo marks.
Projection projection.Projection
// GeoStore (P18) is the feature-geometry source. Defaults to
// geodata.DefaultStore() at dispatch time.
GeoStore geodata.Store
// GeoTier (P18) is the manifest tier the encoder pulls features
// from. Defaults to TierWorld110m.
GeoTier geodata.Tier
// LayerID is the scene-layer identifier stamped onto every
// per-row mark's Datum back-reference (D077). Empty defaults to
// "layer-0" — matches the flat-encoder hardcoded layer ID.
// Composite callers (layer / facet / repeat) override per-cell.
LayerID string
// KeyField (animation) is the encoding-channel field name flagged
// with key:true in the spec. When non-empty, per-row marks get
// Mark.Key = "<field>=<value>" so the client-side animator can
// match marks across scene swaps. Empty (default) leaves Mark.Key
// blank; SVG and PDF renderers ignore Mark.Key either way.
KeyField string
}
Inputs carries the per-Encode-call context: table, encoded channels, layout, mark style.
Tooltip (P10) carries the encoding.tooltip binding; when non-nil, the dispatch attaches one *scene.Tooltip per produced mark via AttachTooltips (per-row marks: 1:1; single-mark types: row 0's tooltip). See D063.
Source / Target / Value (P11) carry the sankey-specific channel bindings — Field name only, no scale. See D064. Used exclusively by encodeSankey; other encoders ignore them.
type SankeyLayout ¶
type SankeyLayout struct {
Nodes []SankeyNode
Links []SankeyLink
}
SankeyLayout bundles the encoder's layout output. Exposed for the PHASE.md gate to hand-verify deterministic positions.
func ComputeSankeyLayout ¶
func ComputeSankeyLayout(in Inputs) (*SankeyLayout, error)
ComputeSankeyLayout runs the place-once layout algorithm. Exposed for the PHASE.md test gate so positions can be hand-verified.
type SankeyLink ¶
type SankeyLink struct {
Source string
Target string
Value float64
SX float64 // source-side x (right edge of source node)
SY float64 // source-side y (center of link's slice within source)
TX float64 // target-side x (left edge of target node)
TY float64 // target-side y (center of link's slice within target)
Width float64 // visual stroke width = Value * heightScale
}
SankeyLink is one link between two nodes. Source/Target are node IDs; SourceY / TargetY are the y-pixel offsets within the source and target nodes (cumulative-flow stacking).
type SankeyNode ¶
type SankeyNode struct {
ID string
Depth int
Column int
Rank int // vertical rank within column (0-based)
X float64 // top-left pixel
Y float64
W float64
H float64
Inflow float64
Outflow float64
}
SankeyNode is one node in the sankey diagram. Exposed for parity tests (TestPrismSankeyLayout in sankey_test.go).