Draft-to-plan pipeline: domains, ticks, legends, layout, and grid inference. Takes draft maps (from pose/leaf->draft) and produces a Plan record with all geometry needed for rendering.
Draft-to-plan pipeline: domains, ticks, legends, layout, and grid inference. Takes draft maps (from pose/leaf->draft) and produces a Plan record with all geometry needed for rendering.
Where a composite collects its cells' unread-option warnings, as an
atom of one set of lines per plan. Nil for a plot on its own, which
prints them. A composite's options reach every cell, so a cell that
draws no legend would warn about a :color-label its neighbour's
legend reads; compositor/composite-draft->plan prints only the
lines every cell raised.
Where a composite collects its cells' unread-option warnings, as an atom of one set of lines per plan. Nil for a plot on its own, which prints them. A composite's options reach every cell, so a cell that draws no legend would warn about a `:color-label` its neighbour's legend reads; `compositor/composite-draft->plan` prints only the lines every cell raised.
(collect-domain stat-results axis-key scale-spec padding temporal?)(collect-domain stat-results axis-key scale-spec padding temporal? shared)(collect-domain stat-results
axis-key
scale-spec
padding
temporal?
shared
baseline)Collect and merge domains from stat results along axis-key.
The parse and the categorical axis's reading of a number live in
parse-axis-domains, which the y axis reads too.
padding is the resolved :domain-padding. temporal? says the
axis reads dates, which is what lets :include be written as one.
shared is the extent :share-scales computed across the cells of
a composite, or nil. It stands in for the extent this panel's own
values give, and is then padded and anchored as that extent would
be -- so a cell in a shared composite is padded exactly as it is
alone, and every cell reaches the same padded domain because they
start from the same shared extent. On a categorical axis it is the
categories of every sharing cell, in the order the axis holds them,
and this panel's own follow where it holds any other.
baseline is the values a mark on this axis is measured from --
[0.0] for bars drawn across, whose values run along :x
(baseline-along-x?) -- or nil. The :y axis reads its own in
compute-global-y-domain.
Collect and merge domains from stat results along axis-key. The parse and the categorical axis's reading of a number live in `parse-axis-domains`, which the y axis reads too. `padding` is the resolved `:domain-padding`. `temporal?` says the axis reads dates, which is what lets `:include` be written as one. `shared` is the extent `:share-scales` computed across the cells of a composite, or nil. It stands in for the extent this panel's own values give, and is then padded and anchored as that extent would be -- so a cell in a shared composite is padded exactly as it is alone, and every cell reaches the same padded domain because they start from the same shared extent. On a categorical axis it is the categories of every sharing cell, in the order the axis holds them, and this panel's own follow where it holds any other. `baseline` is the values a mark on this axis is measured from -- `[0.0]` for bars drawn across, whose values run along `:x` (`baseline-along-x?`) -- or nil. The `:y` axis reads its own in `compute-global-y-domain`.
(compute-global-y-domain plan-layers scale-spec padding temporal?)(compute-global-y-domain plan-layers scale-spec padding temporal? shared)Compute global y-domain from position-adjusted layers. Reads pre-computed :y0/:y1 from stacked layers. Extends domain to include 0 for marks that draw from a zero baseline (bar, area, lollipop) on linear scales. On log scales, baseline extension is skipped -- the lower bound is the smallest positive value the layers report -- because log scales have no zero.
padding is the resolved :domain-padding. temporal? says the
axis reads dates, for :include.
shared is the extent :share-scales computed across the cells of
a composite, or nil, and stands in for the extent this panel's own
layers give -- see collect-domain. A :fill axis is left alone:
it is normalized to 0 to 1 and reads no column extent at all.
Compute global y-domain from position-adjusted layers. Reads pre-computed :y0/:y1 from stacked layers. Extends domain to include 0 for marks that draw from a zero baseline (bar, area, lollipop) on linear scales. On log scales, baseline extension is skipped -- the lower bound is the smallest positive value the layers report -- because log scales have no zero. `padding` is the resolved `:domain-padding`. `temporal?` says the axis reads dates, for `:include`. `shared` is the extent `:share-scales` computed across the cells of a composite, or nil, and stands in for the extent this panel's own layers give -- see `collect-domain`. A `:fill` axis is left alone: it is normalized to 0 to 1 and reads no column extent at all.
(compute-ticks domain pixel-range scale-spec spacing)(compute-ticks domain pixel-range scale-spec spacing temporal-extent)(compute-ticks domain pixel-range scale-spec spacing temporal-extent separators)(compute-ticks domain
pixel-range
scale-spec
spacing
temporal-extent
separators
whole?)(compute-ticks domain
pixel-range
scale-spec
spacing
temporal-extent
separators
whole?
stacked?)Compute tick values and labels for a domain+pixel range, using wadogo transiently.
When temporal-extent is provided (a [min max] pair of temporal objects),
uses wadogo :datetime scale for calendar-aware ticks and formatting.
When scale-spec contains :breaks (a vector of numbers), those
exact values are used as ticks instead of the auto-computed ones
-- ggplot2's scale_*_continuous(breaks = ...) equivalent. When
scale-spec also contains :tick-labels (a vector of strings), those
replace the auto-formatted labels at the corresponding break
positions.
whole? says whether every value the domain came from is a whole
number. It cannot be read off the domain, which arrives padded: a
whole 40 to 60 reaches here as 39 to 61. A numeric axis whose values
are whole is ticked at whole numbers rather than at the halves
wadogo picks when the span is small and the count asked for is not.
On a categorical axis, :breaks selects which categories get a tick
(ggplot2's discrete breaks): each break is matched to a category by
its displayed label, unmatched breaks are dropped with a warning, and
:tick-labels relabels the kept ticks. Explicit :breaks take precedence
over :n-ticks -- when both are given, the exact breaks win and no
thinning is applied.
Compute tick values and labels for a domain+pixel range, using wadogo transiently. When temporal-extent is provided (a [min max] pair of temporal objects), uses wadogo :datetime scale for calendar-aware ticks and formatting. When `scale-spec` contains `:breaks` (a vector of numbers), those exact values are used as ticks instead of the auto-computed ones -- ggplot2's `scale_*_continuous(breaks = ...)` equivalent. When `scale-spec` also contains `:tick-labels` (a vector of strings), those replace the auto-formatted labels at the corresponding break positions. `whole?` says whether every value the domain came from is a whole number. It cannot be read off the domain, which arrives padded: a whole 40 to 60 reaches here as 39 to 61. A numeric axis whose values are whole is ticked at whole numbers rather than at the halves wadogo picks when the span is small and the count asked for is not. On a categorical axis, `:breaks` selects which categories get a tick (ggplot2's discrete `breaks`): each break is matched to a category by its displayed label, unmatched breaks are dropped with a warning, and `:tick-labels` relabels the kept ticks. Explicit `:breaks` take precedence over `:n-ticks` -- when both are given, the exact breaks win and no thinning is applied.
(draft->extents draft opts)What a draft's panels draw on each axis, as {:x e :y e} in data
order -- a low and a high for a numeric axis, the categories for a
categorical one -- unpadded, and reaching whatever the marks are
measured from. The stats run, so this is what is drawn and not what
the columns hold: the top of a stack, the ends of an error bar, a
count. Nothing is printed. compositor/composite-draft->plan asks
this of every cell sharing an axis, pools the answers, and plans
each cell with the pooled extent.
What a draft's panels draw on each axis, as `{:x e :y e}` in data
order -- a low and a high for a numeric axis, the categories for a
categorical one -- unpadded, and reaching whatever the marks are
measured from. The stats run, so this is what is drawn and not what
the columns hold: the top of a stack, the ends of an error bar, a
count. Nothing is printed. `compositor/composite-draft->plan` asks
this of every cell sharing an axis, pools the answers, and plans
each cell with the pooled extent.(draft->plan draft)(draft->plan draft
{:keys [x-label y-label title subtitle caption scales
legend-position grid-cols grid-rows]
:as opts})Pipeline: convert a draft into a plan using panel-based grid layout. Grid position from structural columns.
New layout pipeline (2026-04-11): stats first, then scene -> padding ->
dimensions, then per-panel ticks at the now-known panel dimensions.
:width/:height are total SVG dimensions; panel dimensions are
derived by subtracting layout overhead. :panel-width/:panel-height
in opts are escape hatches that pin panel size on their axis.
Pipeline: convert a draft into a plan using panel-based grid layout. Grid position from structural columns. New layout pipeline (2026-04-11): stats first, then scene -> padding -> dimensions, then per-panel ticks at the now-known panel dimensions. `:width`/`:height` are total SVG dimensions; panel dimensions are derived by subtracting layout overhead. `:panel-width`/`:panel-height` in opts are escape hatches that pin panel size on their axis.
(order-categories categories data-order)categories in the order data-order lists them, the ones it does
not list after, as they came. data-order is the categories in the
order of the rows of the dataset the sharing panels all read, or nil
where they read no one dataset.
Panels sharing a categorical axis pool their categories panel by
panel, which is the order of the panels and not of the data: bars of
:class split by :drv listed the first panel's classes, then what
the second added. Ordered by the data, the split has the axis of the
same plot unsplit, whatever order its panels come in.
`categories` in the order `data-order` lists them, the ones it does not list after, as they came. `data-order` is the categories in the order of the rows of the dataset the sharing panels all read, or nil where they read no one dataset. Panels sharing a categorical axis pool their categories panel by panel, which is the order of the panels and not of the data: bars of `:class` split by `:drv` listed the first panel's classes, then what the second added. Ordered by the data, the split has the axis of the same plot unsplit, whatever order its panels come in.
(order-categories-by category-of items data-order)items in the order data-order lists the category (category-of item) names, the ones it does not list after, as they came. See
order-categories, which is this with the items the categories
themselves.
`items` in the order `data-order` lists the category `(category-of item)` names, the ones it does not list after, as they came. See `order-categories`, which is this with the items the categories themselves.
(pool-extents extents)One extent from the extents several panels draw on an axis: the
lowest low and the highest high of numeric ones, the categories of
categorical ones in the order they come. Nil where there is none.
Panels holding numbers beside panels holding categories cannot be
pooled, and the caller says so in its own terms: this answers
::mixed for them.
One extent from the extents several panels draw on an axis: the lowest low and the highest high of numeric ones, the categories of categorical ones in the order they come. Nil where there is none. Panels holding numbers beside panels holding categories cannot be pooled, and the caller says so in its own terms: this answers `::mixed` for them.
(resolve-panel-draft-layers panel-draft-layers
all-colors
cfg
&
{:keys [resolved shape-map extents]})Resolve draft layers and compute stats for a group of draft layers belonging to one panel.
If pre-resolved draft layers are provided, skips resolve-draft-layer.
:shape-map is the plot-wide category-to-symbol assignment, carried
onto every layer so the marks draw the symbols the legend advertises.
:extents is the plot-wide [lo hi] per continuous appearance
aesthetic, carried the same way and for the same reason: a mark is
scaled against every value the plot holds rather than against its
own layer or its own panel, so the swatch beside a value is the
quantity a mark of that value is drawn at wherever it sits.
Returns {:resolved [...] :stat-results [...] :layers [...]}.
Resolve draft layers and compute stats for a group of draft layers belonging to one panel.
If pre-resolved draft layers are provided, skips resolve-draft-layer.
`:shape-map` is the plot-wide category-to-symbol assignment, carried
onto every layer so the marks draw the symbols the legend advertises.
`:extents` is the plot-wide `[lo hi]` per continuous appearance
aesthetic, carried the same way and for the same reason: a mark is
scaled against every value the plot holds rather than against its
own layer or its own panel, so the swatch beside a value is the
quantity a mark of that value is drawn at wherever it sits.
Returns {:resolved [...] :stat-results [...] :layers [...]}.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |