Liking cljdoc? Tell your friends :D

scicloj.plotje.impl.compositor

Composite-pose chrome layout, composite-pose->draft, and composite-draft->plan. Pure data-side: shared-scale reconciliation, chrome geometry computation, per-leaf opt adjustment. The plan-to-membrane rendering for composites lives in render/composite.clj, keeping this namespace free of membrane dependencies.

Shared scales are reconciled before drafting by stamping a forced domain on matching leaves (impl.pose/inject-shared-scales).

When the composite root carries a legend-producing mapping (:color/:size/:alpha), the chrome reserves a strip on the right of the grid; the per-leaf opts get :suppress-legend true so each cell hides its own legend, and the rendering side (render/ composite.clj) draws ONE shared legend in the reserved strip.

Composite-pose chrome layout, composite-pose->draft, and
composite-draft->plan. Pure data-side: shared-scale reconciliation,
chrome geometry computation, per-leaf opt adjustment. The
plan-to-membrane rendering for composites lives in
`render/composite.clj`, keeping this namespace free of membrane
dependencies.

Shared scales are reconciled before drafting by stamping a forced
domain on matching leaves (impl.pose/inject-shared-scales).

When the composite root carries a legend-producing mapping
(:color/:size/:alpha), the chrome reserves a strip on the right
of the grid; the per-leaf opts get :suppress-legend true so each
cell hides its own legend, and the rendering side (render/
composite.clj) draws ONE shared legend in the reserved strip.
raw docstring

scicloj.plotje.impl.draft-schema

Malli schemas for the draft data model -- the records returned by pj/pose->draft (and pj/draft).

Drafts are the intermediate stage between pose and plan. They are user-observable (the pj/draft shortcut and the predicates pj/leaf-draft? / pj/composite-draft? are public) but are primarily inspected, not traversed programmatically. The schemas here document the top-level structure -- the keys on the records themselves -- without enumerating every key a layer map may carry. That post-scope-merge layer shape would essentially duplicate the pose mapping schema in a different state, and the drift risk would outweigh the documentation value.

Backend authors who consume drafts directly should rely on destructuring :layers and :opts on a leaf draft, or :sub-drafts / :chrome-spec / :layout on a composite, and apply the layer-type registry to interpret each layer's :layer-type, :mark, and :stat.

Malli schemas for the draft data model -- the records returned by
`pj/pose->draft` (and `pj/draft`).

Drafts are the intermediate stage between pose and plan. They are
user-observable (the `pj/draft` shortcut and the predicates
`pj/leaf-draft?` / `pj/composite-draft?` are public) but are
primarily inspected, not traversed programmatically. The schemas
here document the top-level structure -- the keys on the records
themselves -- without enumerating every key a layer map may carry.
That post-scope-merge layer shape would essentially duplicate the
pose mapping schema in a different state, and the drift risk
would outweigh the documentation value.

Backend authors who consume drafts directly should rely on
destructuring `:layers` and `:opts` on a leaf draft, or
`:sub-drafts` / `:chrome-spec` / `:layout` on a composite, and
apply the layer-type registry to interpret each layer's
`:layer-type`, `:mark`, and `:stat`.
raw docstring

scicloj.plotje.impl.extract

Extract data-space geometry from resolved draft layers and stat results. Produces layer descriptor maps — plain Clojure maps with mark type, style, and groups of data-space coordinates.

Extract data-space geometry from resolved draft layers and stat results.
Produces layer descriptor maps — plain Clojure maps with mark type,
style, and groups of data-space coordinates.
raw docstring

scicloj.plotje.impl.layout

Layout inference pipeline. Three pure functions turn scene facts and configuration into concrete pixel dimensions.

Under the new semantics, :width and :height in opts mean the TOTAL SVG dimensions. Panel dimensions are derived by subtracting layout overhead (titles, axis labels, legends, facet strips) from the total. :panel-width/:panel-height are escape hatches: when set, they pin the panel size on that axis and :width/:height become the derived total.

The classic width→tick-count→label-width→y-label-pad→panel-width cycle is broken by a single reformulation: max-label-pixel-width runs the tick picker at a pixel budget equal to the user-supplied :height (or :width), not the actual panel size. Label width is monotonic non-decreasing in tick count across every scale type we support (verified at the REPL), so this over-estimate is always safe.

Pipeline:

compute-scene scene data from resolved draft layers + opts (no pixels) compute-padding scene + cfg + opts -> padding map (no pixel dims yet) compute-dims scene + padding + cfg + opts -> pw/ph/total-w/total-h

None of these need actual per-panel tick positions -- the tick budget is baked into y-label-pad in compute-padding via the over-estimate trick. Real per-panel ticks are computed AFTER compute-dims when the final pw/ph are known.

Layout inference pipeline. Three pure functions turn scene facts
and configuration into concrete pixel dimensions.

Under the new semantics, `:width` and `:height` in opts mean the
TOTAL SVG dimensions. Panel dimensions are derived by subtracting
layout overhead (titles, axis labels, legends, facet strips) from
the total. `:panel-width`/`:panel-height` are escape hatches: when
set, they pin the panel size on that axis and `:width`/`:height`
become the derived total.

The classic width→tick-count→label-width→y-label-pad→panel-width
cycle is broken by a single reformulation: `max-label-pixel-width`
runs the tick picker at a pixel budget equal to the user-supplied
`:height` (or `:width`), not the actual panel size. Label width is
monotonic non-decreasing in tick count across every scale type we
support (verified at the REPL), so this over-estimate is always safe.

Pipeline:

  compute-scene    scene data from resolved draft layers + opts (no pixels)
  compute-padding  scene + cfg + opts -> padding map (no pixel dims yet)
  compute-dims     scene + padding + cfg + opts -> pw/ph/total-w/total-h

None of these need actual per-panel tick positions -- the tick
budget is baked into y-label-pad in `compute-padding` via the
over-estimate trick. Real per-panel ticks are computed AFTER
`compute-dims` when the final pw/ph are known.
raw docstring

scicloj.plotje.impl.membrane-schema

Malli schema for the metadata Plotje stamps onto the vector returned by plan->membrane (and so by pj/membrane).

The vector itself is a Membrane drawable tree -- a sequence of things satisfying membrane.ui/IOrigin. That structural contract belongs to Membrane (see membrane.ui protocols) and is not modeled here. This schema is strictly Plotje's own contract: the keys we attach as metadata so that membrane->plot defmethods (and any third-party backend) can read plan-derived dimensions and title without re-walking the tree.

Malli schema for the metadata Plotje stamps onto the vector
returned by `plan->membrane` (and so by `pj/membrane`).

The vector itself is a Membrane drawable tree -- a sequence of
things satisfying `membrane.ui/IOrigin`. That structural contract
belongs to Membrane (see `membrane.ui` protocols) and is not
modeled here. This schema is strictly Plotje's own contract: the
keys we attach as metadata so that `membrane->plot` defmethods
(and any third-party backend) can read plan-derived dimensions
and title without re-walking the tree.
raw docstring

scicloj.plotje.impl.plan

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.
raw docstring

scicloj.plotje.impl.pose

Pose substrate -- the recursive plain-map type that is the library's spec vocabulary. This namespace holds the pure tree operations (resolve, layout, shared-scale injection) and the leaf->draft emitter that feeds plan.clj.

Shape of a pose: {:data ? dataset (inherited from ancestor if absent) :mapping ? aesthetic mappings (merges with ancestors) :layers ? layers at this level (accumulate into leaves) :poses ? sub-poses; absence = leaf :layout ? {:direction :horizontal|:vertical :weights [pos-num ...]} :opts ? plot options (inheritable) :share-scales ? #{:x :y} for composites}

Pose substrate -- the recursive plain-map type that is the
library's spec vocabulary. This namespace holds the pure tree
operations (resolve, layout, shared-scale injection) and the
leaf->draft emitter that feeds plan.clj.

Shape of a pose:
  {:data         ?  dataset (inherited from ancestor if absent)
   :mapping      ?  aesthetic mappings (merges with ancestors)
   :layers       ?  layers at this level (accumulate into leaves)
   :poses       ?  sub-poses; absence = leaf
   :layout       ?  {:direction :horizontal|:vertical
                     :weights   [pos-num ...]}
   :opts         ?  plot options (inheritable)
   :share-scales ?  #{:x :y}  for composites}
raw docstring

scicloj.plotje.impl.pose-schema

Malli schema for the Pose data model.

A pose is a plain recursive map. A leaf pose has no :poses (or an empty :poses vector). A composite pose has :poses and an optional :layout describing how sub-poses tile a bounding rectangle.

Validation is not wired into any runtime path yet; Phase 6 of the pre-alpha refactor adds validation at public API boundaries. Until then, impl.pose operates on structurally-valid poses by convention; this schema is the authoritative definition of that convention.

Decisions made in Phase 2:

  • A leaf with no :data and no :mapping is valid -- leaves inherit context from ancestors via impl.pose/resolve-tree.
  • :share-scales is structurally allowed on any pose; it is a no-op on leaves (nothing to share).
  • :layout :weights length is not required to equal (count :poses); impl.pose/compute-layout tolerates short/long weight vectors.
Malli schema for the Pose data model.

A pose is a plain recursive map. A leaf pose has no :poses (or
an empty :poses vector). A composite pose has :poses and an
optional :layout describing how sub-poses tile a bounding
rectangle.

Validation is not wired into any runtime path yet; Phase 6 of the
pre-alpha refactor adds validation at public API boundaries. Until
then, impl.pose operates on structurally-valid poses by convention;
this schema is the authoritative definition of that convention.

Decisions made in Phase 2:
- A leaf with no :data and no :mapping is valid -- leaves inherit
  context from ancestors via impl.pose/resolve-tree.
- :share-scales is structurally allowed on any pose; it is a no-op
  on leaves (nothing to share).
- :layout :weights length is not required to equal (count :poses);
  impl.pose/compute-layout tolerates short/long weight vectors.
raw docstring

scicloj.plotje.impl.position

Position adjustment — composable transforms on layer descriptors. Runs between extract-layer and build-panels in the plan pipeline.

Position types: :identity — no adjustment (default) :dodge — side-by-side within a categorical band (annotation) :stack — cumulative y-values across groups (data transform) :fill — normalized cumulative y, sums to 1.0 (data transform)

Position adjustment — composable transforms on layer descriptors.
Runs between extract-layer and build-panels in the plan pipeline.

Position types:
  :identity — no adjustment (default)
  :dodge    — side-by-side within a categorical band (annotation)
  :stack    — cumulative y-values across groups (data transform)
  :fill     — normalized cumulative y, sums to 1.0 (data transform)
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close