25  API Reference

Complete reference for every public function in scicloj.plotje.api.

Each entry shows the docstring, a live example, and a test. For galleries of mark variations, see the Reference notebooks (Scatter, Distributions, Ranking, Change Over Time, Relationships).

Sample Data

(def tiny {:x [1 2 3 4 5]
           :y [2 4 1 5 3]
           :group [:a :a :b :b :b]})
(def sales {:product [:widget :gadget :gizmo :doohickey]
            :revenue [120 340 210 95]})
(def measurements {:treatment ["A" "B" "C" "D"]
                   :mean [10.0 15.0 12.0 18.0]
                   :ci-lo [8.0 12.0 9.5 15.5]
                   :ci-hi [12.0 18.0 14.5 20.5]})

Construction

pose

[]

[x]

[x y]

[x y z]

[x y z opts]

Construct or extend a pose.

On raw data (first argument is not itself a pose): (pj/pose) – empty leaf (pj/pose data) – leaf with data; on 1-3 column datasets the mapping is auto-inferred (:x, then :y, then :color) so the pose renders without an explicit mapping call (pj/pose data {:color :species}) – leaf with aesthetic mapping (pj/pose data :x-col) – leaf with {:x :x-col} (pj/pose data :x-col {:color :c}) – univariate x + opts (pj/pose data :x-col :y-col) – leaf with :x and :y (pj/pose data :x-col :y-col {:color :c}) – positional x/y + opts (pj/pose data [[:a :b] [:c :d]]) – multi-pair: N bivariate panels (pj/pose data [:a :b :c]) – multi-pair: N univariate panels (pj/pose data (pj/cross cols cols) {:color :c}) – multi-pair plus aesthetic mapping at the composite root

Threaded over an existing pose (first argument is a pose): (pj/pose fr) – pass-through; lifts a literal map for notebook auto-render if it is not already tagged (pj/pose fr :x-col :y-col) – extend a leaf-without-position, or promote a leaf-with-position into a 2-panel composite, or append a panel to a composite (pj/pose fr :x-col :y-col {:color :c}) – same, with aesthetic routed to the composite root on promote (pj/pose fr {:color :c}) – aesthetic-only: extend mapping or (on leaf-with-position) promote (pj/pose fr [[:a :b] [:c :d]]) – multi-pair: append N panels (pj/pose fr (pj/cross cols cols)) – SPLOM N^2 panels in one call (pj/pose fr (pj/cross cols cols) {:color :c}) – SPLOM plus aesthetic mapping at the composite root (pj/pose fr {:data X :color :c}) – extend mapping AND replace the top-level data with X

On a hand-built pose-shaped map (1-arity, input has :layers or :poses): the map is validated and tagged with Kindly auto-render metadata, but its keys are not reordered and its :data is not coerced – the typed shape is preserved verbatim. A flat composite (:poses of leaf maps) is supported; literal nested composites (any sub-pose itself has :poses) are rejected, matching pj/arrange’s rule that its elements must be leaves.

Create a leaf pose with data and columns:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width)
    pj/lay-point)
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

Map form – include aesthetics on the pose so every layer sees them:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width {:color :species})
    pj/lay-point
    (pj/lay-smooth {:stat :linear-model}))
sepal widthsepal lengthspeciessetosaversicolorvirginica4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

with-data

[pose data]

Supply or replace the top-level dataset on a pose. Useful for building a template once and applying it to different datasets:

   (def template (-> (pj/pose)
                     (pj/pose :x :y {:color :group})
                     pj/lay-point
                     (pj/lay-smooth {:stat :linear-model})))

   (-> template (pj/with-data my-data))
   (-> template (pj/with-data other-data))

At attach time, every keyword column reference in the template’s mapping, layers, sub-poses, and facet options must exist in the dataset – otherwise an error is thrown naming the missing columns and listing what is available. Per-layer / per-sub-pose :data still overrides the top-level data. (with-data pose data)

Attach or replace the top-level dataset on a pose. Useful for building a dataless template and applying it to many datasets:

(def scatter-template
  (-> (pj/pose nil {:x :x :y :y :color :group})
      pj/lay-point))
(-> scatter-template
    (pj/with-data tiny))
yxgroupab1.01.52.02.53.03.54.04.55.01.01.52.02.53.03.54.04.55.0

Multi-pair pose – a vector of [x y] pairs creates a composite with one sub-pose per pair:

(-> (rdatasets/datasets-iris)
    (pj/pose [[:sepal-length :sepal-width]
              [:petal-length :petal-width]])
    (pj/lay-point {:color :species}))
682345012sepal lengthpetal lengthsepal widthpetal widthspeciessetosaversicolorvirginica

Map form – explicit keys on a pose:

(-> (rdatasets/datasets-iris)
    (pj/pose {:x :sepal-length :y :sepal-width})
    pj/lay-point)
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

cross

[xs ys]

Build a vector of [x y] pairs from two column-name sequences. Pair with pj/pose for SPLOM grids: when an MxN rectangle of pairs is threaded through pj/pose, the result is an MxN composite with shared scales.

(pj/cross [:a :b] [:c :d]) ; => [[:a :c] [:a :d] [:b :c] [:b :d]]

(pj/cross [:a :b] [1 2 3])
([:a 1] [:a 2] [:a 3] [:b 1] [:b 2] [:b 3])

Combine pj/cross with pj/pose to build a SPLOM:

(-> (rdatasets/datasets-iris)
    (pj/pose (pj/cross [:sepal-length :petal-length]
                       [:sepal-width :petal-width])
             {:color :species}))
234246234246sepal-widthpetal-widthsepal-lengthpetal-lengthspeciessetosaversicolorvirginica

Multi-column vector creates one panel per column:

(pj/lay-histogram (rdatasets/datasets-iris) [:sepal-length :sepal-width])
567805101520252.02.53.03.54.04.505101520253035404550sepal lengthsepal width

Layer Functions

lay

[pose-or-data layer-type-key]

[pose-or-data layer-type-key opts]

Add a root-scope layer. The layer attaches to :layers and flows to every descendant leaf at plan time (composite) or renders on the single panel (leaf).

The generic layer adder. pj/lay-point, pj/lay-bar, etc. are convenience wrappers around pj/lay with a registered layer-type key. Use pj/lay directly when you have a custom layer type (from pj/layer-type-lookup on a registered key, or a raw layer-type map from an extension):

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width)
    (pj/lay :point))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

The above just delegates to :point – equivalent to pj/lay-point. The intended use of pj/lay is with a layer type that isn’t a built-in convenience: a registered custom layer type from an extension, or a raw layer-type map. See the Waterfall Extension chapter for the full pattern – registering a :waterfall layer type and calling (pj/lay pose (layer-type/lookup :waterfall)) or wrapping it in a pj/lay-waterfall convenience function.

lay-point

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add a :point (scatter) layer to a pose. Without columns -> bare layer at the pose’s root (flows to every leaf). With columns -> position-bearing layer (attaches to the matching leaf via DFS-last identity, or appends a new sub-pose on miss). (lay-point fr) – bare layer at root (lay-point fr {:color :species}) – bare layer with aesthetic opts (lay-point data :x :y) – coerce data to a leaf, then attach (lay-point data :x :y {:color :c}) – same with aesthetic opts

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width {:color :species}))
sepal widthsepal lengthspeciessetosaversicolorvirginica4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-line

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :line layer type – connected line through data points. Requires x (numerical) and y (numerical). Accepts :color, :alpha, :size (stroke width), :nudge-x, :nudge-y.

(def wave {:x (range 30)
           :y (map #(Math/sin (* % 0.3)) (range 30))})
(-> wave
    (pj/lay-line :x :y))
yx051015202530-1.0-0.8-0.6-0.4-0.20.00.20.40.60.81.0

lay-histogram

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :histogram layer type – bin numerical values into bars. X-only: pass one column. Accepts :bins (count), :binwidth, :color, :normalize (:density for density-normalized heights).

(-> (rdatasets/datasets-iris)
    (pj/lay-histogram :sepal-length))
sepal length4.55.05.56.06.57.07.58.00510152025

lay-bar

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :bar layer type – count occurrences of each category. X-only: pass one categorical column. Accepts :color for grouped bars.

(-> (rdatasets/datasets-iris)
    (pj/lay-bar :species))
speciessetosaversicolorvirginica05101520253035404550

Stacked bars: pass {:position :stack} to pj/lay-bar.

(-> (rdatasets/palmerpenguins-penguins)
    (pj/lay-bar :island {:position :stack :color :species}))
islandspeciesAdelieGentooChinstrapTorgersenBiscoeDream020406080100120140160

100% stacked bars: pass {:position :fill} to pj/lay-bar.

(-> (rdatasets/palmerpenguins-penguins)
    (pj/lay-bar :island {:position :fill :color :species}))
islandspeciesAdelieGentooChinstrapTorgersenBiscoeDream0.00.10.20.30.40.50.60.70.80.91.0

lay-value-bar

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :value-bar layer type – bars with pre-computed heights. Requires categorical x and numerical y. Unlike :bar (which counts), :value-bar uses the y value directly as the bar height.

(-> sales
    (pj/lay-value-bar :product :revenue))
revenueproductwidgetgadgetgizmodoohickey050100150200250300350

Linear regression: pass {:stat :linear-model} to pj/lay-smooth.

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-smooth {:stat :linear-model}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-smooth

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :smooth layer type – a smoothed trend line. Defaults to LOESS (local regression). Pass {:stat :linear-model} for ordinary least squares instead. Requires x and y (both numerical). Accepts {:confidence-band true} for a confidence ribbon.

(-> (let [r (rng/rng :jdk 42)
          xs (vec (range 50))]
      {:x xs
       :y (mapv #(+ (Math/sin (* % 0.2))
                    (* 0.3 (- (rng/drandom r) 0.5)))
                xs)})
    (pj/lay-point :x :y)
    (pj/lay-smooth {:bandwidth 0.2}))
yx05101520253035404550-1.2-1.0-0.8-0.6-0.4-0.20.00.20.40.60.81.0

lay-density

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :density layer type – kernel density estimate curve. X-only: pass one numerical column. Accepts :color, :bandwidth.

(-> (rdatasets/datasets-iris)
    (pj/lay-density :sepal-length))
sepal length3456789100.00.050.10.150.20.250.30.350.4

lay-area

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :area layer type – filled region between y and the baseline. Requires x and y (both numerical). Accepts :color, :alpha.

(-> wave
    (pj/lay-area :x :y))
yx051015202530-1.0-0.8-0.6-0.4-0.20.00.20.40.60.81.0

Stacked areas: pass {:position :stack} to pj/lay-area.

(-> {:x (concat (range 10) (range 10) (range 10))
     :y (concat [1 2 3 4 5 4 3 2 1 0]
                [2 2 2 3 3 3 2 2 2 2]
                [1 1 1 1 2 2 2 1 1 1])
     :group (concat (repeat 10 "A") (repeat 10 "B") (repeat 10 "C"))}
    (pj/lay-area :x :y {:position :stack :color :group}))
yxgroupABC02468012345678910

lay-text

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :text layer type – text labels at data coordinates. Requires x, y, and {:text :column} for label content.

(-> {:x [1 2 3 4] :y [4 7 5 8] :name ["A" "B" "C" "D"]}
    (pj/lay-text :x :y {:text :name}))
yxABCD1.01.52.02.53.03.54.04.04.55.05.56.06.57.07.58.0

lay-label

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :label layer type – text labels with background box at data coordinates. Like :text but with a rectangular background for readability.

(-> {:x [1 2 3 4] :y [4 7 5 8] :name ["A" "B" "C" "D"]}
    (pj/lay-point :x :y {:size 5})
    (pj/lay-label {:text :name}))
yxABCD1.01.52.02.53.03.54.04.04.55.05.56.06.57.07.58.0

lay-boxplot

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :boxplot layer type – box-and-whisker plot. Requires categorical x and numerical y. Shows median, quartiles, whiskers, and outliers. Accepts :color for grouped boxplots.

(-> (rdatasets/datasets-iris)
    (pj/lay-boxplot :species :sepal-width))
sepal widthspeciesno datasetosaversicolorvirginica2.02.53.03.54.04.5

lay-violin

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :violin layer type – mirrored density estimate by category. Requires categorical x and numerical y. Accepts :color, :bandwidth.

(-> (rdatasets/reshape2-tips)
    (pj/lay-violin :day :total-bill))
total billdayno dataSunSatThurFri-20-10010203040506070

lay-errorbar

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :errorbar layer type – vertical error bars from pre-computed bounds. Requires x, y, and {:y-min :col :y-max :col} for lower/upper bounds.

(-> measurements
    (pj/lay-point :treatment :mean)
    (pj/lay-errorbar {:y-min :ci-lo :y-max :ci-hi}))
meantreatmentABCD8101214161820

lay-lollipop

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :lollipop layer type – dot on a stem from the baseline. Requires categorical x and numerical y. Like value-bar but with a circle+line instead of a filled rectangle.

(-> sales
    (pj/lay-lollipop :product :revenue))
revenueproductwidgetgadgetgizmodoohickey050100150200250300350

lay-tile

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :tile layer type – colored grid cells (heatmap). With :fill option: pre-computed tile colors from a column. Without :fill: auto-binned 2D histogram (stat :bin2d).

(-> (rdatasets/datasets-iris)
    (pj/lay-tile :sepal-length :sepal-width))
sepal widthsepal lengthcount0.0009.000no data4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-density-2d

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :density-2d layer type – 2D kernel density heatmap. Requires x and y (both numerical). Produces a smoothed density surface as colored tiles with a continuous gradient legend.

(-> (rdatasets/datasets-iris)
    (pj/lay-density-2d :sepal-length :sepal-width))
sepal widthsepal lengthrelative density0.00027.10no data34567891.52.02.53.03.54.04.55.0

lay-contour

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :contour layer type – iso-density contour lines from 2D KDE. Requires x and y (both numerical). Accepts {:levels 10} for the number of contour levels.

(-> (rdatasets/datasets-iris)
    (pj/lay-contour :sepal-length :sepal-width))
sepal widthsepal lengthrelative density0.00027.10no data34567891.52.02.53.03.54.04.55.0

lay-ridgeline

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :ridgeline layer type – stacked density curves by category. Requires categorical x and numerical y. Categories stack vertically with density curves rendered horizontally.

(-> (rdatasets/datasets-iris)
    (pj/lay-ridgeline :species :sepal-length))
speciessepal lengthno data456789setosaversicolorvirginica

lay-rug

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :rug layer type – short tick marks along the axis showing individual values. X-only: pass one column. Often layered with density or scatter.

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-rug {:side :both}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-step

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :step layer type – staircase line (horizontal then vertical). Requires x and y (both numerical).

(-> tiny
    (pj/lay-step :x :y)
    pj/lay-point)
yx1.01.52.02.53.03.54.04.55.01.01.52.02.53.03.54.04.55.0

lay-summary

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :summary layer type – mean +/- standard error per category. Requires categorical x and numerical y. Shows a point at the mean with error bars for +/- 1 SE. Accepts :color for grouped summaries.

(-> (rdatasets/datasets-iris)
    (pj/lay-summary :species :sepal-length))
sepal lengthspeciessetosaversicolorvirginica5.05.25.45.65.86.06.26.46.6

lay-interval-h

[pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :interval-h layer type – horizontal bar from x to x-end at categorical y. Each row becomes one rectangle; the y column is treated categorically so each distinct value occupies its own lane. Required: x (numeric or temporal start), y (categorical lane), :x-end column ref in opts (numeric or temporal end). Accepts :color, :alpha, :interval-thickness (band fill fraction, 0.0-1.0, default 0.7). (lay-interval-h data :start :task {:x-end :end :color :status})

(-> {:start [#inst "2024-01-01" #inst "2024-03-01" #inst "2024-05-01"]
     :end   [#inst "2024-04-01" #inst "2024-06-01" #inst "2024-08-01"]
     :task  ["Design" "Build" "Test"]}
    (pj/lay-interval-h :start :task {:x-end :end}))
taskstartJan-02Jan-28Feb-23Mar-20Apr-15May-11Jun-06Jul-02Jul-28DesignBuildTest

Annotations

Reference lines and shaded bands are regular layers. Position comes from the options map (:y-intercept for lay-rule-h, :x-intercept for lay-rule-v; :y-min/:y-max for lay-band-h, :x-min/:x-max for lay-band-v); appearance aesthetics like :color and :alpha work the same as on any other layer. Without x/y columns they attach at the root (every panel); with x/y columns they attach to one matching leaf.

Rule intercepts also accept temporal values (LocalDate, LocalDateTime, Instant, java.util.Date) so date-axis annotations need no manual conversion – see the second lay-rule-v example below.

lay-rule-v

[_pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :rule-v layer – vertical reference line at x = x-intercept. Position comes from opts (not data columns); :x-intercept is required. Accepts :x-intercept (numeric or temporal – LocalDate, LocalDateTime, Instant, java.util.Date), :color (literal string), :alpha. Temporal values are converted internally to match the x-axis scale so date-axis annotations work without manual conversion. The 4-arity finds or creates a sub-pose with these x/y columns and attaches the rule there (only panels matching that leaf show it). (lay-rule-v pose {:x-intercept 5}) – root-level, flows to every panel (lay-rule-v pose :x :y {:x-intercept 5}) – panel-scope (columns pick or create a sub-pose) (lay-rule-v pose {:x-intercept 5 :color “red” :alpha 0.5}) (lay-rule-v pose {:x-intercept #inst “2008-09-15”})

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-rule-v {:x-intercept 6.0}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

A temporal rule on a date axis – the same pose pattern, with :x-intercept taking a LocalDate.

(-> {:date  [#inst "2024-01-01" #inst "2024-04-01" #inst "2024-08-01"]
     :value [3 5 9]}
    (pj/lay-line :date :value)
    (pj/lay-rule-v {:x-intercept (java.time.LocalDate/parse "2024-06-01")
                    :color "#c0392b"}))
valuedateJan-02Jan-28Feb-23Mar-20Apr-15May-11Jun-06Jul-02Jul-283456789

lay-rule-h

[_pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :rule-h layer – horizontal reference line at y = y-intercept. Position comes from opts (not data columns); :y-intercept is required. Accepts :y-intercept (numeric or temporal – LocalDate, LocalDateTime, Instant, java.util.Date), :color (literal string), :alpha. Temporal values are converted internally to match the y-axis scale so date-axis annotations work without manual conversion. The 4-arity finds or creates a sub-pose with these x/y columns and attaches the rule there (only panels matching that leaf show it). (lay-rule-h pose {:y-intercept 3}) – root-level, flows to every panel (lay-rule-h pose :x :y {:y-intercept 3}) – panel-scope (columns pick or create a sub-pose) (lay-rule-h pose {:y-intercept 3 :color “red” :alpha 0.5}) (lay-rule-h pose {:y-intercept (java.time.LocalDate/parse “2024-01-01”)})

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-rule-h {:y-intercept 3.0}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-band-v

[_pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :band-v layer – vertical shaded band between x = x-min and x = x-max. Position comes from opts (not data columns); :x-min and :x-max are required and :x-min must be <= :x-max. Accepts :x-min (required), :x-max (required), :color (literal string), :alpha. The 4-arity finds or creates a sub-pose with these x/y columns and attaches the band there (only panels matching that leaf show it). (lay-band-v pose {:x-min 4 :x-max 6}) – root-level, flows to every panel (lay-band-v pose :x :y {:x-min 4 :x-max 6}) – panel-scope (columns pick or create a sub-pose) (lay-band-v pose {:x-min 4 :x-max 6 :color “blue” :alpha 0.3})

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-band-v {:x-min 5.5 :x-max 6.5}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

lay-band-h

[_pose-or-data]

[pose-or-data x-or-opts]

[pose-or-data x y-or-opts]

[pose-or-data x y opts]

Add :band-h layer – horizontal shaded band between y = y-min and y = y-max. Position comes from opts (not data columns); :y-min and :y-max are required and :y-min must be <= :y-max. Accepts :y-min (required), :y-max (required), :color (literal string), :alpha. The 4-arity finds or creates a sub-pose with these x/y columns and attaches the band there (only panels matching that leaf show it). (lay-band-h pose {:y-min 2 :y-max 4}) – root-level, flows to every panel (lay-band-h pose :x :y {:y-min 2 :y-max 4}) – panel-scope (columns pick or create a sub-pose) (lay-band-h pose {:y-min 2 :y-max 4 :color “blue” :alpha 0.3})

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width)
    (pj/lay-band-h {:y-min 2.5 :y-max 3.5}))
sepal widthsepal length4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

Transforms

coord

[pose coord-type]

Set coordinate transform on a pose. Coord is plot-level – it applies across every panel. On a composite pose the coord attaches to the root so every descendant leaf inherits it at plan time. (coord pose :flip) – flipped coordinates.

Flip axes:

(-> (rdatasets/datasets-iris)
    (pj/lay-bar :species) (pj/coord :flip))
species05101520253035404550setosaversicolorvirginica

Polar coordinates:

(-> (rdatasets/datasets-iris)
    (pj/lay-bar :species) (pj/coord :polar))

scale

[pose channel scale-type]

Set scale on a pose. Scale is plot-level – it applies across every panel. Accepts a type keyword or a scale spec map with :type, optional :domain, and optional :breaks (explicit tick locations). On a composite pose the scale attaches to the root so every descendant leaf inherits it at plan time.

Axis channels (:x, :y) accept :linear, :log, :categorical. Continuous visual channels (:size, :alpha, :fill, :color) accept :linear and :log only – :categorical does not apply. Discrete visual channels (:shape, :group) accept :categorical only – :linear and :log do not apply to a discrete encoding. The :domain on a discrete scale gives explicit category order for the legend.

(scale pose :x :log) – log scale on x-axis (scale pose :x {:type :categorical :domain […]}) – explicit category order (scale pose :y {:type :linear :breaks [0 5 10]}) – pin tick locations (scale pose :y {:type :log :domain [1 1000]}) – log scale with explicit range (scale pose :size :log) – log-spaced point sizes (scale pose :fill :log) – log-spaced tile fill (scale pose :shape {:type :categorical :domain […]}) – shape legend order

Log scale:

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width) (pj/scale :x :log))
sepal widthsepal length52.02.53.03.54.04.5

Fixed domain:

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width) (pj/scale :x {:domain [3 9]}))
sepal widthsepal length34567892.02.53.03.54.04.5

Log scale on a visual channel (:size, :alpha, :fill, or :color):

(-> {:user [:a :b :c] :n [10 100 1000]}
    (pj/lay-point :user :n {:size :n :x-type :categorical})
    (pj/scale :size :log))
nusern10.0100.01000.0abc01002003004005006007008009001000

Faceting

facet

[pose col]

[pose col direction]

Facet a pose by a column. Direction is :col (default, horizontal row) or :row (vertical column). Faceting is plot-level – every panel is faceted the same way. Composite poses are not supported yet (see dev-notes/facet-composite-deferral.md).

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width {:color :species})
    (pj/facet :species))
sepal widthsepal lengthspeciessetosaversicolorvirginica682.02.53.03.54.04.56868setosaversicolorvirginica

facet-grid

[pose col-col row-col]

Facet a pose by two columns (2D grid). Faceting is plot-level – every panel is faceted the same way. Composite poses are not supported yet (see dev-notes/facet-composite-deferral.md).

(-> (rdatasets/reshape2-tips)
    (pj/lay-point :total-bill :tip {:color :sex})
    (pj/facet-grid :smoker :sex))
tiptotal billsexFemaleMale51020405102040NoYesFemaleMale

Composition

arrange

[plots]

[plots opts]

Arrange multiple leaf poses in a grid. Returns a composite pose that renders through the compositor via membrane – so :svg, :bufimg, and any other membrane target work uniformly.

Inputs must be leaf poses. Pre-rendered hiccup is not accepted; build your own [:div ...] if you need to combine already-rendered values outside the library.

Opts: :cols N explicit column count (default: min(4, n-plots)) :title STRING centered title band above the grid :width W total composite width in pixels :height H total composite height in pixels :share-scales S subset of #{:x :y} shared across cells (default: #{})

(arrange [fr-a fr-b]) – 1x2 row (arrange [fr-a fr-b fr-c] {:cols 2 :width 900}) – 2x2 grid (wraps) (arrange [[fr-a fr-b] [fr-c fr-d]]) – explicit 2x2 grid

(pj/arrange [(-> (rdatasets/datasets-iris)
                 (pj/lay-point :sepal-length :sepal-width {:color :species})
                 (pj/options {:width 250 :height 200}))
             (-> (rdatasets/datasets-iris)
                 (pj/lay-point :petal-length :petal-width {:color :species})
                 (pj/options {:width 250 :height 200}))]
            {:cols 2})
sepal widthsepal length682.02.53.03.54.04.5petal widthpetal length50.00.51.01.52.02.5speciessetosaversicolorvirginica

Rendering

plot

[pose]

[pose opts]

Render a pose to a figure. The format keyword in the pose’s :opts ({:format :svg} – default; {:format :bufimg} for raster PNG via Java2D; or any other registered backend) selects which plan->plot / membrane->plot defmethod runs.

On a composite pose, leaves are rendered individually and tiled via the layout in the resolved chrome, in the same chosen format. The pose flows through the canonical pose -> draft -> plan -> membrane -> plot pipeline for both leaf and composite shapes. (plot pose) (plot pose {:width 800 :title “My Plot”}) (plot pose {:format :bufimg}) ;; returns a BufferedImage

See the Customization notebook for options (title, theme, tooltip, brush, legend position, palette).

(-> tiny
    (pj/lay-point :x :y))
yx1.01.52.02.53.03.54.04.55.01.01.52.02.53.03.54.04.55.0

options

[pose opts]

Set plot-level options (title, labels, width, height, etc.). Nested maps (e.g. :theme) are deep-merged. :width and :height are coerced to long (rounded) so the plan carries integer pixel dimensions through to render. On a composite pose the options attach to the root so every descendant leaf inherits them at plan time.

Set render options on a pose:

(-> tiny
    (pj/lay-point :x :y)
    (pj/options {:width 400 :height 200 :title "Small Plot"}))
Small Plotyx1234524

Predicates

pose?

[x]

Return true if x is a pose-shaped plain map (a map carrying at least one of :layers or :poses).

Check whether a value is a pose (leaf or composite):

(pj/pose? (-> tiny (pj/pose :x :y) pj/lay-point))
true

plan?

[x]

Return true if x is a plan (leaf or composite) – the resolved geometry returned by pj/plan.

Check whether a value is a plan (from pj/plan):

(pj/plan? (pj/plan (pj/lay-point tiny :x :y)))
true

plan-layer?

[x]

Return true if x is a plan-layer (resolved geometry for one mark).

Check whether a value is a resolved plan layer:

(pj/plan-layer? (first (:layers (first (:panels (pj/plan (pj/lay-point tiny :x :y)))))))
true

layer-type?

[x]

Return true if x is a layer type (mark + stat + position bundle from the registry).

Check whether a value is a registered layer-type map:

(pj/layer-type? (pj/layer-type-lookup :point))
true

Inspection

draft

[pose]

[pose opts]

Resolve a pose into a draft. For a leaf pose, returns a vector of flat maps – one per applicable layer, with all scope merged: data, mappings, and layer type fully determined. For a composite pose, returns a CompositeDraft carrying per-leaf drafts (each contextualized – shared-scale domains injected, suppress-* flags applied), the resolved chrome geometry, and the layout (path -> rect). The 2-arity folds opts into the pose first via pj/options, mirroring the 2-arity of pj/plan and pj/plot. (draft pose) (draft pose {:width 800 :title “Plot”})

Flatten a pose into a vector of draft layers – one per applicable layer, with all scope merged. Useful for inspecting exactly what the renderer will draw:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width)
    pj/lay-point
    pj/draft
    kind/pprint)
[{:x :sepal-length,
  :y :sepal-width,
  :mark :point,
  :stat :identity,
  :layer-type :point,
  :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}]

plan

[pose]

[pose opts]

Convert a pose into a plan. For a leaf pose, returns a Plan record with one panel per facet variant. For a composite pose, returns a CompositePlan record with :sub-plots tying each leaf path to its rect and sub-plan, plus :chrome carrying the resolved layout geometry (title-band, grid-rect, strip labels, shared-legend spec). (plan pose) (plan pose {:title “My Plot”})

Returns the intermediate plan data structure:

(def plan1 (-> tiny
               (pj/lay-point :x :y)
               pj/plan))
plan1
{:panels
 [{:coord :cartesian,
   :y-domain [0.8 5.2],
   :x-scale {:type :linear},
   :x-domain [0.8 5.2],
   :x-ticks
   {:values [1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0],
    :labels ["1.0" "1.5" "2.0" "2.5" "3.0" "3.5" "4.0" "4.5" "5.0"],
    :categorical? false},
   :col 0,
   :layers
   [{:mark :point,
     :style {:opacity 0.75, :radius 3.0},
     :size-scale nil,
     :alpha-scale nil,
     :groups
     [{:color [0.2 0.2 0.2 1.0], :xs #tech.v3.dataset.column<int64>[5]
:x
[1, 2, 3, 4, 5], :ys #tech.v3.dataset.column<int64>[5]
:y
[2, 4, 1, 5, 3], :row-indices #tech.v3.dataset.column<int64>[5]
:__row-idx
[0, 1, 2, 3, 4]}],
     :y-domain [1 5],
     :x-domain [1 5]}],
   :y-scale {:type :linear},
   :y-ticks
   {:values [1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0],
    :labels ["1.0" "1.5" "2.0" "2.5" "3.0" "3.5" "4.0" "4.5" "5.0"],
    :categorical? false},
   :row 0}],
 :width 600,
 :height 400,
 :caption nil,
 :total-width 600.0,
 :legend-position :none,
 :layout-type :single,
 :layout
 {:subtitle-pad 0,
  :legend-w 0,
  :caption-pad 0,
  :y-label-pad 42.5,
  :legend-h 0.0,
  :title-pad 0,
  :strip-h 0,
  :x-label-pad 38,
  :strip-w 0.0},
 :grid {:rows 1, :cols 1},
 :legend nil,
 :panel-height 362.0,
 :title nil,
 :y-label "y",
 :alpha-legend nil,
 :x-label "x",
 :subtitle nil,
 :panel-width 557.5,
 :size-legend nil,
 :total-height 400.0,
 :tooltip nil,
 :margin 10}

svg-summary

[svg-or-pose]

[svg-or-pose theme]

Extract structural summary from SVG hiccup for testing. Returns a map with :width, :height, :panels, :points, :lines, :polygons, :tiles, :visible-tiles, and :texts – useful for asserting plot structure. Accepts SVG hiccup or a pose (auto-renders to SVG first). (svg-summary (plot fr)) – summary of rendered SVG (svg-summary my-pose) – auto-renders pose (leaf or composite)

(-> (rdatasets/datasets-iris)
    (pj/lay-point :sepal-length :sepal-width {:color :species}) pj/svg-summary)
{:sizes #{3.0},
 :texts
 ["sepal width"
  "sepal length"
  "species"
  "setosa"
  "versicolor"
  "virginica"
  "4.5"
  "5.0"
  "5.5"
  "6.0"
  "6.5"
  "7.0"
  "7.5"
  "8.0"
  "2.0"
  "2.5"
  "3.0"
  "3.5"
  "4.0"
  "4.5"],
 :width 600.0,
 :lines 0,
 :colors #{"none" "rgb(228,26,28)" "rgb(55,126,184)" "rgb(77,175,74)"},
 :points 150,
 :alphas #{0.75},
 :tiles 0,
 :polygons 0,
 :visible-tiles 0,
 :panels 1,
 :height 400.0,
 :shapes #{:rect}}

valid-plan?

[plan]

Check if a plan conforms to the Malli schema. (valid-plan? (plan pose)) – true if valid

(pj/valid-plan? plan1)
true

explain-plan

[plan]

Explain why a plan does not conform to the Malli schema. Returns nil if valid, or a Malli explanation map if invalid. (explain-plan (plan pose))

(pj/explain-plan plan1)
nil

Pipeline

plan->membrane

[plan-data]

[plan-data opts]

Convert a plan into a membrane drawable tree. The 1-arity uses no rendering options. The 2-arity takes an opts map with optional :tooltip, :theme, :palette, etc. (plan->membrane (plan fr)) (plan->membrane (plan fr) {:tooltip true})

(def m1 (pj/plan->membrane plan1))
(vector? m1)
true

membrane->plot

[membrane-tree format opts]

Convert a membrane drawable tree into a figure for the given format. Dispatches on format keyword; :svg is always available. (membrane->plot (plan->membrane (plan pose)) :svg {})

(first (pj/membrane->plot m1 :svg
                          {:total-width (:total-width plan1)
                           :total-height (:total-height plan1)}))
:svg

plan->plot

[plan format opts]

Convert a plan into a figure for the given format. Dispatches on format keyword. Each renderer is a separate namespace that registers a defmethod; :svg is always available. (plan->plot (plan fr) :svg {}) (plan->plot (plan fr) :plotly {})

(first (pj/plan->plot plan1 :svg {}))
:svg

Configuration

config

[]

Return the effective resolved configuration as a map. Merges: library defaults < plotje.edn < set-config! < config. Useful for inspecting which values are in effect. (config) – show current resolved config

(pj/config)
{:strict false,
 :margin-multi 10,
 :validate true,
 :point-stroke "none",
 :title-offset 18,
 :tick-spacing-y 40,
 :panel-size 200,
 :min-panel-size 20,
 :label-offset 38,
 :label-font-size 13,
 :default-color "#333",
 :width 600,
 :legend-header-pad 20,
 :point-stroke-width 0,
 :annotation-dash [4 3],
 :legend-width 100,
 :legend-entry-height 18,
 :theme {:bg "#E8E8E8", :grid "#F5F5F5", :font-size 11},
 :bin-method :sturges,
 :domain-padding 0.05,
 :strip-height 16,
 :point-opacity 0.75,
 :line-width 2.5,
 :grid-stroke-width 0.6,
 :tick-spacing-x 60,
 :strip-font-size 10,
 :title-font-size 15,
 :band-opacity 0.15,
 :bar-opacity 0.85,
 :annotation-stroke "#333",
 :height 400,
 :margin 10,
 :point-radius 3.0}

set-config!

[m]

Set global config overrides. Persists across calls until reset. (set-config! {:palette :dark2 :theme {:bg “#FFFFFF”}}) (set-config! nil) – reset to defaults

with-config

[config-map & body]

Execute body with thread-local config overrides. Overrides take precedence over set-config! and defaults, but plot options still win. (with-config {:theme {:bg “#FFF”}} (plot …))

(pj/with-config {:palette :pastel1}
  (:palette (pj/config)))
:pastel1

Documentation Metadata

Three maps document the option keys at each scope level.

config-key-docs

Documentation metadata for configuration keys. Maps each config key to [category description]. Use with (pj/config) to build reference tables.

(count pj/config-key-docs)
37

plot-option-docs

Documentation for plot-level option keys. These are accepted by pj/options, pj/plan, and pj/plot but are inherently per-plot (text content or nested config override). Maps each key to [category description].

(count pj/plot-option-docs)
14

layer-option-docs

Documentation for layer option keys accepted by lay- functions. Maps each key to a description string.

(count pj/layer-option-docs)
29

Layer Type Registry

layer-type-lookup

[k]

Look up a registered layer type by keyword. Returns the layer-type map (with :mark, :stat, :position, :doc), or nil if not found. (layer-type-lookup :histogram) => {:mark :bar, :stat :bin, …}

(pj/layer-type-lookup :smooth)
{:mark :line,
 :stat :loess,
 :accepts
 [:confidence-band
  :bootstrap-resamples
  :bandwidth
  :size
  :nudge-x
  :nudge-y],
 :doc
 "Smoothed trend line — defaults to LOESS; pass {:stat :linear-model} for OLS."}

registered-layer-types

[]

Return all registered layer types as a map of keyword -> layer-type map. Useful for generating documentation tables.

(count (pj/registered-layer-types))
26
(first (pj/registered-layer-types))
[:smooth
 {:mark :line,
  :stat :loess,
  :accepts
  [:confidence-band
   :bootstrap-resamples
   :bandwidth
   :size
   :nudge-x
   :nudge-y],
  :doc
  "Smoothed trend line — defaults to LOESS; pass {:stat :linear-model} for OLS."}]

Documentation Helpers

Query the self-documenting dispatch tables for any extensible concept.

stat-doc

[k]

Return the prose description for a stat keyword. Returns “(no description)” if no [:key :doc] defmethod is registered. (stat-doc :bin) => “Bin numerical values into ranges”

(pj/stat-doc :linear-model)
"Linear model — OLS regression line + optional confidence band"

mark-doc

[k]

Return the prose description for a mark keyword. Returns “(no description)” if no [:key :doc] defmethod is registered. (mark-doc :point) => “Filled circle”

(pj/mark-doc :point)
"Filled circle"

position-doc

[k]

Return the prose description for a position keyword. Returns “(no description)” if no [:key :doc] defmethod is registered. (position-doc :dodge) => “Shift groups side-by-side within a band”

(pj/position-doc :dodge)
"Shift groups side-by-side within a band"

scale-doc

[k]

Return the prose description for a scale keyword. Returns “(no description)” if no [:key :doc] defmethod is registered. (scale-doc :linear) => “Continuous linear mapping”

(pj/scale-doc :linear)
"Continuous linear mapping"

coord-doc

[k]

Return the prose description for a coordinate type keyword. Returns “(no description)” if no [:key :doc] defmethod is registered. (coord-doc :polar) => “Radial mapping: x->angle, y->radius”

(pj/coord-doc :cartesian)
"Standard x-right, y-up mapping"

membrane-mark-doc

[k]

Return the prose description for how a mark renders to membrane drawables. Returns “(no description)” if no [:key :doc] defmethod is registered. (membrane-mark-doc :point) => “Translated colored rounded-rectangles”

(pj/membrane-mark-doc :point)
"Translated colored rounded-rectangles"

Export

save

[pose path]

[pose path opts]

Save a plot to a file. Format resolution, in precedence order: 1. :format in the pose’s :opts (or the 3-arity opts map) wins. 2. Otherwise inferred from the path extension (.svg -> :svg, .png -> :bufimg). 3. Default :svg.

When the resolved format and the path extension disagree, prints a warning – the file still gets the bytes the resolved format produces, but the extension is misleading.

pose – a pose. path – file path (string or java.io.File). opts – same options as plot (:format, :width, :height, :title, …). Tooltip and brush interactivity are not included in saved files. Returns the path. (save my-pose “plot.svg”) ;; SVG (save my-pose “plot.png”) ;; inferred PNG (save my-pose “plot.svg” {:format :bufimg}) ;; opts override (warns)

Save a plot to an SVG file:

(let [path (str (java.io.File/createTempFile "plotje-example" ".svg"))]
  (-> (rdatasets/datasets-iris)
      (pj/lay-point :sepal-length :sepal-width {:color :species})
      (pj/save path {:title "Iris Export"}))
  (.contains (slurp path) "<svg"))
true

save-png

[pose path]

[pose path opts]

Save a plot as a PNG file. Convenience wrapper around pj/save that pins :format :bufimg. Equivalent to: (pj/save pose path (assoc opts :format :bufimg)) pose – a pose. path – file path (string or java.io.File). opts – same options as save (:width, :height, :title, :theme, …). Returns the path. (save-png my-pose “plot.png”) (save-png my-pose “plot.png” {:width 800 :height 600})

Save a plot to a PNG file via membrane’s Java2D backend. Returns the path:

(let [path (str (java.io.File/createTempFile "plotje-example" ".png"))]
  (-> (rdatasets/datasets-iris)
      (pj/lay-point :sepal-length :sepal-width {:color :species})
      (pj/save-png path))
  (.exists (java.io.File. ^String path)))
true
source: notebooks/plotje_book/api_reference.clj