4  Pose Model

Plotje is a composable plotting library inspired by Wilkinsonโ€™s Grammar of Graphics and Juliaโ€™s AlgebraOfGraphics.jl. Its operators are shaped by Clojure idioms โ€“ threading, merge, plain maps โ€“ rather than a custom DSL.

This chapter introduces the mental model in five ideas. Each idea shows a rendered plot followed by the printed pose value, so you can see both what the library produces and the data structure underneath.

(ns plotje-book.pose-model
  (:require
   ;; Kindly -- notebook rendering protocol
   [scicloj.kindly.v4.kind :as kind]
   ;; Rdatasets -- standard datasets
   [scicloj.metamorph.ml.rdatasets :as rdatasets]
   ;; Plotje -- composable plotting
   [scicloj.plotje.api :as pj]))

Idea 1: A pose describes a plot

In Plotje, every plot you compose is a pose โ€“ a plain Clojure value that describes what to show. The composition functions (pj/pose, pj/lay-*, pj/options, pj/scale, pj/coord, pj/facet, pj/arrange) all take a pose and return a pose, so plots build up through ordinary -> threading. Output functions (pj/plan, pj/plot, pj/save, pj/draft) take a pose and return a different shape โ€“ a plan, an SVG, a file path โ€“ and so close the pipeline.

Two core operators do the work: pj/pose builds a pose by declaring which columns carry which aesthetics, and pj/lay-* adds a layer to a pose. A pose is what you arrange before drawing โ€“ which columns become axes, which become aesthetics. Layers are the visual elements: points, lines, smooths, bars. A composite pose contains sub-poses arranged side by side, each able to carry its own layers.

The simplest pose carries some data and picks columns. With no explicit chart type, the library infers one from the column types:

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

Two numerical columns produced a scatter. And because a pose is plain data, you can inspect it with kind/pprint:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width)
    kind/pprint)
{:mapping {:x :sepal-length, :y :sepal-width},
 :layers [],
 :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 |
}

A pose is a plain Clojure map. The dataset lives under :data, the column mapping under :mapping, chart-type layers under :layers (empty here, since none was attached), and plot-level options under :opts.

Idea 2: Poses carry mappings

A mapping connects columns to visual properties. We added :x and :y in Idea 1; the pose also accepts appearance aesthetics like :color, :size, :alpha, and :shape:

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

The printed pose shows the full mapping:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width {:color :species})
    kind/pprint)
{:mapping {:color :species, :x :sepal-length, :y :sepal-width},
 :layers [],
 :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 |
}

All three pairs โ€“ :x -> :sepal-length, :y -> :sepal-width, :color -> :species โ€“ end up in the one :mapping map. Future layers on this pose will inherit the whole set.

Idea 3: What to show, how to show it

The API separates what to plot from how to show it: a poseโ€™s :mapping holds the โ€œwhatโ€ (columns to aesthetics), and its :layers holds the โ€œhowโ€ (one entry per chart-type layer). Declaring the mapping once lets several layers share it โ€“ scatter points and a regression line per species. Written as a literal map โ€“ pj/pose accepts the nested-map shape directly:

(def multi-layer
  (pj/pose
   {:data (rdatasets/datasets-iris)
    :mapping {:x :sepal-length :y :sepal-width :color :species}
    :layers [{:layer-type :point}
             {:layer-type :smooth :mapping {:stat :linear-model}}]}))
multi-layer
sepal widthsepal lengthspeciessetosaversicolorvirginica4.55.05.56.06.57.07.58.02.02.53.03.54.04.5

Printed, the mapping and the layers are visibly separate:

(kind/pprint multi-layer)
{: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 |
,
 :mapping {:x :sepal-length, :y :sepal-width, :color :species},
 :layers
 [{:layer-type :point}
  {:layer-type :smooth, :mapping {:stat :linear-model}}]}

:mapping answers the โ€œwhatโ€ question โ€“ which columns flow to which aesthetic โ€“ and :layers answers the โ€œhowโ€ question, with each entry naming a chart type and optional layer-specific options (:stat :linear-model on the smooth layer here).

The threaded form builds the same pose step by step: pj/pose sets the mapping, then each pj/lay-* appends a layer.

(-> (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

Printed, the threaded form produces the same shape as the explicit-map form shown earlier โ€“ :mapping at the top, :layers alongside it. pj/pose and pj/lay-* build the same pose value step by step.

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length :sepal-width {:color :species})
    pj/lay-point
    (pj/lay-smooth {:stat :linear-model})
    kind/pprint)
{:mapping {:color :species, :x :sepal-length, :y :sepal-width},
 :layers
 [{:layer-type :point} {:layer-type :smooth, :stat :linear-model}],
 :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 |
}

Idea 4: Inference fills the gaps

When you omit a choice, Plotje infers it from the data. One numerical column becomes a histogram:

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

The printed pose shows an empty :layers โ€“ the histogram layer is chosen by inference at render time, not stored on the pose:

(-> (rdatasets/datasets-iris)
    (pj/pose :sepal-length)
    kind/pprint)
{:mapping {:x :sepal-length},
 :layers [],
 :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 |
}

The principle: the inferred value fills in only when you have not specified one yourself. Explicit choices flow down the pose tree and override inference. (One subtlety: an explicit nil is a real choice and cancels inheritance โ€“ it does not fall back to inference. See Pose Rule S3 for the precise semantics.)

This works for marks (the shape shown, like points or bars), stats (the computation before rendering, like binning), color types, and grouping. See Inference Rules for the full set.

Idea 5: Poses compose

Composition functions take a pose and return a pose. A composite pose is a plain map too โ€“ with :poses holding its sub-poses and :layout describing how to tile them. Here is a two-panel composite written as an explicit map:

(def two-panel
  (pj/pose
   {:data (rdatasets/datasets-iris)
    :layout {:direction :horizontal}
    :poses [{:mapping {:x :sepal-length :y :sepal-width :color :species}
             :layers [{:layer-type :point}]}
            {:mapping {:x :petal-length :y :petal-width :color :species}
             :layers [{:layer-type :point}]}]}))
two-panel
sepal widthsepal length682.02.53.03.54.04.5petal widthpetal length50.00.51.01.52.02.5speciessetosaversicolorvirginica

Printed, its structure is visible at once:

(kind/pprint two-panel)
{: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 |
,
 :layout {:direction :horizontal},
 :poses
 [{:mapping {:x :sepal-length, :y :sepal-width, :color :species},
   :layers [{:layer-type :point}]}
  {:mapping {:x :petal-length, :y :petal-width, :color :species},
   :layers [{:layer-type :point}]}]}

The outer :data is inherited by every sub-pose. pj/arrange is the ergonomic way to build this shape from a list of already- built poses:

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

Printed, pj/arrange always wraps its plots in a top-level vertical layout whose rows are horizontal strips โ€“ a single row of two panels shows up here as a vertical-of-horizontal composite. The sub-poses themselves are clean leaf maps that match the shape of the explicit-map form above:

(-> (pj/arrange
     [(-> (rdatasets/datasets-iris)
          (pj/pose :sepal-length :sepal-width {:color :species})
          pj/lay-point)
      (-> (rdatasets/datasets-iris)
          (pj/pose :petal-length :petal-width {:color :species})
          pj/lay-point)])
    kind/pprint)
{:opts {:width 600, :height 400},
 :layout {:direction :vertical},
 :poses
 [{:layout {:direction :horizontal},
   :poses
   [{:mapping {:color :species, :x :sepal-length, :y :sepal-width},
     :layers [{: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 |
}
    {:mapping {:color :species, :x :petal-length, :y :petal-width},
     :layers [{: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 |
}]}]}

pose, lay-*, arrange, facet, options, scale, coord โ€“ all take a pose and return a pose. The pipeline reads like a sentence; composites nest the same shape inside :poses. The Composition chapter covers the multi-pose patterns in depth.

Summary

Idea In code
A pose describes a plot pj/pose, pj/lay-* return poses; inspect with kind/pprint
Poses carry mappings Column-to-aesthetic pairs live in :mapping
What vs how pj/pose declares what; pj/lay-* declares how
Inference fills gaps Omit choices, the library infers from data
Poses compose pj/arrange tiles sibling poses; composites nest under :poses

Whatโ€™s Next

source: notebooks/plotje_book/pose_model.clj