11 Glossary
Key terms used throughout Plotje, with brief definitions and code examples.
(ns plotje-book.glossary
(:require
;; Rdatasets -- standard datasets
[scicloj.metamorph.ml.rdatasets :as rdatasets]
;; Kindly -- notebook rendering protocol
[scicloj.kindly.v4.kind :as kind]
;; Plotje -- composable plotting
[scicloj.plotje.api :as pj]
;; clojure2d -- color palettes and gradients
[clojure2d.color :as c2d]))Pose
A pose is the composable value in Plotje. A leaf pose describes one plot panel; a composite pose contains sub-poses arranged together. Every function in the API (pj/pose, pj/lay-*, pj/facet, pj/arrange, pj/options, pj/scale, pj/coord) takes a pose and returns a pose. Poses auto-render in Kindly-compatible tools like Clay.
(def my-pose
(-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width {:color :species})
(pj/options {:title "Iris"})))my-poseA pose is a plain Clojure value – inspect it with kind/pprint or reach into its fields directly.
Leaf Pose
A leaf pose is a pose that describes a single plot panel. It carries :data, a :mapping from columns to aesthetics, and :layers – the chart-type layers attached to it. Created by pj/pose or pj/lay-*.
Composite Pose
A composite pose is a pose that contains other poses under :poses plus an optional :layout. Created by pj/arrange. Its leaves render independently and are tiled into the final plot.
Some features are not yet exposed through pj/arrange – unequal weights, nested poses, and cross-sibling shared scales. To use them, build the composite as a literal map; pj/pose accepts the literal form.
Arrange
pj/arrange builds a composite pose from a sequence of poses. Each input pose becomes a sub-pose; the result is a composite that tiles them via :layout (direction and optional weights). For features pj/arrange does not yet expose – nested composites or :share-scales – pass a literal map to pj/pose.
Layer Type
A layer type is the bundle of mark + stat + position that determines how data becomes a visual element. See the Layer Types chapter for detailed tables of all built-in layer types, marks, stats, and positions.
Layer types attach to poses in three ways, depending on what you pass to pj/lay-*:
Bare –
pj/lay-*without columns attaches the layer so it sees the current pose’s mapping (inherited frompj/poseor a priorpj/lay-*).Matching columns –
pj/lay-*with columns that match the most recent matching leaf reuses that leaf, so the new layer joins the existing panel.Non-matching columns –
pj/lay-*with columns that do not match any existing leaf creates a fresh leaf pose with the layer attached.
Mark
The mark is the visual shape shown for each data point or group. Several layer types may share the same mark – for instance, :line and :smooth both produce lines, and :area and :density both produce filled regions. See the Layer Types chapter for a table of all built-in marks.
Stat
A stat (statistical transform) processes raw data before rendering. Each stat takes data-space inputs and produces the geometry that its mark will show. See the Layer Types chapter for a table of all built-in stats.
Position
A position adjustment determines how groups share a categorical axis slot. Position runs between stat computation and rendering. You can override the default position by passing :position in the layer options. When multiple layers share :position :dodge, they are coordinated together – error bars automatically align with bars. See the Layer Types chapter for a table of all built-in positions.
(def tips {:day ["Mon" "Mon" "Tue" "Tue"]
:count [30 20 45 15]
:meal ["lunch" "dinner" "lunch" "dinner"]})(-> tips
(pj/lay-value-bar :day :count {:color :meal :position :stack})
pj/plan
(get-in [:panels 0 :layers 0 :groups 1 :y0s]))[30.0 45.0]Draft
A draft is a vector of flat maps produced by pj/draft. Each applicable layer in a pose resolves to one draft element by merging the pose and layer mappings. Draft elements carry all the information the pipeline needs: data, columns, mark, stat, color, grouping.
pj/draft is useful for inspecting exactly what the renderer will consume before any domains, ticks, or coordinate math are computed.
(-> my-pose pj/draft kind/pprint)[{:x :sepal-length,
:y :sepal-width,
:mark :point,
:stat :identity,
:layer-type :point,
:color :species,
:data
https://vincentarelbundock.github.io/Rdatasets/csv/datasets/iris.csv [150 6]:
| :rownames | :sepal-length | :sepal-width | :petal-length | :petal-width | :species |
|----------:|--------------:|-------------:|--------------:|-------------:|-----------|
| 1 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
| 2 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
| 3 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
| 4 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
| 5 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
| 6 | 5.4 | 3.9 | 1.7 | 0.4 | setosa |
| 7 | 4.6 | 3.4 | 1.4 | 0.3 | setosa |
| 8 | 5.0 | 3.4 | 1.5 | 0.2 | setosa |
| 9 | 4.4 | 2.9 | 1.4 | 0.2 | setosa |
| 10 | 4.9 | 3.1 | 1.5 | 0.1 | setosa |
| ... | ... | ... | ... | ... | ... |
| 140 | 6.9 | 3.1 | 5.4 | 2.1 | virginica |
| 141 | 6.7 | 3.1 | 5.6 | 2.4 | virginica |
| 142 | 6.9 | 3.1 | 5.1 | 2.3 | virginica |
| 143 | 5.8 | 2.7 | 5.1 | 1.9 | virginica |
| 144 | 6.8 | 3.2 | 5.9 | 2.3 | virginica |
| 145 | 6.7 | 3.3 | 5.7 | 2.5 | virginica |
| 146 | 6.7 | 3.0 | 5.2 | 2.3 | virginica |
| 147 | 6.3 | 2.5 | 5.0 | 1.9 | virginica |
| 148 | 6.5 | 3.0 | 5.2 | 2.0 | virginica |
| 149 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
| 150 | 5.9 | 3.0 | 5.1 | 1.8 | virginica |
,
:__panel-idx 0}]Mapping
A mapping is a binding from a column (or literal value) to an aesthetic. Mappings live on a pose – where they flow into every layer attached to it – or on a single layer, where they scope to that layer alone. Lower scope wins on conflict; an explicit nil cancels a mapping inherited from above.
Aesthetic
An aesthetic is a visual property of a mark that can be mapped to a data column. Plotje supports these aesthetic mappings:
| Key | Controls | Column type |
|---|---|---|
:color |
Fill/stroke color | Categorical or numerical |
:size |
Point radius | Numerical |
:alpha |
Opacity | Numerical |
:shape |
Point shape | Categorical |
:text |
Label content | Any |
:fill |
Tile gradient color | Numerical |
When a keyword is passed, it maps to a dataset column. A literal value (e.g., "#E74C3C", "red", 0.5) sets a fixed aesthetic for all points.
(merge (pj/layer-type-lookup :point) {:color :species :size :petal-length :alpha 0.7}){:mark :point,
:stat :identity,
:accepts [:size :shape :jitter :text :nudge-x :nudge-y],
:doc "Scatter — individual data points.",
:color :species,
:size :petal-length,
:alpha 0.7}Group
A group is a subset of data that is processed and rendered together. Mapping :color to a categorical column automatically creates groups – one per unique value. You can also create groups without color using the :group key.
(-> (rdatasets/datasets-iris)
(pj/lay-line :sepal-length :sepal-width {:group :species})
pj/plan
(get-in [:panels 0 :layers 0 :groups])
count)3Nudge
A nudge shifts data coordinates by a constant offset. It is orthogonal to position – you can nudge within a dodge, or nudge at identity. Applied via :nudge-x and :nudge-y keys in the layer options.
(-> {:x [1 2 3] :y [4 5 6]}
(pj/lay-point :x :y {:nudge-x 0.5})
pj/plan
(get-in [:panels 0 :layers 0 :groups 0 :xs]))[1.5 2.5 3.5]Jitter
Jitter adds random offsets in drawing units to reduce overplotting. Unlike position and nudge, jitter operates after scaling (not in data space) and is deterministic – seeded by a hash of the group’s color so repeated renders produce identical output.
On categorical x-axes, jitter is applied along the band axis only.
(merge (pj/layer-type-lookup :point) {:jitter true}){:mark :point,
:stat :identity,
:accepts [:size :shape :jitter :text :nudge-x :nudge-y],
:doc "Scatter — individual data points.",
:jitter true}Inference
Inference is the automatic selection of a layer type (mark + stat + position) when you bypass pj/lay-* and just pass columns to pj/pose. Plotje picks a layer type based on column types: numerical x and y defaults to :point, categorical x with numerical y to :boxplot, a single numerical column to :histogram, and so on. Use :x-type / :y-type on a pose or layer to override the detected type.
(-> (rdatasets/datasets-iris)
(pj/pose :sepal-length :sepal-width)
pj/lay-point)Plan
A plan is the fully resolved intermediate representation – a plain Clojure map containing everything needed to render a plot: data-space geometry, domains, tick info, legend, layout dimensions. No membrane types, no datasets, no scale objects.
Created with pj/plan. Numeric arrays (:xs, :ys, etc.) are dtype-next buffers for efficiency.
(def my-plan (pj/plan my-pose))(sort (keys my-plan))(:alpha-legend
:caption
:grid
:height
:layout
:layout-type
:legend
:legend-position
:margin
:panel-height
:panel-width
:panels
:size-legend
:subtitle
:title
:tooltip
:total-height
:total-width
:width
:x-label
:y-label)Panel
A panel is a single plotting area within a plan. It contains x/y domains, scale specs, tick info, coordinate type, and layers. A simple plot has one panel; pj/facet and pj/facet-grid produce multiple.
(sort (keys (first (:panels my-plan))))(:col
:coord
:layers
:row
:x-domain
:x-scale
:x-ticks
:y-domain
:y-scale
:y-ticks)Layer
A layer is a layer type placed on a pose, optionally with scoped mappings. Created by pj/lay-*. Layers attach to a pose either at the root ((pj/lay-point pose)) where they flow to every leaf, or with columns ((pj/lay-point pose :x :y)) where they attach to the matching leaf.
(-> my-pose :layers first :layer-type):pointPlan Layer
A plan layer is the resolved descriptor inside a plan panel: resolved mark type, style, and groups of data-space geometry. The user-level layer becomes the plan layer through pj/plan.
(-> my-pose
pj/plan
(get-in [:panels 0 :layers 0])){:mark :point,
:style {:opacity 0.75, :radius 3.0},
:size-scale nil,
:alpha-scale nil,
:groups
[{:color
[0.8941176470588236 0.10196078431372549 0.10980392156862745 1.0],
:xs #tech.v3.dataset.column<float64>[50]
:sepal-length
[5.100, 4.900, 4.700, 4.600, 5.000, 5.400, 4.600, 5.000, 4.400, 4.900, 5.400, 4.800, 4.800, 4.300, 5.800, 5.700, 5.400, 5.100, 5.700, 5.100...],
:ys #tech.v3.dataset.column<float64>[50]
:sepal-width
[3.500, 3.000, 3.200, 3.100, 3.600, 3.900, 3.400, 3.400, 2.900, 3.100, 3.700, 3.400, 3.000, 3.000, 4.000, 4.400, 3.900, 3.500, 3.800, 3.800...],
:label "setosa",
:row-indices #tech.v3.dataset.column<int64>[50]
:__row-idx
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19...]}
{:color
[0.21568627450980393 0.49411764705882355 0.7215686274509804 1.0],
:xs #tech.v3.dataset.column<float64>[50]
:sepal-length
[7.000, 6.400, 6.900, 5.500, 6.500, 5.700, 6.300, 4.900, 6.600, 5.200, 5.000, 5.900, 6.000, 6.100, 5.600, 6.700, 5.600, 5.800, 6.200, 5.600...],
:ys #tech.v3.dataset.column<float64>[50]
:sepal-width
[3.200, 3.200, 3.100, 2.300, 2.800, 2.800, 3.300, 2.400, 2.900, 2.700, 2.000, 3.000, 2.200, 2.900, 2.900, 3.100, 3.000, 2.700, 2.200, 2.500...],
:label "versicolor",
:row-indices #tech.v3.dataset.column<int64>[50]
:__row-idx
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69...]}
{:color
[0.30196078431372547 0.6862745098039216 0.2901960784313726 1.0],
:xs #tech.v3.dataset.column<float64>[50]
:sepal-length
[6.300, 5.800, 7.100, 6.300, 6.500, 7.600, 4.900, 7.300, 6.700, 7.200, 6.500, 6.400, 6.800, 5.700, 5.800, 6.400, 6.500, 7.700, 7.700, 6.000...],
:ys #tech.v3.dataset.column<float64>[50]
:sepal-width
[3.300, 2.700, 3.000, 2.900, 3.000, 3.000, 2.500, 2.900, 2.500, 3.600, 3.200, 2.700, 3.000, 2.500, 2.800, 3.200, 3.000, 3.800, 2.600, 2.200...],
:label "virginica",
:row-indices #tech.v3.dataset.column<int64>[50]
:__row-idx
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119...]}],
:y-domain [2.0 4.4],
:x-domain [4.3 7.9]}Dataset
A dataset is the tabular data backing a plot. Plotje uses Tablecloth datasets internally; raw input (a map of {column-name [values]}, a sequence of row-maps, or a CSV/URL string) is coerced via tablecloth.api/dataset at construction time. The dataset lives on a pose under :data; per-layer and per-sub-pose :data overrides are also supported.
Pipeline
The pipeline is the five-stage flow from user code to rendered output: pose -> draft -> plan -> membrane -> plot. A pose is what you compose; pj/draft flattens it into a vector of maps; pj/plan resolves geometry and layout; the membrane layer turns the plan into drawable primitives; the plot is the terminal SVG hiccup or PNG output. See the Architecture chapter for the per-stage details.
Sub-plot
A sub-plot is one resolved sub-pose in a composite pose’s plan. Where a plain leaf-pose’s plan carries :panels (one per faceted variant), a composite pose’s plan carries :sub-plots (one per sub-pose), each with its own nested :plan map. The compositor reads :sub-plots and tiles their rendered membranes into the final canvas.
Resolve Tree
The resolve tree is the scope-merge walk that propagates a root pose’s :mapping, :opts, and root-attached :layers downward into every descendant leaf during plan construction. Lower (narrower) scopes override higher ones; root-attached layers reach every applicable leaf in the tree.
Domain
A domain is the range of data values along an axis.
- Numerical:
[min max]with padding (e.g.,[4.0 8.2]) - Categorical: sequence of distinct values (e.g.,
["setosa" "versicolor" "virginica"])
(let [p (first (:panels my-plan))]
{:x-domain (:x-domain p)
:y-domain (:y-domain p)}){:x-domain [4.12 8.08], :y-domain [1.88 4.5200000000000005]}Tick
A tick is an axis mark with a label at a domain value. Ticks are chosen at layout time to fit the available pixel budget – label widths, minimum spacing, and calendar boundaries (for temporal axes) all feed into the selection. Each panel in the plan carries its own :x-ticks and :y-ticks maps with parallel :values and :labels vectors.
(-> my-plan :panels first :x-ticks (select-keys [:values :labels])){:values [4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0],
:labels ["4.5" "5.0" "5.5" "6.0" "6.5" "7.0" "7.5" "8.0"]}Scale
A scale maps data values to pixel positions. Built from a domain and a pixel range using wadogo.
| Type | Use |
|---|---|
:linear |
Numerical data (default) |
:log |
Orders-of-magnitude data |
:categorical |
Distinct categories (band scale) |
Scales are created at render time, not stored in the plan. The plan stores scale specs (:type, :domain).
Temporal columns (LocalDate, LocalDateTime, Instant, java.util.Date) are automatically detected and treated as numerical. Tick labels are calendar-aware – snapped to year, month, day, or hour boundaries depending on the time span.
Coord
A coord (coordinate system) defines how data-space maps to drawing units.
| Type | Behavior |
|---|---|
:cartesian |
Standard: x rightward, y upward |
:flip |
Swap x and y axes |
:polar |
Radial: x as angle, y as radius |
:fixed |
Equal aspect ratio: 1 data unit = 1 data unit |
Facet
A facet splits data into multiple panels by a categorical column. Each panel shows a subset of the data.
pj/facetcreates a row or column of panelspj/facet-gridcreates a row-by-column grid from two columns
By default all panels share the same x and y domains, derived from the full dataset (:scales :shared). To let each panel use its own data range, set {:scales :free} (or :free-x/:free-y) in pj/options.
(-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width)
(pj/facet :species)
pj/plan :panels count)3Annotation
An annotation is a non-data mark that adds visual reference to a plot. Annotations are not connected to data columns – they overlay fixed positions passed via options (:y-intercept or :x-intercept for rules; :y-min/:y-max or :x-min/:x-max for bands). They are regular layers, so they attach under the same three cases as any lay-*: bare call sits on the pose, matching columns join the most recent matching leaf, non-matching columns create a new leaf.
| Constructor | What |
|---|---|
pj/lay-rule-v |
Vertical line at x = x-intercept |
pj/lay-rule-h |
Horizontal line at y = y-intercept |
pj/lay-band-v |
Vertical shaded region from x = x-min to x = x-max |
pj/lay-band-h |
Horizontal shaded region from y = y-min to y = y-max |
(-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width)
(pj/lay-rule-h {:y-intercept 3.0})
:layers (nth 1) :layer-type):rule-hLegend
A legend is generated automatically when a color (or shape) aesthetic maps to a data column. It appears in the plan as a :legend key containing entries with labels and colors. Position is controlled via {:legend-position :bottom} in options.
(:legend my-plan){:title :species,
:entries
[{:label "setosa",
:color
[0.8941176470588236 0.10196078431372549 0.10980392156862745 1.0]}
{:label "versicolor",
:color
[0.21568627450980393 0.49411764705882355 0.7215686274509804 1.0]}
{:label "virginica",
:color
[0.30196078431372547 0.6862745098039216 0.2901960784313726 1.0]}]}Theme
A theme controls the visual appearance of non-data elements. It is a nested map under :theme with three keys:
| Key | Controls |
|---|---|
:bg |
Panel background color |
:grid |
Gridline color |
:font-size |
Base font size in pixels |
Passed as {:theme {...}} via pj/options, pj/with-config, or pj/set-config!. Other visual knobs (margins, legend width, tick spacing) are top-level configuration keys, not theme entries – see pj/config-key-docs.
(-> (rdatasets/datasets-iris)
(pj/lay-point :sepal-length :sepal-width {:color :species})
(pj/options {:theme {:bg "#2d2d2d" :grid "#444444" :font-size 10}})
pj/svg-summary :points)150Membrane
A membrane is a value of the Membrane library – a tree of layout and drawing primitives (Translate, WithColor, RoundedRectangle, Label, etc.) that represents a complete plot.
The membrane is an intermediate step in the SVG rendering path: the plan becomes a membrane, which becomes SVG hiccup. Direct renderers (e.g., Plotly) skip the membrane entirely.
(def my-membrane (pj/plan->membrane my-plan))(vector? my-membrane)true(count my-membrane)9Plot
A plot is the final rendered output – the result of rendering a plan to a specific format. For SVG, the plot is hiccup markup wrapped in kind/hiccup.
Created by pj/plot or by auto-rendering a pose.
(def my-plot (pj/plan->plot my-plan :svg {}))(first my-plot):svgPalette
A palette is an ordered set of colors used for categorical aesthetics. When :color maps to a categorical column, colors are assigned from the active palette in order.
Plotje uses clojure2d for palettes. Set via {:palette :set2} in options. The number of named palettes available:
(count (c2d/find-palette #".*"))7024Gradient
A gradient (or color scale) maps a continuous numeric range to a smooth color ramp. Used when :color maps to a numerical column.
Common gradients: :viridis, :inferno, :plasma, :magma. Diverging gradients center on a midpoint value. Set via {:color-scale :inferno} in options.
Configuration
Configuration controls rendering behavior – dimensions, theme, palette, color scale, margins, and more. It is one of three option scopes – the others are plot options and layer options. Configuration follows a precedence chain:
plot options > pj/with-config > pj/set-config! > plotje.edn > library defaults
plotje.edn is an optional file in your project root that provides project-level defaults (e.g., a consistent palette or theme across all plots).
See the Configuration chapter for details.
Plot Options
Plot options are per-plot settings passed to pj/options, pj/plan, or pj/plot. They include text content (title, subtitle, caption, axis labels) and a nested :config override. Unlike configuration keys, plot options are inherently per-plot – a title does not make sense as a global default.
See pj/plot-option-docs for the full list, or the Configuration chapter for usage examples.
(count pj/plot-option-docs)14Layer Options
Layer options are per-layer settings passed in the options map of layer functions (pj/lay-point, pj/lay-histogram, etc.). They control aesthetics (:color, :size, :alpha, :shape), grouping (:group), position adjustment (:position), and layer-type-specific parameters (:bandwidth, :confidence-band, :normalize, etc.).
Four keys are universal – accepted by every layer – and each layer type may accept additional keys. The Layer Types chapter lists which options each layer type accepts. See also pj/layer-option-docs for descriptions, or inspect a specific layer type with pj/layer-type-lookup.
(count pj/layer-option-docs)29Tooltip and Brush
A tooltip shows data values on hover. A brush enables click-and-drag selection that highlights a rectangular region. Both are JavaScript-based interactions added to the SVG output.
Enabled via {:tooltip true} and {:brush true} in options.
Summary Table
| Term | What | Key functions |
|---|---|---|
| Pose | Composable value: data + mapping + layers (+ sub-poses) | All pj/ functions return poses |
| Leaf pose | Pose describing one plot panel | pj/pose, pj/lay-* with columns |
| Composite pose | Pose containing sub-poses and a layout | pj/arrange |
| Mapping | Column-to-aesthetic association on a pose or layer | pj/pose mapping, pj/lay-* options |
| Layer | Layer type attached to a pose, optionally with scoped mappings | pj/lay-* |
| Dataset | Tabular data backing a plot (Tablecloth) | :data slot, pj/with-data |
| Pipeline | Five-stage flow pose -> draft -> plan -> membrane -> plot |
Architecture chapter |
| Sub-plot | One resolved sub-pose in a composite pose’s plan | :sub-plots in plan |
| Resolve tree | Scope-merge walk: root mappings propagate to every leaf | Internal to pj/plan |
| Draft | Vector of flat maps from merging pose and layer mappings | pj/draft, automatic during pj/plan |
| Layer type | Mark + stat + position bundle | pj/layer-type-lookup, pj/lay-* |
| Mark | Visual shape: point, line, bar, area, … | Key in layer-type map |
| Stat | Data transform: identity, bin, count, linear-model, density, … | Key in layer-type map |
| Position | How groups share space: dodge, stack, fill, identity | Key in layer-type map |
| Inference | Auto-choosing mark/stat from column types | When pj/lay-* is omitted |
| Aesthetic | Data-driven visual property: color, size, alpha | Key in mapping or layer |
| Group | Subset of data rendered together | From :color or :group |
| Plan | Fully resolved plot description | pj/plan |
| Panel | One plotting area (domain, ticks, layers) | One or more per plan |
| Plan layer | Resolved geometry + style for one mark | Inside plan panels |
| Domain | Data range on an axis | Part of panel |
| Tick | Axis mark with label at a domain value | Part of panel |
| Scale | Data-to-pixel mapping (linear, log, categorical) | pj/scale |
| Coord | Coordinate system (cartesian, flip, polar, fixed) | pj/coord |
| Facet | Split into panels by a categorical column | pj/facet, pj/facet-grid |
| Arrange | Compose multiple poses into a grid | pj/arrange |
| Share scales | Make sibling sub-poses of a composite pose share data ranges across named axes | :share-scales in composite :opts |
| Annotation | Non-data reference marks (rules, bands) | pj/lay-rule-*, pj/lay-band-* |
| Legend | Color/size/alpha key from aesthetic mappings | Automatic in plan |
| Plot options | Title, subtitle, caption, labels, dimensions | pj/options |
| Layer options | Per-layer aesthetics and layer-type parameters | pj/lay-* options map |
| Theme | Visual styling: background, grid, fonts | :theme in pj/options |
| Palette | Ordered color set for categorical aesthetics | :palette in pj/options |
| Gradient | Continuous color ramp for numerical mappings | :color-scale in pj/options |
| Configuration | Global rendering defaults | pj/config, pj/set-config!, pj/with-config |
| Membrane | Drawable tree (membrane library) | Internal rendering step |
| Plot | Final output (SVG hiccup) | pj/plot, pj/save |
| Tooltip / Brush | JavaScript hover and selection interactions | {:tooltip true} in options |