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.
- 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
The library is packaged as a CHICKEN 5 egg. Install with:
chicken-install ggplotThe following eggs must be available:
cairo- Cairo bindingsmatchable- pattern matchingdatatype- algebraic data typesstatistics- statistical functionsyasos- object system (used internally)
(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)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 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")))(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 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 parametersConvenience 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
(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")))(labs #:title "Title" #:subtitle "Subtitle" #:x "X axis" #:y "Y axis")(theme-minimal #:base-size 12.0)
(theme-classic #:base-size 12.0)
(theme-dark #:base-size 12.0)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)(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))(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))(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))(ggplot data (aes #:x 'x #:y 'y)
(layer 'point #:size 4)
(facet-wrap 'group #:ncol 2)
(theme-minimal))(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));; 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"))The modules below gg-plot can be used directly for custom plot pipelines.
(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(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)))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