15 Cookbook
Practical plotting recipes β how to combine marks, overlay stats, and build publication-ready charts.
(ns napkinsketch-book.cookbook
(:require
;; Shared datasets for these docs
[napkinsketch-book.datasets :as data]
;; Tablecloth β dataset manipulation
[tablecloth.api :as tc]
;; Kindly β notebook rendering protocol
[scicloj.kindly.v4.kind :as kind]
;; Napkinsketch β composable plotting
[scicloj.napkinsketch.api :as sk]
;; Fastmath β random number generation
[fastmath.random :as rng]
;; Java-time β idiomatic date/time construction
[java-time.api :as jt]))Quick Recipes
Boxplot with jittered points
Overlay raw observations on a boxplot summary. The auto-jitter detects the categorical axis and constrains points to the band width.
(-> data/iris
(sk/lay-boxplot :species :sepal_length)
(sk/lay-point {:jitter true :alpha 0.3}))Histogram with density overlay
Normalize the histogram to density scale so it is comparable with the KDE (kernel density estimation) curve.
(-> data/iris
(sk/lay-histogram :sepal_length {:normalize :density :alpha 0.5})
sk/lay-density)Scatter with regression lines
Fit a linear regression per group to reveal trends across species.
(-> data/iris
(sk/view :sepal_length :sepal_width {:color :species})
(sk/lay-point {:alpha 0.6})
sk/lay-lm)Violin with jittered points
Show the density shape and every observation together.
(-> data/iris
(sk/lay-violin :species :petal_width {:alpha 0.3})
(sk/lay-point {:jitter true :alpha 0.4}))Time series with multiple layers
Combine area, line, and points. Date columns are detected automatically β ticks snap to calendar boundaries.
(def ts-dates (take 52 (jt/iterate jt/plus (jt/local-date 2020 1 6) (jt/weeks 1))))(def ts-ds {:date ts-dates
:value (map #(+ 100.0 (* 30.0 (Math/sin (* (double %) 0.12))))
(range 52))})(-> ts-ds
(sk/lay-area :date :value {:alpha 0.2})
sk/lay-line
(sk/lay-point {:alpha 0.5}))Faceted comparison
Split a scatter plot by species to compare patterns side by side.
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species})
(sk/facet :species))Annotated chart
Add reference lines and shaded bands to highlight regions of interest. Pass {:alpha β¦} to control band opacity.
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species})
(sk/lay (sk/rule-h 3.0) (sk/band-v 5.5 6.5 {:alpha 0.3})))Ridgeline with color
Compare distribution shapes across categories with overlapping density curves. Grid lines at each baseline aid comparison.
(-> data/iris
(sk/lay-ridgeline :species :sepal_length {:color :species}))Stacked bars (proportions)
Show the proportion of each species per island using 100% stacked bars.
(-> data/penguins
(sk/lay-stacked-bar-fill :island {:color :species}))Multi-Layer Compositions
Overall regression with per-group points
Color points by group, but fit a single overall regression line.
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species})
sk/lay-lm)Points with Error Bars
Combining point and errorbar layers shows measurements with uncertainty.
(def experiment
{:condition ["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]})(-> experiment
(sk/lay-point :condition :mean {:size 5})
(sk/lay-errorbar {:ymin :ci_lo :ymax :ci_hi}))Lollipop with error bars
Composing lollipop stems with error bars.
(-> experiment
(sk/lay-lollipop :condition :mean)
(sk/lay-errorbar {:ymin :ci_lo :ymax :ci_hi}))Summary (Mean Β± SE) with Raw Data
The summary method computes mean and SE (standard error) per category.
(-> data/iris
(sk/lay-point :species :sepal_length {:alpha 0.3 :jitter 5})
(sk/lay-summary {:color :species}))Tipping behavior
Scatter + per-group regression to compare smoker tipping patterns.
(-> data/tips
(sk/view :total_bill :tip {:color :smoker})
sk/lay-point
sk/lay-lm
(sk/options {:title "Tipping Behavior"
:x-label "Total Bill ($)"
:y-label "Tip ($)"}))More Recipes
Confidence ribbon
A scatter plot with per-group linear regressions and 95% confidence ribbons.
(-> data/iris
(sk/view :sepal_length :sepal_width {:color :species})
(sk/lay-point {:alpha 0.5})
(sk/lay-lm {:se true})
(sk/options {:title "Sepal Regression with Confidence Bands"}))Stacked vs grouped bars
Side-by-side comparison: default dodged bars vs stacked bars.
(-> data/tips
(sk/lay-bar :day {:color :sex})
(sk/options {:title "Dodged Bars (default)"}))(-> data/tips
(sk/lay-stacked-bar :day {:color :sex})
(sk/options {:title "Stacked Bars"}))Step line
A step plot for discrete time series data β useful when values hold constant between observations.
(def daily-temps
{:day (range 1 15)
:temp [12 14 14 16 18 17 15 13 14 16 19 21 20 18]})(-> daily-temps
(sk/lay-step :day :temp {:color "#2196F3"})
(sk/lay-point {:color "#2196F3" :size 3})
(sk/options {:title "Daily Temperature (Step)"}))Contour + scatter
Density contour lines overlaid on a scatter plot β reveals high-density regions in a point cloud.
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species :alpha 0.4})
(sk/lay-contour {:levels 5}))Label marks
Annotate specific data points with text labels.
(def top5 (-> data/iris (tc/order-by :sepal_length :desc) (tc/head 5)))(-> top5
(sk/lay-point :sepal_length :sepal_width {:size 5})
(sk/lay-label {:text :species :nudge-y 0.15}))Custom palette map
Assign specific colors to each category using a palette map.
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species})
(sk/options {:palette {:setosa "#E91E63"
:versicolor "#4CAF50"
:virginica "#2196F3"}
:title "Custom Palette Map"}))Fixed aspect ratio
Use sk/coord :fixed so one unit on x equals one unit on y. This makes the plot square when x and y have equal ranges.
(-> data/iris
(sk/view :sepal_length :sepal_width {:color :species})
sk/lay-point
sk/lay-lm
(sk/coord :fixed)
(sk/options {:title "Fixed Aspect Ratio"}))Diverging color scale
Use :color-scale :diverging with :color-midpoint to center a red-white-blue gradient on a meaningful value (e.g., zero).
(-> {:x (range 20)
:y (map #(Math/sin (/ % 3.0)) (range 20))
:change (map #(- % 10) (range 20))}
(sk/lay-point :x :y {:color :change})
(sk/options {:color-scale :diverging
:color-midpoint 0
:title "Diverging Color Scale"}))LOESS (Local Regression) Confidence Ribbon
Add {:se true} to a LOESS smoother for a bootstrap confidence band.
(-> data/iris
(sk/view :sepal_length :sepal_width {:color :species})
sk/lay-point
(sk/lay-loess {:se true})
(sk/options {:title "LOESS with 95% CI"}))Multi-plot dashboard
Use sk/arrange to combine independent plots into a grid layout.
(def iris-sepal
(-> data/iris
(sk/lay-point :sepal_length :sepal_width {:color :species})
(sk/options {:title "Sepal" :width 300 :height 250})))(def iris-petal
(-> data/iris
(sk/lay-point :petal_length :petal_width {:color :species})
(sk/options {:title "Petal" :width 300 :height 250})))(sk/arrange [iris-sepal iris-petal]
{:title "Iris Dashboard" :cols 2})Labeled scatter
Combine points with text labels, using nudge to offset text from data points.
(def top-cities
{:city ["Tokyo" "Delhi" "Shanghai" "SΓ£o Paulo" "Mumbai"]
:population [37.4 32.9 29.2 22.4 21.7]
:area [2194 1484 6341 1521 603]})(-> top-cities
(sk/lay-point :area :population)
(sk/lay-text {:text :city :nudge-y 1.0})
(sk/options {:title "Population vs Area"}))Simulated Data
Generate data from a known model and verify the regression recovers it.
(let [r (rng/rng :jdk 77)
xs (range 0 10 0.5)
ys (map #(+ (* 3 %)
5
(* 2 (- (rng/drandom r) 0.5)))
xs)]
(-> {:x xs :y ys}
(sk/lay-point :x :y)
sk/lay-lm
(sk/options {:title "Simulated: y = 3x + 5 + noise"})))Analytical Walkthroughs
Palmer Penguins
Bill dimensions separate the three species clearly.
(-> data/penguins
(sk/lay-point :bill_length_mm :bill_depth_mm {:color :species})
(sk/options {:title "Palmer Penguins: Bill Dimensions"}))Per-species regression reveals different slopes.
(-> data/penguins
(sk/view :bill_length_mm :bill_depth_mm {:color :species})
sk/lay-point
sk/lay-lm
(sk/options {:title "Bill Length vs Depth with Regression"}))Without grouping, the overall trend appears negative β an example of Simpsonβs paradox.
(-> data/penguins
(sk/lay-point :bill_length_mm :bill_depth_mm {:color :species})
sk/lay-lm
(sk/options {:title "Simpson's Paradox: Overall vs Per-Group Trend"}))Species distribution across islands.
(-> data/penguins
(sk/lay-bar :island {:color :species})
(sk/options {:title "Species by Island"}))Flipper length vs body mass β a strong positive correlation.
(-> data/penguins
(sk/view :flipper_length_mm :body_mass_g {:color :species})
sk/lay-point
sk/lay-lm
(sk/options {:title "Flipper Length vs Body Mass"}))Body mass distribution by species.
(-> data/penguins
(sk/lay-histogram :body_mass_g {:color :species})
(sk/options {:title "Body Mass Distribution"}))Tips
Tipping behavior: smokers vs non-smokers.
(-> data/tips
(sk/view :total_bill :tip {:color :smoker})
sk/lay-point
sk/lay-lm
(sk/options {:title "Tipping: Smokers vs Non-Smokers"
:x-label "Total Bill ($)" :y-label "Tip ($)"}))Tip amounts by day, colored by meal time.
(-> data/tips
(sk/lay-bar :day {:color :time})
(sk/options {:title "Visits by Day and Meal Time"}))Stacked view of the same data.
(-> data/tips
(sk/lay-stacked-bar :day {:color :time})
(sk/options {:title "Visits by Day (Stacked)"}))Horizontal bar chart of party sizes.
(-> data/tips
(sk/lay-bar :day {:color :sex})
(sk/coord :flip)
(sk/options {:title "Day by Gender (Horizontal)"}))MPG
Horsepower vs fuel efficiency, colored by origin.
(-> data/mpg
(sk/view :horsepower :mpg {:color :origin})
sk/lay-point
sk/lay-lm
(sk/options {:title "Horsepower vs MPG by Origin"}))Displacement vs MPG β another negative correlation.
(-> data/mpg
(sk/lay-point :displacement :mpg {:color :origin})
(sk/options {:title "Engine Displacement vs Fuel Efficiency"}))Count of cars by origin.
(-> data/mpg
(sk/lay-bar :origin)
(sk/options {:title "Cars by Origin"}))Whatβs Next
- Configuration β control dimensions, palettes, and themes at every scope
- Customization β annotations, tooltips, and brush selection