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}Bound to an atom by compositor/composite-pose->draft while it drafts
the cells of an arrangement: leaf->draft collects there the Note for
a cell that draws nothing, in place of printing it. A blank cell beside
cells that draw is left to the Note lay-* prints when it adds a layer
on a cell of its own; the Note is printed where no cell draws.
Bound to an atom by `compositor/composite-pose->draft` while it drafts the cells of an arrangement: `leaf->draft` collects there the Note for a cell that draws nothing, in place of printing it. A blank cell beside cells that draw is left to the Note `lay-*` prints when it adds a layer on a cell of its own; the Note is printed where no cell draws.
Within one elaborate, the row-filter warnings already printed: a
composite's filter reaches every cell, and a value it misspells is
reported once rather than once per cell.
Within one `elaborate`, the row-filter warnings already printed: a composite's filter reaches every cell, and a value it misspells is reported once rather than once per cell.
(apply-track-weights pose)The composite with its :col-weights and :row-weights written as
the :weights of its layout, at every depth: the rows of cells a
vertical composite holds take the column weights, and the composite
the row weights. A horizontal composite is one row, and a vertical
one of single cells one column. The keys are then removed from the
options, so no cell reads them.
The cells are laid out in these proportions, and the composite is
aligned (compositor/drawing-tracks), so its drawing areas keep
them once the tick labels have taken their room.
The composite with its `:col-weights` and `:row-weights` written as the `:weights` of its layout, at every depth: the rows of cells a vertical composite holds take the column weights, and the composite the row weights. A horizontal composite is one row, and a vertical one of single cells one column. The keys are then removed from the options, so no cell reads them. The cells are laid out in these proportions, and the composite is aligned (`compositor/drawing-tracks`), so its drawing areas keep them once the tick labels have taken their room.
(apply-where pose)A pose whose written row filter, :where, is applied to its data:
{:where {:species "setosa"}} keeps the rows whose :species is
"setosa". Several keys must all match; a set is any of its values.
The filter is consumed, so the result carries the filtered data and
no :where. A pose with no data keeps its filter for the data it
is given later.
Numbers compare by value (same-value?). A value that appears
nowhere in its column is reported -- a misspelling, or a category the
data does not hold -- since it selects no rows; a cell generated from
the data never names one.
A cell generated from a category keeps the full data and writes its
filter, so the listed pose says that its cells split one dataset.
The spelling :where is provisional.
A pose whose written row filter, `:where`, is applied to its data:
`{:where {:species "setosa"}}` keeps the rows whose `:species` is
"setosa". Several keys must all match; a set is any of its values.
The filter is consumed, so the result carries the filtered data and
no `:where`. A pose with no data keeps its filter for the data it
is given later.
Numbers compare by value (`same-value?`). A value that appears
nowhere in its column is reported -- a misspelling, or a category the
data does not hold -- since it selects no rows; a cell generated from
the data never names one.
A cell generated from a category keeps the full data and writes its
filter, so the listed pose says that its cells split one dataset.
The spelling `:where` is provisional.(check-explicit-mapping! k v)Throw when an explicit mapping is malformed. Nothing here reads the
layer's data, which is what lets api run it at the pj/pose or
lay-* call rather than at pj/draft: a mistyped key inside the
map is a mistake about the form, and the form is fully visible
where it is written. The checks that need the data -- whether the
column is there, whether the value is one the aesthetic can draw --
stay in validate-columns.
Called both from the call site and from
normalize-explicit-mapping, so a pose built by hand and threaded
straight to pj/draft is held to the same rules.
Throw when an explicit mapping is malformed. Nothing here reads the layer's data, which is what lets `api` run it at the `pj/pose` or `lay-*` call rather than at `pj/draft`: a mistyped key inside the map is a mistake about the form, and the form is fully visible where it is written. The checks that need the data -- whether the column is there, whether the value is one the aesthetic can draw -- stay in `validate-columns`. Called both from the call site and from `normalize-explicit-mapping`, so a pose built by hand and threaded straight to `pj/draft` is held to the same rules.
(check-panel-domain! k v spec)Throw unless spec, the :scale of a panel aesthetic, is a map
holding a :domain of categories and nothing else.
:col and :row draw nothing through a scale, so they take no scale
type, range or breaks. What they share with a categorical axis and a
categorical legend is an order of categories, and the :domain that
orders those two orders the panels: the listed categories first, the
others after, in the order of the data. Called from the mapping check
and from pj/scale, so the two refuse the same things.
Throw unless `spec`, the `:scale` of a panel aesthetic, is a map holding a `:domain` of categories and nothing else. `:col` and `:row` draw nothing through a scale, so they take no scale type, range or breaks. What they share with a categorical axis and a categorical legend is an order of categories, and the `:domain` that orders those two orders the panels: the listed categories first, the others after, in the order of the data. Called from the mapping check and from `pj/scale`, so the two refuse the same things.
(check-panel-domain-key! k col domain)Throw where a :domain is specified for a panel aesthetic that
reads several columns as a compound key. A :domain lists the
categories of one column, and a compound key has a panel for each
combination of values the data holds, so the list has nothing to be
matched against. Called where the two are written together
(check-panel-mapping!) and where the panels are made
(panel-order), since a pj/scale on an outer pose meets the
facet of an inner one only there.
Throw where a `:domain` is specified for a panel aesthetic that reads several columns as a compound key. A `:domain` lists the categories of one column, and a compound key has a panel for each combination of values the data holds, so the list has nothing to be matched against. Called where the two are written together (`check-panel-mapping!`) and where the panels are made (`panel-order`), since a `pj/scale` on an outer pose meets the facet of an inner one only there.
(check-panel-mapping! k v)Throw where v, a mapping value written for the panel aesthetic k
in full, cannot be read: a :scale that is not a :domain alone
(check-panel-domain!), or a :domain beside a compound key
(check-panel-domain-key!). Called from the mapping check, from
pj/facet and from pj/scale, so the three refuse the same
things.
Throw where `v`, a mapping value written for the panel aesthetic `k` in full, cannot be read: a `:scale` that is not a `:domain` alone (`check-panel-domain!`), or a `:domain` beside a compound key (`check-panel-domain-key!`). Called from the mapping check, from `pj/facet` and from `pj/scale`, so the three refuse the same things.
(check-series! caller data m)Throw where the series written in mapping m cannot be pivoted out
of data -- the checks the pivot makes, without pivoting. Run by a
lay-* call that has the data, so the error names the call, and by
the draft before it pivots.
Throw where the series written in mapping `m` cannot be pivoted out of `data` -- the checks the pivot makes, without pivoting. Run by a `lay-*` call that has the data, so the error names the call, and by the draft before it pivots.
(check-series-leaf! leaf)Throw where the series on a leaf cannot be pivoted together with the
rest of it: two series pivoting one dataset (see leaf-series), or
the pose's own mapping naming a column the pivot consumes -- that
aesthetic would apply to the pivoted rows, which no longer hold the
column. A layer naming such a column is not refused: it reads the
data as written, before the pivot (pivot-leaf-series). Run by every
lay-* call on a leaf, so the call that makes the conflict is the
one that reports it, and by the draft.
Throw where the series on a leaf cannot be pivoted together with the rest of it: two series pivoting one dataset (see `leaf-series`), or the pose's own mapping naming a column the pivot consumes -- that aesthetic would apply to the pivoted rows, which no longer hold the column. A layer naming such a column is not refused: it reads the data as written, before the pivot (`pivot-leaf-series`). Run by every `lay-*` call on a leaf, so the call that makes the conflict is the one that reports it, and by the draft.
(check-shared-panel! leaf)Report layers of a leaf that share its one panel and disagree about what an axis holds.
The layers of a pose share its panel, so each axis is one scale for
all of them. Columns of different kinds on one axis -- a category
beside a number -- cannot be placed on one scale, and drawing them
anyway placed the numbers as category places: an error, naming the
layers and the two ways to separate panels. A count or a density
beside a column on :y can be placed, and so can a count beside a
density, but the axis then reads in two units: a Note, with the same
advice. Numeric columns of very different
size can be placed too, and one of them is then drawn flat: a Note
(note-columns-of-different-size!).
Report layers of a leaf that share its one panel and disagree about what an axis holds. The layers of a pose share its panel, so each axis is one scale for all of them. Columns of different kinds on one axis -- a category beside a number -- cannot be placed on one scale, and drawing them anyway placed the numbers as category places: an error, naming the layers and the two ways to separate panels. A count or a density beside a column on `:y` can be placed, and so can a count beside a density, but the axis then reads in two units: a Note, with the same advice. Numeric columns of very different size can be placed too, and one of them is then drawn flat: a Note (`note-columns-of-different-size!`).
(check-track-weights! k weights n what)Report a weight vector that is not one positive number for each of
the n columns or rows (what) it shares out.
Report a weight vector that is not one positive number for each of the `n` columns or rows (`what`) it shares out.
(coerce-data-in-tree pose)A pose with the :data of every pose in it a dataset. pj/pose
coerces the data it is given; a pose written as a map may hold a
plain map or rows, and the sharing of axes reads columns from
:data as a dataset -- on a plain map it found no column, and cells
asked to share an axis kept their own, with no message.
A pose with the `:data` of every pose in it a dataset. `pj/pose` coerces the data it is given; a pose written as a map may hold a plain map or rows, and the sharing of axes reads columns from `:data` as a dataset -- on a plain map it found no column, and cells asked to share an axis kept their own, with no message.
(collapse-regular-split pose)A composite whose cells are a regular split of its data, as the faceted leaf that draws it in one plan; any other pose as it is.
Regular: the composite holds the data and writes no strips or axis
titles of its own; each cell carries only a :where of single
values; and the cells keep exactly the values the data holds for the
facet columns, in the order the data holds them -- one row of cells
by :col, one column by :row, or a grid by both, with every
combination present, as expand-variation writes it. A written
:share-scales is kept in the faceted leaf's options, where the
facet plan reads it.
A composite whose cells are a regular split of its data, as the faceted leaf that draws it in one plan; any other pose as it is. Regular: the composite holds the data and writes no strips or axis titles of its own; each cell carries only a `:where` of single values; and the cells keep exactly the values the data holds for the facet columns, in the order the data holds them -- one row of cells by `:col`, one column by `:row`, or a grid by both, with every combination present, as `expand-variation` writes it. A written `:share-scales` is kept in the faceted leaf's options, where the facet plan reads it.
(combine-scales outer inner)Combine an outer scale statement with an inner one.
Scale settings accumulate down the scope chain: where both name a spec the two merge key by key, so a pose that sets a range and a layer that names a type give a plot with both. The innermost wins per key.
true and false are not specs and do not merge. false says the
value passes through no scale at all, so it replaces whatever was
set above; true says it does pass through one without saying
which, so it leaves an outer spec standing.
Combine an outer scale statement with an inner one. Scale settings accumulate down the scope chain: where both name a spec the two merge key by key, so a pose that sets a range and a layer that names a type give a plot with both. The innermost wins per key. `true` and `false` are not specs and do not merge. `false` says the value passes through no scale at all, so it replaces whatever was set above; `true` says it does pass through one without saying which, so it leaves an outer spec standing.
(composite? f)A composite pose has at least one sub-pose.
A composite pose has at least one sub-pose.
(compute-layout pose rect)(compute-layout pose [x y w h] path)Walk the pose tree and assign a pixel rectangle to each leaf. Returns a map of path -> [x y w h].
Composite :layout is {:direction :horizontal|:vertical|:matrix :weights [pos-num ...]}. Defaults: :direction :horizontal :weights (repeat n 1) (equal share)
Matrix layout (:direction :matrix) places leaves on a grid
derived from their :x / :y mappings -- distinct x-cols become
grid columns, distinct y-cols become grid rows, leaves land at
their (x, y) intersection cell. Duplicate (x, y) pairs stack
into new rows in DFS order. Empty cells get no entry. See
matrix-axes for the full algorithm and the corresponding
strip-label derivation. :weights are ignored under :matrix.
Rectangle arithmetic is in doubles; callers that need integer pixels should coerce at the render boundary (see pj/plot's width/height coercion).
Walk the pose tree and assign a pixel rectangle to each leaf.
Returns a map of path -> [x y w h].
Composite :layout is {:direction :horizontal|:vertical|:matrix
:weights [pos-num ...]}. Defaults:
:direction :horizontal
:weights (repeat n 1) (equal share)
Matrix layout (`:direction :matrix`) places leaves on a grid
derived from their :x / :y mappings -- distinct x-cols become
grid columns, distinct y-cols become grid rows, leaves land at
their (x, y) intersection cell. Duplicate (x, y) pairs stack
into new rows in DFS order. Empty cells get no entry. See
`matrix-axes` for the full algorithm and the corresponding
strip-label derivation. :weights are ignored under :matrix.
Rectangle arithmetic is in doubles; callers that need integer
pixels should coerce at the render boundary (see pj/plot's
width/height coercion).(data-category-order data cols)The values the columns cols of data hold, each once, in the order
of the rows -- the order a categorical axis and a categorical legend
list them in, whichever panel a row is drawn in. Nil where data
holds none of the columns.
The values are the data's own, which is what a legend's categories
are matched against; an axis is matched against display labels, so
its callers map defaults/fmt-category-label over the answer. One
function for the panels of a facet (leaf->draft), the cells of an
arrangement (shared-axis-groups) and the legend they share
(compositor/unify-legend-scales), because the three ask one
question.
The values the columns `cols` of `data` hold, each once, in the order of the rows -- the order a categorical axis and a categorical legend list them in, whichever panel a row is drawn in. Nil where `data` holds none of the columns. The values are the data's own, which is what a legend's categories are matched against; an axis is matched against display labels, so its callers map `defaults/fmt-category-label` over the answer. One function for the panels of a facet (`leaf->draft`), the cells of an arrangement (`shared-axis-groups`) and the legend they share (`compositor/unify-legend-scales`), because the three ask one question.
(default-mapping d)The mapping raw data gets when nothing names a column: the first
1-3 columns, as :x, :y and :color. Nil for 0 or 4+ columns.
The mapping raw data gets when nothing names a column: the first 1-3 columns, as `:x`, `:y` and `:color`. Nil for 0 or 4+ columns.
The name the key column a series invents takes when the writer does not give one. It titles the legend, so it is a word a reader can read there.
The name the key column a series invents takes when the writer does not give one. It titles the legend, so it is a word a reader can read there.
(default-share-axes composite)The axes the cells of a composite do share by default -- two or more
cells draw one column there (or count one column), and the cells of
each bucket agree on the kind of scale. Sharing is
by column, so cells reading different columns on an axis keep their
own extents, and an axis where every cell draws a column of its own
is not in the default: written out, the default changes nothing and
draws no message (warn-share-scales-without-effect!). An axis the
cells cannot share is left alone, with no message: the writer did
not ask for it.
The axes the cells of a composite do share by default -- two or more cells draw one column there (or count one column), and the cells of each bucket agree on the kind of scale. Sharing is by column, so cells reading different columns on an axis keep their own extents, and an axis where every cell draws a column of its own is not in the default: written out, the default changes nothing and draws no message (`warn-share-scales-without-effect!`). An axis the cells cannot share is left alone, with no message: the writer did not ask for it.
(elaborate pose)(elaborate pose parent-ctx)elaborate-leaf on every leaf of a pose, each read with the context
its ancestors give it, and each leaf's choices written back onto that
leaf. An ancestor's :infer layer, which reaches several leaves, is
left to the plan.
`elaborate-leaf` on every leaf of a pose, each read with the context its ancestors give it, and each leaf's choices written back onto that leaf. An ancestor's `:infer` layer, which reaches several leaves, is left to the plan.
(elaborate-leaf leaf)A leaf with the draft's choices written in. leaf carries its full
context -- a top-level leaf, or one resolve-tree resolved.
apply-where.pivot-leaf-series.infer-default-mapping.(-> data (pj/pose :a :b) (pj/lay-point :c :d)), the leaf draws
c-against-d alone and report-unread-positions! warns that
:a and :b are not drawn (teaching: pose_rules.clj, "Note on
leaf-input with other columns").read-panel-columns.:infer takes the type the data chooses for
the place it draws at.Idempotent: a second call finds nothing left to choose.
A leaf with the draft's choices written in. `leaf` carries its full context -- a top-level leaf, or one `resolve-tree` resolved. - The row filter applied -- see `apply-where`. - Series pivoted -- see `pivot-leaf-series`. - The data's default mapping, where the leaf needs one -- see `infer-default-mapping`. - A leaf with a place and no layers draws one layer, of the type the data chooses. - A column the leaf's own mapping names is drawn by the layers that name no column on that axis, and by no other: where every layer names its own, as in `(-> data (pj/pose :a :b) (pj/lay-point :c :d))`, the leaf draws c-against-d alone and `report-unread-positions!` warns that `:a` and `:b` are not drawn (teaching: `pose_rules.clj`, "Note on leaf-input with other columns"). - A layer holds the panel's columns it reads, where it names none or names one and its layer type needs two -- see `read-panel-columns`. - A layer written as `:infer` takes the type the data chooses for the place it draws at. Idempotent: a second call finds nothing left to choose.
(expand-facet-node pose panel-mapping)A leaf holding a :facet node, as the listed pose it expands to;
any other pose as it is. A part over columns of :y alone stacks its
cells down, so they share the :x axis; any other single part runs
across; :col and :row make a grid. The leaf's series is pivoted
first, as for a facet over categories.
panel-mapping is what the pose and the poses above it map :col
and :row to. An order of panels specified there with no column --
(pj/scale pose :col {:domain [..]}) written before the facet, or
on a pose above -- orders the categories of that part of the node,
where the part specifies no order of its own.
A leaf holding a `:facet` node, as the listed pose it expands to;
any other pose as it is. A part over columns of `:y` alone stacks its
cells down, so they share the `:x` axis; any other single part runs
across; `:col` and `:row` make a grid. The leaf's series is pivoted
first, as for a facet over categories.
`panel-mapping` is what the pose and the poses above it map `:col`
and `:row` to. An order of panels specified there with no column --
`(pj/scale pose :col {:domain [..]})` written before the facet, or
on a pose above -- orders the categories of that part of the node,
where the part specifies no order of its own.(expand-facet-nodes pose)(expand-facet-nodes pose inherited)(expand-facet-nodes pose inherited panel-mapping)expand-facet-node on every pose of a tree that holds a :facet
node, so a pose faceted over columns draws the same panels as a cell
of an arrangement as it does alone. A faceted cell with no data of
its own is expanded with the data it inherits, which the expansion
reads to pivot a series and to list a category's values. A series
faceted by its own key is such a pose (series-key-facet).
`expand-facet-node` on every pose of a tree that holds a `:facet` node, so a pose faceted over columns draws the same panels as a cell of an arrangement as it does alone. A faceted cell with no data of its own is expanded with the data it inherits, which the expansion reads to pivot a series and to list a category's values. A series faceted by its own key is such a pose (`series-key-facet`).
(expand-facets pose)A leaf whose mapping writes :col or :row, as the listed pose its
facet expands to: :col alone is a row of cells, :row alone a
column of them, both a grid with an empty cell for each combination
the data does not hold. The facet's
:share-scales stays where it is, on the listed pose. Any other
pose is returned as it is -- a composite, a leaf with no data of its
own, a grid naming one column on both sides, and a facet wrapped by
:grid-cols or :grid-rows, which needs a strip over each cell.
A leaf whose mapping writes `:col` or `:row`, as the listed pose its facet expands to: `:col` alone is a row of cells, `:row` alone a column of them, both a grid with an empty cell for each combination the data does not hold. The facet's `:share-scales` stays where it is, on the listed pose. Any other pose is returned as it is -- a composite, a leaf with no data of its own, a grid naming one column on both sides, and a facet wrapped by `:grid-cols` or `:grid-rows`, which needs a strip over each cell.
(expand-variation pose variation)A pose with cells generated from a variation, written as the listed pose they expand to. Provisional prototype (step 7 of the PR #61 plan; the verb and whether this is published are open).
:species -- is a category: one cell per
value the column holds, in the order the data holds them, each the
full data with a written row filter, {:where {:species v}}.{:x [:a :b]} or {:y [...]} names columns: one cell per column,
each writing its column on that axis, as pj/pose would.{:col c :row r} crosses two categories into a grid, a row per
value of r; a combination the data does not hold is a filter that
keeps no rows, which draws as an empty cell.The cells inherit the pose's data, mapping and layers, as cells of a
composite do, so they are the parts of one declared split: they share
each axis they can, and an axis they share on one column is ticked
and titled once, and each is labelled in a strip by the value its
filter keeps (share-axes, infer-chrome), as cells written by
hand would be. The expansion adds only one drawing area for the cells.
A pose with cells generated from a variation, written as the listed
pose they expand to. Provisional prototype (step 7 of the PR #61
plan; the verb and whether this is published are open).
- A column of the data -- `:species` -- is a category: one cell per
value the column holds, in the order the data holds them, each the
full data with a written row filter, `{:where {:species v}}`.
- `{:x [:a :b]}` or `{:y [...]}` names columns: one cell per column,
each writing its column on that axis, as `pj/pose` would.
- `{:col c :row r}` crosses two categories into a grid, a row per
value of `r`; a combination the data does not hold is a filter that
keeps no rows, which draws as an empty cell.
The cells inherit the pose's data, mapping and layers, as cells of a
composite do, so they are the parts of one declared split: they share
each axis they can, and an axis they share on one column is ticked
and titled once, and each is labelled in a strip by the value its
filter keeps (`share-axes`, `infer-chrome`), as cells written by
hand would be. The expansion adds only one drawing area for the cells.The keys an explicit mapping map may carry: one source, and optionally the scale to read it through.
The keys an explicit mapping map may carry: one source, and optionally the scale to read it through.
(explicit-mapping? v)True of a mapping value written in the explicit form -- a map naming
its source, as {:column :species} or {:value "red" :scale true},
or naming only a scale, as pj/scale writes.
A map is unambiguous here because no aesthetic takes one as a value: a color is a string or a keyword, a size is a number, a shape is a symbol from a fixed list.
True of a mapping value written in the explicit form -- a map naming
its source, as `{:column :species}` or `{:value "red" :scale true}`,
or naming only a scale, as `pj/scale` writes.
A map is unambiguous here because no aesthetic takes one as a value:
a color is a string or a keyword, a size is a number, a shape is a
symbol from a fixed list.(facet-columns-direction node)The direction a facet over columns with no direction of its own
places its panels in: down for columns of :y alone, so they share
the :x axis, and across otherwise.
The direction a facet over columns with no direction of its own places its panels in: down for columns of `:y` alone, so they share the `:x` axis, and across otherwise.
What joins the parts of a compound facet label. A panel faceted by several columns is labelled by each column's value in turn, and this is what stands between them.
What joins the parts of a compound facet label. A panel faceted by several columns is labelled by each column's value in turn, and this is what stands between them.
(facet-node-directions node)The directions a facet node holds a part in, nil parts left out:
[] for a facet over columns with no direction of its own.
The directions a facet node holds a part in, `nil` parts left out: `[]` for a facet over columns with no direction of its own.
(fit-layers pose)(fit-layers pose inherited)(fit-layers pose inherited data)A composite whose layers are fitted to its cells, as above. Returned unchanged where every layer fits every cell it reaches.
A layer that fits no cell because it names a column on an axis where
every cell names another (columns-no-cell-has) reports an error
where it leaves some cell with no layer drawing that cell's own
columns: the facet's column would be drawn nowhere. Beside layers
that fit every cell it is drawn in every cell, as a column shown in
each panel for comparison.
A composite whose layers are fitted to its cells, as above. Returned unchanged where every layer fits every cell it reaches. A layer that fits no cell because it names a column on an axis where every cell names another (`columns-no-cell-has`) reports an error where it leaves some cell with no layer drawing that cell's own columns: the facet's column would be drawn nowhere. Beside layers that fit every cell it is drawn in every cell, as a column shown in each panel for comparison.
(fold-facet-categories node cats)A facet node with the categories cats -- a map from :col or
:row to the mapping value a pose, or a pose above it, writes there
-- crossed into it, as the grid they draw together. Columns with no
direction of their own take the direction the categories leave.
Categories in a direction the node holds, or in both directions
beside columns with none, report an error: the panels have no
direction left for them.
Categories are kept in the mapping, where they follow the scope rules, and meet the facet over columns here, when the pose is drawn -- so a facet over categories written on an arrangement crosses a cell's facet over columns as it crosses the cell's own.
A facet node with the categories `cats` -- a map from `:col` or `:row` to the mapping value a pose, or a pose above it, writes there -- crossed into it, as the grid they draw together. Columns with no direction of their own take the direction the categories leave. Categories in a direction the node holds, or in both directions beside columns with none, report an error: the panels have no direction left for them. Categories are kept in the mapping, where they follow the scope rules, and meet the facet over columns here, when the pose is drawn -- so a facet over categories written on an arrangement crosses a cell's facet over columns as it crosses the cell's own.
(infer-chrome composite)(infer-chrome composite strip-mode)An elaborated composite with its chrome written in, where its cells
are the parts of one declared split: the once-only axis titles and
ticks (infer-axis-chrome) and the strips naming each cell's part
of the data (infer-strips); where its cells are asked to share an
axis with :share-scales, the axis titles and ticks. Anything
written is kept. strip-mode is :strip-labels (defaults/strip-text).
An elaborated composite with its chrome written in, where its cells are the parts of one declared split: the once-only axis titles and ticks (`infer-axis-chrome`) and the strips naming each cell's part of the data (`infer-strips`); where its cells are asked to share an axis with `:share-scales`, the axis titles and ticks. Anything written is kept. `strip-mode` is `:strip-labels` (`defaults/strip-text`).
(infer-default-mapping leaf)A leaf with the columns it draws filled in where nothing names them, from data of 1-3 columns.
:x or a
:y column, the data's default-mapping is written under the
leaf's own mapping, so a scale it already carries reads the
default column.(-> data pj/lay-point) colours by the third, and so do
(-> data pj/lay-point (pj/lay-smooth :a :b)) and
(-> data pj/lay-point (pj/lay-smooth :b :a)), where the smooth
keeps the columns it names and is drawn on the points' panel.
(-> data (pj/lay-point :a :b) pj/lay-smooth) reads no colour,
as (-> data (pj/lay-point :a :b)) reads none.:y is named and no :x is, and a layer's type draws
only from two columns (layer-type/column-counts lacks 1), the
leaf's :x is the first column nothing names, so
(pj/lay-point data {:y :a}) draws :a against the column before
it. A leaf with no layer, or whose layers can draw from one
column, keeps :y alone and is drawn on its side -- see
side-on -- so (pj/pose data {:y :a}) draws the same on data of
any width. A :y is never filled in: whether a layer needs one
depends on its type, and (pj/lay-bar data :x) counts.An axis a facet over columns names columns on counts as named, and
its columns as used: {:col {:x [:a :b]} :row {:y [:a :b]}} on data
of three columns draws :a and :b and no colour, as
(pj/pose data {:x :a :y :b}) does.
Returns the leaf unchanged otherwise, so it is idempotent.
A leaf with the columns it draws filled in where nothing names them,
from data of 1-3 columns.
- Where neither the leaf's mapping nor any layer names an `:x` or a
`:y` column, the data's `default-mapping` is written under the
leaf's own mapping, so a scale it already carries reads the
default column.
- The same where the first layer reads the leaf's data and names no
column, and the leaf's mapping names none, whatever the layers
after the first name. A layer added to a pose leaves the layers
before it as they were drawn: on data of three columns
`(-> data pj/lay-point)` colours by the third, and so do
`(-> data pj/lay-point (pj/lay-smooth :a :b))` and
`(-> data pj/lay-point (pj/lay-smooth :b :a))`, where the smooth
keeps the columns it names and is drawn on the points' panel.
`(-> data (pj/lay-point :a :b) pj/lay-smooth)` reads no colour,
as `(-> data (pj/lay-point :a :b))` reads none.
- Where a `:y` is named and no `:x` is, and a layer's type draws
only from two columns (`layer-type/column-counts` lacks 1), the
leaf's `:x` is the first column nothing names, so
`(pj/lay-point data {:y :a})` draws `:a` against the column before
it. A leaf with no layer, or whose layers can draw from one
column, keeps `:y` alone and is drawn on its side -- see
`side-on` -- so `(pj/pose data {:y :a})` draws the same on data of
any width. A `:y` is never filled in: whether a layer needs one
depends on its type, and `(pj/lay-bar data :x)` counts.
An axis a facet over columns names columns on counts as named, and
its columns as used: `{:col {:x [:a :b]} :row {:y [:a :b]}}` on data
of three columns draws `:a` and `:b` and no colour, as
`(pj/pose data {:x :a :y :b})` does.
Returns the leaf unchanged otherwise, so it is idempotent.(infer-nested-chrome composite)(infer-nested-chrome composite strip-mode)composite with the chrome of each composite nested below its root
written in as infer-chrome writes the root's -- a facet over
columns placed as a cell of an arrangement is drawn as it is drawn
alone: its axis titles once, its ticks on the outer cells, its
strips. A nested composite's strips and axis titles are drawn in
bands beside its block (compositor/strip-nested-titles). The cells
whose y tick labels it drops are recorded on the root
(:plotje/y-ticks-inferred-off), by their paths from the root.
`composite` with the chrome of each composite nested below its root written in as `infer-chrome` writes the root's -- a facet over columns placed as a cell of an arrangement is drawn as it is drawn alone: its axis titles once, its ticks on the outer cells, its strips. A nested composite's strips and axis titles are drawn in bands beside its block (`compositor/strip-nested-titles`). The cells whose y tick labels it drops are recorded on the root (`:plotje/y-ticks-inferred-off`), by their paths from the root.
(last-leaf-path pose)Return the path vector of the last leaf visited in left-to-right depth-first order. Nil if the pose is itself a leaf with no path context (the caller is the root leaf).
Return the path vector of the last leaf visited in left-to-right depth-first order. Nil if the pose is itself a leaf with no path context (the caller is the root leaf).
(last-matching-leaf-path pose position-mapping)Walk pose in left-to-right DFS order. Return the :path of the
last leaf whose panel's columns (leaf-place, read after the
ancestors' :mapping is merged in) match position-mapping.
Matching is strict equality: :x and "x" are different column
references. Returns nil if no leaf matches.
position-mapping may carry either or both of :x and :y; a
nil value matches a leaf whose panel has no column on that axis.
The panel's columns are the leaf's own, and on an axis its mapping
names none, those of its first layer naming one: a lay-* call
keeps its columns on its layer, so a cell built by lay-* alone
names them only there.
What a mapping names decides the match, not how it is written: a column carrying a scale names the same column as the plain form, and a mapping that names only a scale names no column at all.
Walk `pose` in left-to-right DFS order. Return the `:path` of the last leaf whose panel's columns (`leaf-place`, read after the ancestors' `:mapping` is merged in) match `position-mapping`. Matching is strict equality: `:x` and `"x"` are different column references. Returns `nil` if no leaf matches. `position-mapping` may carry either or both of `:x` and `:y`; a `nil` value matches a leaf whose panel has no column on that axis. The panel's columns are the leaf's own, and on an axis its mapping names none, those of its first layer naming one: a `lay-*` call keeps its columns on its layer, so a cell built by `lay-*` alone names them only there. What a mapping names decides the match, not how it is written: a column carrying a scale names the same column as the plain form, and a mapping that names only a scale names no column at all.
(layer-position-key leaf-mapping layer data)The place a layer draws at, as [x-source y-source] -- what decides
which panel it lands on. Nil where the layer names no place of its
own, which is what makes it draw on every panel.
Whether the layer names a place is read from its own :mapping: a
layer that names none is not choosing the leaf's, it is declining to
choose, and the two answers place it differently. The place itself is
read from the leaf's mapping merged with the layer's, so that a layer
naming one axis draws at the same place as one naming both.
The place a layer draws at, as `[x-source y-source]` -- what decides which panel it lands on. Nil where the layer names no place of its own, which is what makes it draw on every panel. Whether the layer names a place is read from its own `:mapping`: a layer that names none is not choosing the leaf's, it is declining to choose, and the two answers place it differently. The place itself is read from the leaf's mapping merged with the layer's, so that a layer naming one axis draws at the same place as one naming both.
(leaf->draft leaf)Emit a draft vector from a leaf pose. A draft has one entry per
applicable layer; each entry is a flat map carrying the merged
aesthetic mapping (pose < layer-type-info < layer), the layer's
:stat/:position/:mark as first-class siblings, each aesthetic's
resolved scale spec under its own key, and plot-level :coord
stamped from :opts. The scales come from the mapping, which is
where pj/scale writes them; only :coord is still an option.
If the leaf's :opts carry :facet-col or :facet-row, the draft is multiplied over distinct facet values. Each variant carries a filtered :data plus :facet-col / :facet-row labels that plan.clj detects to build the facet grid.
The leaf's :opts is passed through to plan/draft->plan; in particular the compositor uses :suppress-legend on grid cells.
An empty :layers vector yields one {:mark :infer ...} placeholder so downstream inference can still choose a layer type from the data.
Data precedence: layer :data > leaf :data.
:__panel-idx is the panel a draft entry belongs to, which plan.clj groups by. A leaf draws one panel -- its layers share it -- and faceting multiplies it, so the index is the facet variant.
Emit a draft vector from a leaf pose. A draft has one entry per
applicable layer; each entry is a flat map carrying the merged
aesthetic mapping (pose < layer-type-info < layer), the layer's
:stat/:position/:mark as first-class siblings, each aesthetic's
resolved scale spec under its own key, and plot-level :coord
stamped from :opts. The scales come from the mapping, which is
where `pj/scale` writes them; only :coord is still an option.
If the leaf's :opts carry :facet-col or :facet-row, the draft is
multiplied over distinct facet values. Each variant carries a
filtered :data plus :facet-col / :facet-row labels that plan.clj
detects to build the facet grid.
The leaf's :opts is passed through to plan/draft->plan; in
particular the compositor uses :suppress-legend on grid cells.
An empty :layers vector yields one {:mark :infer ...} placeholder so
downstream inference can still choose a layer type from the data.
Data precedence: layer :data > leaf :data.
:__panel-idx is the panel a draft entry belongs to, which plan.clj
groups by. A leaf draws one panel -- its layers share it -- and
faceting multiplies it, so the index is the facet variant.(leaf-at pose path)Fetch the leaf at path in pose. Returns nil if the path does
not land on a leaf.
Fetch the leaf at `path` in `pose`. Returns nil if the path does not land on a leaf.
(leaf-columns leaf)The columns a leaf draws on :x and :y on its first panel, as
{:x source :y source} with the axes it does not name left out. The
leaf's own mapping where it names an axis, and otherwise the columns
its layers name: a lay-* call keeps its columns on its layer, so a
pose built by lay-* alone names them only there.
The columns a leaf draws on `:x` and `:y` on its first panel, as
`{:x source :y source}` with the axes it does not name left out. The
leaf's own mapping where it names an axis, and otherwise the columns
its layers name: a `lay-*` call keeps its columns on its layer, so a
pose built by `lay-*` alone names them only there.(leaf-place leaf)The place a leaf draws at -- the panel's columns -- as
[x-source y-source], or nil where neither it nor any layer names
one. Decided axis by axis: the leaf's own column, and where its
mapping names none on that axis, that of the first layer naming one
there. A lay-* call keeps its columns on its layer, so a pose built
by lay-* alone names them only there. The layers of a leaf share
this one panel; separate panels come from a split or from
pj/arrange.
The place a leaf draws at -- the panel's columns -- as `[x-source y-source]`, or nil where neither it nor any layer names one. Decided axis by axis: the leaf's own column, and where its mapping names none on that axis, that of the first layer naming one there. A `lay-*` call keeps its columns on its layer, so a pose built by `lay-*` alone names them only there. The layers of a leaf share this one panel; separate panels come from a split or from `pj/arrange`.
(leaf? f)A leaf pose has no sub-poses. (An empty :poses vector also counts as leaf because it has nothing to tile.)
A leaf pose has no sub-poses. (An empty :poses vector also counts as leaf because it has nothing to tile.)
(mapping-source v)What a mapping value names, with the full form unwrapped: the
:column, the :value or the :from. A mapping that names only a
scale names no source, and answers nil.
Identity is decided on this rather than on the written value, so
that {:x {:from :a :scale ...}} and a plain {:x :a} are the same
position -- which they are, since pj/scale produces the first from
the second.
What a mapping value names, with the full form unwrapped: the
`:column`, the `:value` or the `:from`. A mapping that names only a
scale names no source, and answers nil.
Identity is decided on this rather than on the written value, so
that `{:x {:from :a :scale ...}}` and a plain `{:x :a}` are the same
position -- which they are, since `pj/scale` produces the first from
the second.(matrix-axes composite)For a composite whose layout is :matrix, walk its leaves in
DFS order and compute the grid axes:
Univariate leaves (missing :x or :y) use the no-x-key / no-y-key sentinels so they get their own grid lane.
Returns {:col-keys [...] :row-keys [...] :col-labels [...|nil] :row-labels [...|nil] :positions {path -> [col-idx row-idx]} :x-vars [...] :y-vars [...]}.
The compositor consumes :positions for rect math and the labels for strip rendering; :x-vars / :y-vars surface in plan introspection.
For a composite whose layout is `:matrix`, walk its leaves in
DFS order and compute the grid axes:
- col-key per leaf: the leaf's :x mapping. Two leaves sharing
(x, y) keep the same col-key.
- row-key per leaf: the leaf's :y mapping, with a DFS-occurrence
discriminator when (x, y) repeats. The first (a, b) gets row
b; the second (a, b) gets row [b 1]; the third [b 2]; etc.
Same column, new row in DFS order.
- col-keys / row-keys: distinct keys in order of first appearance.
- col-labels / row-labels: human-readable strings via
defaults/fmt-name; nil when only one column or one row exists
so we don't render a redundant strip header.
Univariate leaves (missing :x or :y) use the no-x-key / no-y-key
sentinels so they get their own grid lane.
Returns {:col-keys [...] :row-keys [...]
:col-labels [...|nil] :row-labels [...|nil]
:positions {path -> [col-idx row-idx]}
:x-vars [...] :y-vars [...]}.
The compositor consumes :positions for rect math and the labels
for strip rendering; :x-vars / :y-vars surface in plan introspection.(merge-mappings outer inner)Merge an outer mapping into an inner one, the way pose mappings have
always merged -- the inner value wins -- except for the scale, which
accumulates. See merge-mapping-value.
Merge an outer mapping into an inner one, the way pose mappings have always merged -- the inner value wins -- except for the scale, which accumulates. See `merge-mapping-value`.
(overlay-labels leaf)The column each layer of a panel draws where its layers disagree, as
a vector aligned with (:layers leaf), or nil where they all draw
one place.
Read for two things, which do not depend on one another. The axis is
titled by every column drawn on it, so each labelled layer is marked
for the title. And the label is the default for a layer's :color:
a layer with no :color specified takes its label as a colour and a
legend entry (default-color-layers).
Layers that disagree about a column take a panel each, and the panels name the columns. Overlaid, they share a panel and nothing names them: the marks are drawn in one colour under an axis titled after whichever layer came first, which is a picture that shows less than the writer asked for and says nothing about it.
The label is the column a layer draws where the layers disagree. Answered nil where nothing distinguishes them, which is the ordinary case of layers drawing one place.
The column each layer of a panel draws where its layers disagree, as a vector aligned with `(:layers leaf)`, or nil where they all draw one place. Read for two things, which do not depend on one another. The axis is titled by every column drawn on it, so each labelled layer is marked for the title. And the label is the default for a layer's `:color`: a layer with no `:color` specified takes its label as a colour and a legend entry (`default-color-layers`). Layers that disagree about a column take a panel each, and the panels name the columns. Overlaid, they share a panel and nothing names them: the marks are drawn in one colour under an axis titled after whichever layer came first, which is a picture that shows less than the writer asked for and says nothing about it. The label is the column a layer draws where the layers disagree. Answered nil where nothing distinguishes them, which is the ordinary case of layers drawing one place.
(panel-domain v)The :domain specified for a panel aesthetic in a mapping value, or
nil where none is.
The `:domain` specified for a panel aesthetic in a mapping value, or nil where none is.
(panel-facet-call k v)The pj/facet call that writes panel aesthetic k -- :col or
:row, or the retired :facet-col / :facet-row -- with v, as a
message shows it: (pj/facet pose :drv) across,
(pj/facet pose {:row :drv}) down. One form for both messages that
report a panel aesthetic written on a layer.
The `pj/facet` call that writes panel aesthetic `k` -- `:col` or
`:row`, or the retired `:facet-col` / `:facet-row` -- with `v`, as a
message shows it: `(pj/facet pose :drv)` across,
`(pj/facet pose {:row :drv})` down. One form for both messages that
report a panel aesthetic written on a layer.(path->update-in-path path)Translate a leaf path like [0 1] into the get-in / update-in navigation [:poses 0 :poses 1]. A root path [] translates to [].
Translate a leaf path like [0 1] into the get-in / update-in navigation [:poses 0 :poses 1]. A root path [] translates to [].
(pivot-leaf-series leaf)A leaf whose series are pivoted: the columns a series reads become a
key column and a value column, and the mapping that wrote the series
names those two instead -- the key column on :color, or on :group
where that mapping writes :color itself, so the series stay
separate marks either way.
A series on the leaf's mapping is read by every layer below it; a
series on a layer is that layer's. The pivoted data replaces the data
the series was read from: the leaf's, or the layer's own :data.
Checked first by check-series-leaf!.
A layer with no data or series of its own that names a column the
series consumes -- points on :revenue beside lines for [:revenue :cost] -- reads that column's rows of the series, in the series'
colour (read-series-column).
leaf carries its full context, as elaborate-leaf receives it.
Idempotent: a pivoted leaf names no series.
A leaf whose series are pivoted: the columns a series reads become a key column and a value column, and the mapping that wrote the series names those two instead -- the key column on `:color`, or on `:group` where that mapping writes `:color` itself, so the series stay separate marks either way. A series on the leaf's mapping is read by every layer below it; a series on a layer is that layer's. The pivoted data replaces the data the series was read from: the leaf's, or the layer's own `:data`. Checked first by `check-series-leaf!`. A layer with no data or series of its own that names a column the series consumes -- points on `:revenue` beside lines for `[:revenue :cost]` -- reads that column's rows of the series, in the series' colour (`read-series-column`). `leaf` carries its full context, as `elaborate-leaf` receives it. Idempotent: a pivoted leaf names no series.
(pivoted-series-title column scale)The title a series pivot wrote for the value column it invented --
the written columns joined, as "revenue, cost", or the writer's
own :label -- where column is that invented column and scale the
scale spec carried beside it; nil otherwise.
A message that prints a layer's columns prints this instead: the writer never wrote the invented column, and the data holds no column of that name. Read from the title until the pivot keeps the mapping as written (the transforms plan, step C).
The title a series pivot wrote for the value column it invented -- the written columns joined, as "revenue, cost", or the writer's own `:label` -- where `column` is that invented column and `scale` the scale spec carried beside it; nil otherwise. A message that prints a layer's columns prints this instead: the writer never wrote the invented column, and the data holds no column of that name. Read from the title until the pivot keeps the mapping as written (the transforms plan, step C).
(pose? x)True if x looks pose-shaped: a map carrying :layers, :poses, or a map-valued :mapping. Permissive by design -- schema-level validation lives in impl.pose-schema.
A pose carrying only a mapping draws, a layer being inferred for
it, and is completed later by api/with-data. Read as data instead
-- which is what a map with none of these keys is -- it became a
dataset whose columns were :mapping and :data, and drew that.
The :mapping value is tested rather than the key, because a dataset written as a map of columns may hold a column called :mapping. Its value is then the column, a sequence, and not a mapping.
True if x looks pose-shaped: a map carrying :layers, :poses, or a map-valued :mapping. Permissive by design -- schema-level validation lives in impl.pose-schema. A pose carrying only a mapping draws, a layer being inferred for it, and is completed later by `api/with-data`. Read as data instead -- which is what a map with none of these keys is -- it became a dataset whose columns were :mapping and :data, and drew that. The :mapping value is tested rather than the key, because a dataset written as a map of columns may hold a column called :mapping. Its value is then the column, a sequence, and not a mapping.
(position-mapping-key m)A mapping's place, as [x-source y-source], or nil where it names
neither.
A mapping's place, as `[x-source y-source]`, or nil where it names neither.
(put-scale mapping aesthetic spec)Write a scale spec into mapping for aesthetic -- what pj/scale
does.
A scale lives with the mapping it reads, so this is an update of the
mapping rather than of the pose's options. Where the aesthetic is
mapped plainly there is no room for a scale, so the value is
rewritten in the full form under :from, which says the same thing:
ask the data. Where it is not mapped here at all, the scale is
written on its own and applies to whatever source is named below.
A mapping cancelled with nil stays cancelled: an aesthetic that
draws nothing has nothing to scale. A mapping that says :scale false on this same pose is refused rather than overridden: one pose
cannot both draw a value as it stands and read it through a scale.
Write a scale spec into `mapping` for `aesthetic` -- what `pj/scale` does. A scale lives with the mapping it reads, so this is an update of the mapping rather than of the pose's options. Where the aesthetic is mapped plainly there is no room for a scale, so the value is rewritten in the full form under `:from`, which says the same thing: ask the data. Where it is not mapped here at all, the scale is written on its own and applies to whatever source is named below. A mapping cancelled with `nil` stays cancelled: an aesthetic that draws nothing has nothing to scale. A mapping that says `:scale false` on this same pose is refused rather than overridden: one pose cannot both draw a value as it stands and read it through a scale.
(report-panel-aesthetic-on-layer layer-mapping)Report a panel aesthetic written on a layer.
:row and :col send a distinction to panels, and a facet
multiplies the whole leaf rather than one layer of it, so a panel
aesthetic on a layer names a division the draft cannot build. It is
reported here rather than dropped, which is what a mapping key with
no reading used to do.
Report a panel aesthetic written on a layer. `:row` and `:col` send a distinction to panels, and a facet multiplies the whole leaf rather than one layer of it, so a panel aesthetic on a layer names a division the draft cannot build. It is reported here rather than dropped, which is what a mapping key with no reading used to do.
(report-unread-positions! pose which)Warn about an :x or :y written on a composite that no cell reads.
pj/pose writes the composite's own mapping, and a cell that maps its
own :x or :y overrides it, so without this the write changes
nothing and says nothing. The same for a leaf whose layers each name
another column there.
which is :composites or :leaves. The two are asked at different
moments: a composite once its facets are expanded, because an
expansion makes composites; a leaf as it was written, before that,
because the cells an expansion makes each hold the layers of the
whole pose, and fit-layers reports a layer that fits no cell.
Warn about an `:x` or `:y` written on a composite that no cell reads. `pj/pose` writes the composite's own mapping, and a cell that maps its own `:x` or `:y` overrides it, so without this the write changes nothing and says nothing. The same for a leaf whose layers each name another column there. `which` is `:composites` or `:leaves`. The two are asked at different moments: a composite once its facets are expanded, because an expansion makes composites; a leaf as it was written, before that, because the cells an expansion makes each hold the layers of the whole pose, and `fit-layers` reports a layer that fits no cell.
(resolve-tree pose)(resolve-tree pose parent-ctx path)Walk the pose tree top-down, merging parent context into each descendant. Returns a vector of resolved leaves; each leaf carries merged :data, :mapping, :layers, :opts, and a :path vector of indices describing its position in the tree.
Context inheritance rules:
merge-mappings).defaults/combine-options: child overrides on key
collision, and a :theme combines key by key). So a
:share-scales written on a composite reaches a
faceted leaf below that writes none, in place of
the facet's own default: under an outer
{:x :all} the facet's panels share :x only. A
facet that writes its own keeps it.Extra keys on a leaf (anything not in #{:data :mapping :layers :poses :layout :opts :share-scales}) pass through to the resolved leaf so callers can attach metadata like :path-labels from facet-style generators.
Walk the pose tree top-down, merging parent context into each
descendant. Returns a vector of resolved leaves; each leaf carries
merged :data, :mapping, :layers, :opts, and a :path vector of
indices describing its position in the tree.
Context inheritance rules:
- :data -- nearest ancestor wins (child overrides parent).
- :mapping -- merged, with child keys overriding parent keys, and
scale settings accumulating (see `merge-mappings`).
- :layers -- concatenated (ancestor layers distribute down, then
the leaf's own layers append).
- :opts -- combined (`defaults/combine-options`: child overrides on key
collision, and a `:theme` combines key by key). So a
`:share-scales` written on a composite reaches a
faceted leaf below that writes none, in place of
the facet's own default: under an outer
`{:x :all}` the facet's panels share `:x` only. A
facet that writes its own keeps it.
Extra keys on a leaf (anything not in
#{:data :mapping :layers :poses :layout :opts :share-scales})
pass through to the resolved leaf so callers can attach metadata
like :path-labels from facet-style generators.(scale-only-mapping? v)True of a mapping value that names a scale and no source -- what
pj/scale writes for an aesthetic this pose does not map. It says
how to read whatever source is named elsewhere, and where none is,
nothing is drawn and the scale is inert.
True of a mapping value that names a scale and no source -- what `pj/scale` writes for an aesthetic this pose does not map. It says how to read whatever source is named elsewhere, and where none is, nothing is drawn and the scale is inert.
The aesthetics a series may be written under. A series names the columns a mark is drawn from, so it belongs where a column goes on an axis; on an appearance aesthetic there would be nothing for the pivot to draw.
The aesthetics a series may be written under. A series names the columns a mark is drawn from, so it belongs where a column goes on an axis; on an appearance aesthetic there would be nothing for the pivot to draw.
(series-clashes cols label column-names)The columns a series reading cols, with its key column named
label, would write over in data whose columns are column-names,
as {:key <label or nil> :value <value column or nil>}.
The pivot drops the columns it reads and writes the two it invents,
so only the columns it leaves are at risk. One rule for both places
that ask: api/pivot-series reports a clash, and
report-panel-split offers a series only where there is none --
offering it where the pivot would then refuse sent a writer from one
message straight into another.
The columns a series reading `cols`, with its key column named
`label`, would write over in data whose columns are `column-names`,
as `{:key <label or nil> :value <value column or nil>}`.
The pivot drops the columns it reads and writes the two it invents,
so only the columns it leaves are at risk. One rule for both places
that ask: `api/pivot-series` reports a clash, and
`report-panel-split` offers a series only where there is none --
offering it where the pivot would then refuse sent a writer from one
message straight into another.(series-mapping v)The series a mapping value asks for, as {:cols [...] :as label}, or
nil where it asks for none.
Two spellings, one meaning. A vector of columns on a positional
aesthetic is the short one; {:series [...] :as :measure} is the
same thing written out, and the only reason to write it is to name
the key column the pivot invents.
A vector of pairs is not a series -- pj/pose reports it, naming
pj/arrange -- so a vector whose elements are themselves
sequential answers nil and is left to it.
The series a mapping value asks for, as `{:cols [...] :as label}`, or
nil where it asks for none.
Two spellings, one meaning. A vector of columns on a positional
aesthetic is the short one; `{:series [...] :as :measure}` is the
same thing written out, and the only reason to write it is to name
the key column the pivot invents.
A vector of pairs is not a series -- `pj/pose` reports it, naming
`pj/arrange` -- so a vector whose elements are themselves
sequential answers nil and is left to it.The names the two value columns take where a series on :x and a
series on :y are pivoted together as pairs. Each titles its axis,
which :x-label and :y-label rename.
The names the two value columns take where a series on `:x` and a series on `:y` are pivoted together as pairs. Each titles its axis, which `:x-label` and `:y-label` rename.
The name the value column a series invents takes. It titles the
value axis, which :x-label and :y-label already rename, so it
needs no second spelling of its own.
The name the value column a series invents takes. It titles the value axis, which `:x-label` and `:y-label` already rename, so it needs no second spelling of its own.
(series-value-columns)The columns a series pivot invents to hold the values: one for a series, one per axis for series in pairs.
The columns a series pivot invents to hold the values: one for a series, one per axis for series in pairs.
(share-axes pose)The axes a composite's cells share in some way -- the axes
share-spec names.
The axes a composite's cells share in some way -- the axes `share-spec` names.
(share-spec pose)How a composite's cells share each axis, as the map
defaults/share-scales-spec describes: the written :share-scales
(in :opts, or at the top of a hand-built composite), or -- where
none is written and the cells are the parts of one declared split --
every axis they can share, each column on its own. Read by
shared-axis-groups and by infer-chrome, so the domains and the
chrome agree.
How a composite's cells share each axis, as the map `defaults/share-scales-spec` describes: the written `:share-scales` (in `:opts`, or at the top of a hand-built composite), or -- where none is written and the cells are the parts of one declared split -- every axis they can share, each column on its own. Read by `shared-axis-groups` and by `infer-chrome`, so the domains and the chrome agree.
(shared-axis-groups root)Which cells of a pose tree share an axis with which, as
{path {axis {:group id :order [category ...]}}} for every leaf in
a group of two or more. axis there is the leaf's own -- the axis
of its mapping -- while :share-scales names the axis as drawn
(data-axis).
Each composite with a :share-scales -- written in (:opts pose) or
at the top of a hand-built composite, or inferred where its cells are
the parts of one declared split (share-spec) -- links the cells of
each of its buckets (share-buckets). Links chain: a cell whose
layers draw :a and :b on one panel is in both columns' buckets,
and a cell linked by an outer composite and by an inner one joins
the two sets, so sharing is one relation over the whole tree and
every cell of a group ends on the same domain.
A flipped cell and an upright one drawing a column along the same
direction of the page are in one bucket: a marginal on the right
names the panel's :y column on its own :x under a flip, and
follows whatever the panel's layers draw there.
:order is given where every cell of a group reads the dataset of
the composite that links it, whole or in part, and the columns the
group draws hold categories: it lists them in the order of that
dataset's rows, which is the order a shared categorical axis then
takes (plan/order-categories), as the same plot unsplit does.
The checks and warnings about a :share-scales are raised here.
Which cells of a pose tree share an axis with which, as
`{path {axis {:group id :order [category ...]}}}` for every leaf in
a group of two or more. `axis` there is the leaf's own -- the axis
of its mapping -- while `:share-scales` names the axis as drawn
(`data-axis`).
Each composite with a `:share-scales` -- written in `(:opts pose)` or
at the top of a hand-built composite, or inferred where its cells are
the parts of one declared split (`share-spec`) -- links the cells of
each of its buckets (`share-buckets`). Links chain: a cell whose
layers draw `:a` and `:b` on one panel is in both columns' buckets,
and a cell linked by an outer composite and by an inner one joins
the two sets, so sharing is one relation over the whole tree and
every cell of a group ends on the same domain.
A flipped cell and an upright one drawing a column along the same
direction of the page are in one bucket: a marginal on the right
names the panel's `:y` column on its own `:x` under a flip, and
follows whatever the panel's layers draw there.
`:order` is given where every cell of a group reads the dataset of
the composite that links it, whole or in part, and the columns the
group draws hold categories: it lists them in the order of that
dataset's rows, which is the order a shared categorical axis then
takes (`plan/order-categories`), as the same plot unsplit does.
The checks and warnings about a `:share-scales` are raised here.The three ways an explicit mapping can name its source.
:column reads the value from the layer's data and :value is the
value itself; :from is the plain reading spelled out -- ask the
data, and take whichever answer it gives, exactly as a mapping
written plainly does. :from is what lets a plain mapping carry a
:scale, since a bare :size :weight has no room for one.
The three ways an explicit mapping can name its source. `:column` reads the value from the layer's data and `:value` is the value itself; `:from` is the plain reading spelled out -- ask the data, and take whichever answer it gives, exactly as a mapping written plainly does. `:from` is what lets a plain mapping carry a `:scale`, since a bare `:size :weight` has no room for one.
(track-counts pose)How many columns and rows of cells a composite lays out:
{:n-cols :n-rows :row-lengths :rows? :direction}. A vertical
composite of rows -- as pj/arrange and a facet over columns build
them -- has a row per child; a horizontal one is one row, and a
vertical one of single cells one column.
How many columns and rows of cells a composite lays out:
`{:n-cols :n-rows :row-lengths :rows? :direction}`. A vertical
composite of rows -- as `pj/arrange` and a facet over columns build
them -- has a row per child; a horizontal one is one row, and a
vertical one of single cells one column.The plot options that share out a composite's columns and rows of
panels. Each is read on the composite it is written on and reaches
none of its cells (apply-track-weights).
The plot options that share out a composite's columns and rows of panels. Each is read on the composite it is written on and reaches none of its cells (`apply-track-weights`).
(unanimous-column leaves axis)The column every cell of leaves draws along axis of the page, or
nil where they do not all draw the same one. Cells left empty do not
vote. Read along the page (data-axis), as the sharing is, because
the title it decides is drawn there: under a flip the column on a
cell's :y is titled along the bottom.
The column every cell of `leaves` draws along `axis` of the page, or nil where they do not all draw the same one. Cells left empty do not vote. Read along the page (`data-axis`), as the sharing is, because the title it decides is drawn there: under a flip the column on a cell's `:y` is titled along the bottom.
(unread-positions pose)The :x and :y that a composite in pose's tree writes in its own
:mapping and that no leaf below reads, because each leaf, or a pose
between, writes its own -- on its mapping, or on every one of its
layers, which is where a lay-* call naming columns keeps them.
Returns [[path k] ...], path the composite's :poses indices from
the root.
The `:x` and `:y` that a composite in `pose`'s tree writes in its own `:mapping` and that no leaf below reads, because each leaf, or a pose between, writes its own -- on its mapping, or on every one of its layers, which is where a `lay-*` call naming columns keeps them. Returns `[[path k] ...]`, `path` the composite's `:poses` indices from the root.
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 |