10 Layer Types
A layer type is the bundle that determines how data becomes a visual element. It combines three concepts:
- mark β what shape to show (points, bars, lines, β¦)
- stat β what computation to apply first (pass through, bin, count, regress, β¦)
- position β how overlapping groups share space (identity, dodge, stack, fill)
Layer functions (pj/lay-point, pj/lay-histogram, pj/lay-bar, (pj/lay-smooth {:stat :linear-model}), etc.) each add a layer with the corresponding layer type. When no layer is added, Plotje infers a layer type from the column types.
All built-in layer types are registered in a data registry. The tables below are generated from that registry β they stay in sync with the code.
(ns plotje-book.layer-types
(:require
;; Kindly -- notebook rendering protocol
[scicloj.kindly.v4.kind :as kind]
;; Plotje -- composable plotting
[scicloj.plotje.api :as pj]
;; Layer-type registry -- for inspecting layer-type data
[scicloj.plotje.layer-type :as layer-type]
;; String utilities
[clojure.string :as str]))Reading the Registry
The tables below are generated directly from the layer-type registry, so they track whatever is currently registered. Two small helpers query the registry: used-by returns the comma-separated list of layer types whose given field equals a value, and distinct-in-order returns each distinct field value in the order layer types were registered. Both are used to populate the Mark, Stat, and Position tables further down.
(defn used-by
"Sorted comma-separated layer-type names whose `field` equals `value`."
[field value]
(->> (layer-type/registered)
(filter (fn [[_ m]] (= value (or (get m field) :identity))))
(map (comp name key))
sort
(str/join ", ")))(defn distinct-in-order
"Distinct values of `field` across layer types, in first-seen order."
[field]
(let [seen (volatile! #{})]
(reduce (fn [acc k]
(let [v (get (layer-type/lookup k) field)]
(if (@seen v) acc
(do (vswap! seen conj v) (conj acc v)))))
[] layer-type/layer-type-order)))Layer Types
Each row is a registered layer type showing its mark, stat, and position.
(kind/table
{:column-names ["Layer type" "Mark" "Stat" "Position"]
:row-maps
(for [k layer-type/layer-type-order
:let [m (layer-type/lookup k)]]
{"Layer type" (kind/code (pr-str k))
"Mark" (kind/code (pr-str (:mark m)))
"Stat" (kind/code (pr-str (:stat m)))
"Position" (kind/code (pr-str (or (:position m) :identity)))})})| Layer type | Mark | Stat | Position |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Marks
A mark is the visual shape shown for each data point or group. Several layer types may share the same mark β for instance, histogram and value-bar both produce bars, and lm (linear model) and loess (local regression) both produce lines.
(kind/table
{:column-names ["Mark" "Shape" "Used by"]
:row-maps
(for [mk (distinct-in-order :mark)]
{"Mark" (kind/code (pr-str mk))
"Shape" (pj/mark-doc mk)
"Used by" (used-by :mark mk)})})| Mark | Shape | Used by |
|---|---|---|
|
Filled circle | point |
|
Connected path | line, smooth |
|
Horizontal-then-vertical path | step |
|
Filled region under a curve | area, density |
|
Vertical rectangles (binned) | histogram |
|
Positioned rectangles | bar, value-bar |
|
Grid of colored cells | density-2d, tile |
|
Iso-value polylines | contour |
|
Box-and-whisker | boxplot |
|
Mirrored density shape | violin |
|
Stacked density curves | ridgeline |
|
Point with error bar | summary |
|
Vertical error bar | errorbar |
|
Stem with dot | lollipop |
|
Data-driven label | text |
|
Label with background box | label |
|
Axis-margin tick marks | rug |
|
Horizontal bars from x to x-end at categorical y | interval-h |
|
(no description) | rule-h |
|
(no description) | rule-v |
|
(no description) | band-h |
|
(no description) | band-v |
Stats
A stat (statistical transform) processes raw data before rendering. Each stat takes data-space inputs and produces the geometry that its mark will show.
(kind/table
{:column-names ["Stat" "What it computes" "Used by"]
:row-maps
(for [st (distinct-in-order :stat)]
{"Stat" (kind/code (pr-str st))
"What it computes" (pj/stat-doc st)
"Used by" (used-by :stat st)})})| Stat | What it computes | Used by |
|---|---|---|
|
Pass-through β no transform | area, band-h, band-v, errorbar, interval-h, label, line, lollipop, point, rug, rule-h, rule-v, step, text, value-bar |
|
Bin numerical values into ranges | histogram |
|
Count occurrences per category | bar |
|
LOESS (local regression) smoothing | smooth |
|
Density β 1D kernel density estimation (KDE) | density |
|
2D grid binning (heatmap counts) | tile |
|
Density 2D β 2D Gaussian kernel density estimation (KDE) | contour, density-2d |
|
Five-number summary + outliers | boxplot |
|
KDE per category (density profile) | ridgeline, violin |
|
Mean Β± standard error per category | summary |
Positions
A position adjustment determines how groups share a categorical axis slot. Position runs between stat computation and rendering.
(kind/table
{:column-names ["Position" "What it does" "Used by"]
:row-maps
(for [pos [:identity :dodge :stack :fill]]
{"Position" (kind/code (pr-str pos))
"What it does" (pj/position-doc pos)
"Used by" (used-by :position pos)})})| Position | What it does | Used by |
|---|---|---|
|
Plot at exact data coordinates (groups overlap) | area, band-h, band-v, bar, boxplot, contour, density, density-2d, errorbar, histogram, interval-h, label, line, lollipop, point, ridgeline, rug, rule-h, rule-v, smooth, step, summary, text, tile, value-bar, violin |
|
Shift groups side-by-side within a band | |
|
Pile groups cumulatively | |
|
Stack normalized to [0, 1] (proportions) |
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.
Layer Options
The options map passed to lay- functions controls aesthetics, statistical parameters, and spatial adjustments for that layer.
Universal options
Accepted by every layer type:
(kind/table
{:column-names ["Option" "Description"]
:row-maps
(for [k layer-type/universal-layer-options]
{"Option" (kind/code (pr-str k))
"Description" (get layer-type/layer-option-docs k)})})| Option | Description |
|---|---|
|
|
|
|
|
Column keyword (categorical grouping) or literal color string |
|
Override inferred color type β :categorical or :numerical. Use :categorical to treat numeric IDs as groups. |
|
Column keyword (per-point opacity) or fixed number 0.0β1.0 |
|
Column keyword for grouping without color |
|
Position adjustment keyword β how overlapping groups are arranged (see pj/position-doc) |
|
|
|
Override inferred x-column type β :categorical, :numerical, or :temporal. Use :categorical on numeric x (hours, years, IDs) when a categorical-axis mark (bar, boxplot) is needed. |
|
Override inferred y-column type β :categorical, :numerical, or :temporal. Mirror of :x-type, used for horizontal layouts. |
|
|
|
Layer-type-specific options
Some layer types accept additional keys beyond the universal set. Layer types not listed here accept only the universal options above.
(kind/table
{:column-names ["Layer type" "Additional options"]
:row-maps
(for [k layer-type/layer-type-order
:let [m (layer-type/lookup k)
accepts (:accepts m)]
:when (seq accepts)]
{"Layer type" (kind/code (pr-str k))
"Additional options" accepts})})| Layer type | Additional options |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All layer option keys
(kind/table
{:column-names ["Option" "Description"]
:row-maps
(for [[k desc] (sort-by key layer-type/layer-option-docs)]
{"Option" (kind/code (pr-str k))
"Description" desc})})| Option | Description |
|---|---|
|
Column keyword (per-point opacity) or fixed number 0.0β1.0 |
|
Smoothing bandwidth for density and LOESS methods |
|
Number of bootstrap resamples for a LOESS confidence ribbon (default 200) |
|
Column keyword (categorical grouping) or literal color string |
|
Override inferred color type β :categorical or :numerical. Use :categorical to treat numeric IDs as groups. |
|
true to show a standard-error confidence ribbon around the fitted line |
|
2D density grid resolution β number of bins per axis (default 25) |
|
Column keyword for tile fill values (pre-computed heatmap) |
|
Column keyword for grouping without color |
|
Fraction (0.0β1.0) of the categorical band that an interval bar fills (default 0.7) |
|
true or pixel amount β random offset to reduce overplotting |
|
Number of contour iso-levels (default 5) |
|
Histogram normalization β :density (area integrates to 1) or nil |
|
Shift all x-coordinates by this data-space amount |
|
Shift all y-coordinates by this data-space amount |
|
Position adjustment keyword β how overlapping groups are arranged (see pj/position-doc) |
|
Column keyword for per-point shape |
|
Rug tick position β :x (default), :y, or :both |
|
Column keyword or fixed number β point radius or stroke width |
|
Column keyword for label content |
|
Column keyword for the right-edge x value of a horizontal interval bar |
|
Numeric or temporal x-axis position for a vertical reference line |
|
Upper x bound of a vertical shaded band |
|
Lower x bound of a vertical shaded band |
|
Override inferred x-column type β :categorical, :numerical, or :temporal. Use :categorical on numeric x (hours, years, IDs) when a categorical-axis mark (bar, boxplot) is needed. |
|
Numeric or temporal y-axis position for a horizontal reference line |
|
Column keyword for upper error bound of an errorbar, or upper y bound of a horizontal shaded band |
|
Column keyword for lower error bound of an errorbar, or lower y bound of a horizontal shaded band |
|
Override inferred y-column type β :categorical, :numerical, or :temporal. Mirror of :x-type, used for horizontal layouts. |
Whatβs Next
- Scatter Plots β see point, line, and regression layer types in action
- Distributions β histograms, density, boxplots, violins
- Customization β colors, palettes, themes, and per-layer options