7  Methods

A method is the bundle that determines how data becomes a visual element. It combines three concepts:

Layer functions (sk/lay-point, sk/lay-histogram, sk/lay-bar, sk/lay-lm, etc.) each add a layer with the corresponding method. When no layer is added, napkinsketch infers a method from the column types.

All built-in methods are registered in a data registry. The tables below are generated from that registry β€” they stay in sync with the code.

(ns napkinsketch-book.methods
  (:require
   ;; Kindly β€” notebook rendering protocol
   [scicloj.kindly.v4.kind :as kind]
   ;; Napkinsketch β€” composable plotting
   [scicloj.napkinsketch.api :as sk]
   ;; Method registry β€” for inspecting method data
   [scicloj.napkinsketch.method :as method]
   ;; String utilities
   [clojure.string :as str]))

Two helpers used by several tables below.

(defn used-by
  "Sorted comma-separated method names whose `field` equals `value`."
  [field value]
  (->> (method/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 methods, in first-seen order."
  [field]
  (let [seen (volatile! #{})]
    (reduce (fn [acc k]
              (let [v (get (method/lookup k) field)]
                (if (@seen v) acc
                    (do (vswap! seen conj v) (conj acc v)))))
            [] method/method-order)))

Methods

Each row is a registered method showing its mark, stat, and position.

(kind/table
 {:column-names ["Method" "Mark" "Stat" "Position"]
  :row-maps
  (for [k method/method-order
        :let [m (method/lookup k)]]
    {"Method" (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)))})})
Method Mark Stat Position
:point
:point
:identity
:identity
:line
:line
:identity
:identity
:step
:step
:identity
:identity
:area
:area
:identity
:identity
:stacked-area
:area
:identity
:stack
:histogram
:bar
:bin
:identity
:bar
:rect
:count
:identity
:stacked-bar
:rect
:count
:stack
:stacked-bar-fill
:rect
:count
:fill
:value-bar
:rect
:identity
:identity
:lm
:line
:lm
:identity
:loess
:line
:loess
:identity
:density
:area
:kde
:identity
:tile
:tile
:bin2d
:identity
:density2d
:tile
:kde2d
:identity
:contour
:contour
:kde2d
:identity
:boxplot
:boxplot
:boxplot
:identity
:violin
:violin
:violin
:identity
:ridgeline
:ridgeline
:violin
:identity
:summary
:pointrange
:summary
:identity
:errorbar
:errorbar
:identity
:identity
:lollipop
:lollipop
:identity
:identity
:text
:text
:identity
:identity
:label
:label
:identity
:identity
:rug
:rug
:identity
:identity

Marks

A mark is the visual shape drawn for each data point or group. Several methods may share the same mark β€” for instance, histogram and value-bar both draw bars, and lm (linear model) and loess (local regression) both draw lines.

(kind/table
 {:column-names ["Mark" "Shape" "Used by"]
  :row-maps
  (for [mk (distinct-in-order :mark)]
    {"Mark" (kind/code (pr-str mk))
     "Shape" (sk/mark-doc mk)
     "Used by" (used-by :mark mk)})})
Mark Shape Used by
:point
Filled circle point
:line
Connected path line, lm, loess
:step
Horizontal-then-vertical path step
:area
Filled region under a curve area, density, stacked-area
:bar
Vertical rectangles (binned) histogram
:rect
Positioned rectangles bar, stacked-bar, stacked-bar-fill, value-bar
:tile
Grid of colored cells density2d, tile
:contour
Iso-value polylines contour
:boxplot
Box-and-whisker boxplot
:violin
Mirrored density shape violin
:ridgeline
Stacked density curves ridgeline
:pointrange
Point with error bar summary
:errorbar
Vertical error bar errorbar
:lollipop
Stem with dot lollipop
:text
Data-driven label text
:label
Label with background box label
:rug
Axis-margin tick marks rug

Stats

A stat (statistical transform) processes raw data before rendering. Each stat takes data-space inputs and produces the geometry that its mark will draw.

(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" (sk/stat-doc st)
     "Used by" (used-by :stat st)})})
Stat What it computes Used by
:identity
Pass-through β€” no transform area, errorbar, label, line, lollipop, point, rug, stacked-area, step, text, value-bar
:bin
Bin numerical values into ranges histogram
:count
Count occurrences per category bar, stacked-bar, stacked-bar-fill
:lm
Linear model (lm) β€” OLS regression line + optional confidence band lm
:loess
LOESS (local regression) smoothing loess
:kde
KDE (kernel density estimation) β€” 1D density
:bin2d
2D grid binning (heatmap counts) tile
:kde2d
2D Gaussian KDE (kernel density estimation) contour, density2d
:boxplot
Five-number summary + outliers boxplot
:violin
KDE per category (density profile) ridgeline, violin
:summary
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" (sk/position-doc pos)
     "Used by" (used-by :position pos)})})
Position What it does Used by
:identity
Plot at exact data coordinates (groups overlap) area, bar, boxplot, contour, density, density2d, errorbar, histogram, label, line, lm, loess, lollipop, point, ridgeline, rug, step, summary, text, tile, value-bar, violin
:dodge
Shift groups side-by-side within a band
:stack
Pile groups cumulatively stacked-area, stacked-bar
:fill
Stack normalized to [0, 1] (proportions) stacked-bar-fill

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 method:

(kind/table
 {:column-names ["Option" "Description"]
  :row-maps
  (for [k method/universal-layer-options]
    {"Option" (kind/code (pr-str k))
     "Description" (get method/layer-option-docs k)})})
Option Description
:color
Column keyword (categorical grouping) or literal color string
:alpha
Column keyword (per-point opacity) or fixed number 0.0–1.0
:group
Column keyword for grouping without color
:position
Position adjustment keyword β€” how overlapping groups are arranged (see sk/position-doc)

Method-specific options

Some methods accept additional keys beyond the universal set. Methods not listed here accept only the universal options above.

(kind/table
 {:column-names ["Method" "Additional options"]
  :row-maps
  (for [k method/method-order
        :let [m (method/lookup k)
              accepts (:accepts m)]
        :when (seq accepts)]
    {"Method" (kind/code (pr-str k))
     "Additional options" accepts})})
Method Additional options
:point
[:size :shape :jitter :text :nudge-x :nudge-y]
:line
[:size :nudge-x :nudge-y]
:step
[:size]
:histogram
[:normalize]
:lm
[:se :size :nudge-x :nudge-y]
:loess
[:se :se-boot :bandwidth :size :nudge-x :nudge-y]
:density
[:bandwidth]
:tile
[:fill :kde2d-grid]
:density2d
[:kde2d-grid]
:contour
[:levels :size]
:boxplot
[:size]
:violin
[:bandwidth :size]
:ridgeline
[:bandwidth]
:summary
[:size]
:errorbar
[:ymin :ymax :size :nudge-x :nudge-y]
:lollipop
[:size]
:text
[:text :nudge-x :nudge-y]
:label
[:text :nudge-x :nudge-y]
:rug
[:side]

All layer option keys

(kind/table
 {:column-names ["Option" "Description"]
  :row-maps
  (for [[k desc] (sort-by key method/layer-option-docs)]
    {"Option" (kind/code (pr-str k))
     "Description" desc})})
Option Description
:alpha
Column keyword (per-point opacity) or fixed number 0.0–1.0
:bandwidth
Smoothing bandwidth for density and LOESS methods
:color
Column keyword (categorical grouping) or literal color string
:fill
Column keyword for tile fill values (pre-computed heatmap)
:group
Column keyword for grouping without color
:jitter
true or pixel amount β€” random offset to reduce overplotting
:kde2d-grid
2D KDE grid resolution β€” number of bins per axis (default 25)
:levels
Number of contour iso-levels (default 5)
:normalize
Histogram normalization β€” :density (area integrates to 1) or nil
:nudge-x
Shift all x-coordinates by this data-space amount
:nudge-y
Shift all y-coordinates by this data-space amount
:position
Position adjustment keyword β€” how overlapping groups are arranged (see sk/position-doc)
:se
true to show SE (standard error) confidence ribbon around fitted line
:se-boot
Number of bootstrap resamples for LOESS confidence ribbon (default 200)
:shape
Column keyword for per-point shape
:side
Rug tick position β€” :x (default), :y, or :both
:size
Column keyword or fixed number β€” point radius or stroke width
:text
Column keyword for label content
:ymax
Column keyword for upper error bound
:ymin
Column keyword for lower error bound

What’s Next

  • Scatter Plots β€” see point, line, and regression methods in action
  • Distributions β€” histograms, density, boxplots, violins
  • Customization β€” colors, palettes, themes, and per-layer options
source: notebooks/napkinsketch_book/methods.clj