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, position, and the layer options it presets. Two layer types can share a mark and differ only by one of the other three columns: :histogram is the :bar mark with a binning stat, and :label is the :text mark with a background box preset.
(kind/table
{:column-names ["Layer type" "Mark" "Stat" "Position" "Presets"]
: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)))
"Presets" (if-let [d (:defaults m)] (kind/code (pr-str d)) "")})})| Layer type | Mark | Stat | Position | Presets |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The βPresetsβ column is what separates two layer types that would otherwise look identical here β :text and :label share a mark, a stat, and a position, and differ only in that a label starts with its box switched on:
(mapv #(select-keys (layer-type/lookup %) [:mark :stat :defaults])
[:text :label])[{:mark :text, :stat :identity}
{:mark :text, :stat :identity, :defaults {:box true}}]The βPositionβ column shows each layer-typeβs registered default. A few marks (:bar, :lollipop, :boxplot, :violin) carry no registered default and the table therefore lists :identity for them, but they apply :dodge at extract time when a categorical color or group splits the data into multiple sub-bars per category. So a colored (pj/lay-bar :species {:color :group}) produces dodged bars even though the table shows :identity for :bar. To force a different layout, pass :position explicitly in the layer options.
Marks
A mark is the visual shape shown for each data point or group. Several layer types may share the same mark β for instance, tile and density-2d both produce tiles, 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 |
|
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, optionally on a background box | label, text |
|
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, bar, errorbar, interval-h, label, line, lollipop, point, rug, rule-h, rule-v, step, text |
|
Bin numerical values into ranges | histogram |
|
(no description) | |
|
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, 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 or string naming the column drawn along the x axis, or a value to draw at that x. A value beside a column :y broadcasts over the layer's data; values for both :x and :y draw one mark |
|
Column keyword or string naming the column drawn along the y axis, or a value to draw at that y. The same two shapes as :x |
|
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) |
|
Dataset or plain data for this layer alone, overriding the pose's |
|
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. |
|
Override the mark the layer type draws with β the shape on the panel |
|
Override the statistic the layer type computes β e.g. {:stat :count} on a text layer labels counted bars |
|
Shift the whole layer right by this many drawing units, after the scales. Unlike :nudge-x this is not a data value, so it works on a categorical axis and does not move the axis domain β use it to clear a label of the mark it labels |
|
Shift the whole layer down by this many drawing units, after the scales. See :offset-x |
|
The space this layer's :x and :y are in β :data (default, values mapped through the scales) or :drawing-area (drawing units from the top left of the panel background). A :drawing-area layer is placed on the panel rather than in the data, so it does not move the axis domains |
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 |
|---|---|
|
Horizontal text anchor β :left, :center, or :right (default :left); which part of the label sits at the x position |
|
Vertical text anchor β :top, :center, or :bottom (default :center); which part of the label sits at the y position. Data-oriented: :top puts the label's top edge at the point |
|
Column keyword (per-point opacity) or fixed number 0.0β1.0 |
|
Smoothing bandwidth for density and LOESS methods |
|
Width of a bar on a numeric or temporal x axis, in data units. Defaults to 0.9 of the smallest gap between adjacent x positions. |
|
Number of histogram bins, overriding the :bin-method estimate |
|
Width of one histogram bin in data units, an alternative to :bins |
|
Number of bootstrap resamples for a LOESS confidence ribbon (default 200) |
|
Background box behind text β true for the default box, false or absent for none, or a map of box properties: {:corner-radius n} in drawing units (default 3, 0 for square corners). pj/lay-label is pj/lay-text with the box on |
|
Fraction (0.0-1.0) of the categorical band that a box fills (default 0.6) |
|
Width of an errorbar's end caps in drawing units |
|
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 |
|
Dataset or plain data for this layer alone, overriding the pose's |
|
2D density grid resolution β number of bins per axis (default 25) |
|
Column keyword for tile fill values (pre-computed heatmap) |
|
Text height in drawing units for a text or label mark (default 10) |
|
Draws the text italic β :normal (default) or :italic |
|
Draws the text bold β :normal (default) or :bold |
|
Column keyword for grouping without color |
|
The space this layer's :x and :y are in β :data (default, values mapped through the scales) or :drawing-area (drawing units from the top left of the panel background). A :drawing-area layer is placed on the panel rather than in the data, so it does not move the axis domains |
|
Fraction (0.0β1.0) of the categorical band that an interval bar fills (default 0.7) |
|
true or an amount in drawing units β random offset to reduce overplotting |
|
Length of a rug tick in drawing units |
|
Confidence level of a smooth's ribbon (default 0.95) |
|
Number of contour iso-levels (default 5) |
|
Override the mark the layer type draws with β the shape on the panel |
|
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 |
|
Shift the whole layer right by this many drawing units, after the scales. Unlike :nudge-x this is not a data value, so it works on a categorical axis and does not move the axis domain β use it to clear a label of the mark it labels |
|
Shift the whole layer down by this many drawing units, after the scales. See :offset-x |
|
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 |
|
Override the statistic the layer type computes β e.g. {:stat :count} on a text layer labels counted bars |
|
Outline color for an area or density curve β the fill still comes from :color |
|
Dash pattern for a line, step, smooth, reference line, or area outline β :dashed, :dotted, :solid, or a raw [dash gap ...] pattern in drawing units |
|
Width of that outline in drawing units |
|
Column keyword for label content |
|
Whether a density curve is estimated only over its own group's values. Density defaults to false (every group spans the whole layer's range); violin and ridgeline default to true (each body ends at its category's values) |
|
Column keyword or string naming the column drawn along the x axis, or a value to draw at that x. A value beside a column :y broadcasts over the layer's data; values for both :x and :y draw one mark |
|
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. |
|
Column keyword or string naming the column drawn along the y axis, or a value to draw at that y. The same two shapes as :x |
|
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
- Relationships β see point, line, and regression layer types in action
- Distributions β histograms, density, boxplots, violins
- Customization β colors, palettes, themes, and per-layer options