Skip to content

iraikov/chicken-ggplot

Repository files navigation

ggplot

A Grammar of Graphics plotting library for CHICKEN Scheme, inspired by ggplot2. Plots are described as composable declarative S-expressions that are translated into vector graphics via the Cairo graphics library.

Features

  • Declarative, layered plot specification with ggplot + layer
  • Automatic scale training from data - no manual range computation needed
  • Continuous, discrete, logarithmic, and color scales
  • Axes with configurable tick marks and labels
  • Statistical transformations: histograms, density estimates, boxplots, violin plots, summary statistics
  • Faceted layouts (small multiples)
  • Annotation layers: text, rectangles, segments, arrows
  • Multiple output backends: PNG, SVG, PostScript, PDF (via Cairo)
  • Nine composable modules usable independently or together

Installation

The library is packaged as a CHICKEN 5 egg. Install with:

chicken-install ggplot

Dependencies

The following eggs must be available:

Quick Start

(import gg-plot gg-scales gg-aes gg-backend-cairo)

(define data
  '((x . (1 2 3 4 5))
    (y . (2.1 3.8 3.2 5.0 4.7))))

(define p
  (ggplot data (aes #:x 'x #:y 'y)
    (layer 'point #:size 6 #:color "steelblue")
    (layer 'line  #:color "steelblue" #:width 2)
    (labs  #:title "Simple scatter plot"
           #:x "X" #:y "Y")
    (theme-minimal)))

(ggsave p "plot.png" #:width 800 #:height 600)

Modules

The library is split into seven modules that can be used independently or together.

Module Purpose
gg-vge Virtual Graphics Engine — algebraic IR for graphics instructions
gg-backend Abstract backend protocol (YASOS interface)
gg-backend-cairo Cairo backend: PNG, SVG, PostScript, PDF output
gg-primitives-vge Low-level composable drawing combinators (drawers)
gg-scales Data-to-visual mappings (domain training, break computation)
gg-data Columnar data frame utilities
gg-aes Aesthetic mappings between data columns and visual channels
gg-geom Geometric objects (point, line, bar, …)
gg-guides Axes and legends
gg-plot Top-level declarative API

Data format

Data is passed as an association list of named columns:

'((time    . (0 10 20 30 40 50))
  (value   . (1.2 1.8 2.3 1.9 2.5 2.1))
  (group   . ("A" "A" "A" "B" "B" "B")))

Plot API (gg-plot)

ggplot

(ggplot data aesthetic layer ... scale ... theme ... label-spec)

Creates a complete plot specification. All arguments after the aesthetic mapping are gathered as plot elements.

layer

(layer geom-name
       #:mapping aes      ; optional per-layer aesthetic override
       #:data    data     ; optional per-layer data override
       #:stat    stat     ; optional statistical transformation
       param ...)         ; geometry-specific keyword parameters

Layer constructors

Convenience constructors matching common geometry names:

layer-point   layer-line      layer-path      layer-area
layer-bar     layer-rect      layer-text      layer-segment
layer-hline   layer-vline     layer-eventplot
layer-histogram  layer-density  layer-boxplot  layer-violin
layer-errorbar   layer-pointrange  layer-linerange  layer-crossbar
layer-col

Annotation layers (placed in data coordinates):

layer-annotate-text   layer-annotate-rect
layer-annotate-segment  layer-annotate-arrow

Scales

(scale-x-continuous #:name "label" #:limits '(0 . 100) #:trans 'log)
(scale-y-continuous #:name "label")
(scale-color-gradient #:low "white" #:high "blue")
(scale-color-manual #:values '(("A" . "red") ("B" . "blue")))
(scale-fill-manual  #:values '(("A" . "red") ("B" . "blue")))

Labels

(labs #:title "Title" #:subtitle "Subtitle" #:x "X axis" #:y "Y axis")

Themes

(theme-minimal  #:base-size 12.0)
(theme-classic  #:base-size 12.0)
(theme-dark     #:base-size 12.0)

Output backends

All backends are constructed from gg-backend-cairo:

(make-cairo-png-backend filename width height)   ; PNG raster
(make-cairo-svg-backend filename width height)   ; SVG vector
(make-cairo-ps-backend  filename width height)   ; PostScript
(make-cairo-pdf-backend filename width height)   ; PDF (width/height in pt; A4 = 595×842)

Render using render-plot or the ggsave convenience function:

;; Low-level: pass a backend directly
(render-plot plot (make-cairo-png-backend "out.png" 800 600))

;; Convenience: format inferred from file extension
(ggsave plot "out.png" #:width 800 #:height 600)
(ggsave plot "out.svg" #:width 800 #:height 600)
(ggsave plot "out.ps"  #:width 595 #:height 842)

Examples

Time series with confidence ribbon

(define data
  '((t     . (0 10 20 30 40 50 60 70 80 90 100))
    (value . (1.2 1.5 2.3 1.8 1.4 1.9 2.5 2.1 1.7 2.0 2.3))
    (upper . (1.5 1.8 2.6 2.1 1.7 2.2 2.8 2.4 2.0 2.3 2.6))
    (lower . (0.9 1.2 2.0 1.5 1.1 1.6 2.2 1.8 1.4 1.7 2.0))))

(ggplot data (aes #:x 't #:y 'value)
  (layer 'area  #:mapping (aes #:ymin 'lower #:ymax 'upper)
                #:fill "lightblue" #:alpha 0.3)
  (layer 'line  #:color "steelblue" #:width 2)
  (layer 'point #:size 5 #:color "darkblue")
  (scale-x-continuous #:name "Time (s)")
  (scale-y-continuous #:name "Response (mV)")
  (labs #:title "Time Series with Confidence Band")
  (theme-minimal))

Bar chart

(define data
  '((category . ("A" "B" "C" "D"))
    (count    . (23 41 17 35))))

(ggplot data (aes #:x 'category #:y 'count)
  (layer 'bar #:fill "steelblue")
  (labs #:title "Category Counts" #:x "Category" #:y "Count")
  (theme-minimal))

Multi-series with color mapping

(ggplot data (aes #:x 'time #:y 'value #:color 'condition)
  (layer 'line  #:width 2)
  (layer 'point #:size 4)
  (scale-color-manual
    #:values '(("Control" . "steelblue") ("Treatment" . "firebrick")))
  (labs #:title "Condition Comparison")
  (theme-minimal))

Faceted small multiples

(ggplot data (aes #:x 'x #:y 'y)
  (layer 'point #:size 4)
  (facet-wrap 'group #:ncol 2)
  (theme-minimal))

Logarithmic axis

(ggplot data (aes #:x 'frequency #:y 'power)
  (layer 'line #:width 2)
  (scale-x-continuous #:trans 'log10 #:name "Frequency (Hz)")
  (scale-y-continuous #:trans 'log10 #:name "Power (dB)")
  (theme-minimal))

Statistical geometries

;; Error bars from raw data (computes mean +/- SE automatically)
(ggplot iris (aes #:x 'species #:y 'sepal_length)
  (layer-pointrange #:stat 'summary)
  (labs #:title "Mean Sepal Length ± SE by Species"))

;; Boxplot
(ggplot iris (aes #:x 'species #:y 'petal_length)
  (layer 'boxplot #:fill "lightblue")
  (labs #:title "Petal Length by Species"))

Lower-level usage

The modules below gg-plot can be used directly for custom plot pipelines.

Scales (gg-scales)

(import gg-scales)

(define s (make-scale-linear))
(scale-train! s '(0 1 2 3 4 5))
(scale-set-range! s '(80 . 720))
(scale-map s 2.5)    ; pixel coordinate
(scale-breaks s 5)   ; list of tick positions

Drawing primitives (gg-primitives-vge)

(import gg-primitives-vge gg-vge gg-backend-cairo)

;; Drawers are pure values; combine composes them left-to-right
(define fig
  (combine
    (with-fill-color "white" (filled-rect-drawer 0 0 800 600))
    (with-pen-color "steelblue" (circle-drawer 400 300 50))
    (text-drawer 400 560 "Hello")))

;; Render to a file via a Cairo backend
(let ((vge (make-vge)))
  (render-drawer fig vge)
  (vge-render! vge (make-cairo-png-backend "fig.png" 800 600)))

Serialisation

Plot specifications can be converted to and from S-expressions for storage, transmission, or code generation:

(define sexp (plot->sexp plot))       ; plot → S-expression
(define plot (sexp->plot sexp))       ; S-expression → plot

License

GPL-3