chickadee » ggplot

gg-plot

A declarative plotting system built on top of the Cairo graphics library which provides ggplot2-style plotting routines, with s-expression plot specifications, automatic scale training, and four output formats (PNG, SVG, PostScript, PDF).

Requirements

Overview

The library is organised into nine modules that correspond to the tiers of the Grammar of Graphics. Most users only need to (import gg-plot); the lower-level modules are available for custom rendering pipelines.

gg-plot
Full declarative plot API
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, and PDF output
gg-primitives-vge
Composable drawer abstraction; shapes, text, transforms
gg-scales
Data-to-visual mappings (linear, log, ordinal, color)
gg-data
Columnar data utilities
gg-aes
Aesthetic (column-channel) mapping
gg-geom
Geometry functions (scatter, line, bar, errorbar, raster...)
gg-guides
Axis and legend drawers

The translation pipeline

s-expression spec
  -> normalize / validate defaults
  -> train scales from all layers
  -> compute facet panels
  -> render each panel (background, geometries, axes)
  -> render global elements (title, legends)
  -> emit via Cairo (PNG / SVG / PS / PDF)

Module: gg-plot

The top-level declarative API. Import only this module for typical use.

(import gg-plot)

Plot construction

ggplot data #!rest specsprocedure

Create a plot-spec record.

data is a columnar alist. specs is a mixed list of:

(define p
  (ggplot data (aes #:x 'time #:y 'value #:color 'condition)
    (layer-line  #:width 2)
    (layer-point #:size 5)
    (scale-x-continuous #:name "Time (ms)")
    (scale-y-continuous #:name "Response (mV)")
    (scale-color-manual #:values '(("Control" . "blue") ("Treatment" . "red")))
    (theme-minimal #:base-size 12)
    (labs #:title "Treatment vs Control")))

Rendering

render-plot plot-spec backendprocedure

Execute the full rendering pipeline and write output. backend is a Cairo backend constructed with one of the make-cairo-*-backend procedures from gg-backend-cairo.

ggsave plot-spec filename #!key width height format scaleprocedure

Save to a file. format is inferred from the extension (.png, .svg, .ps) or can be given explicitly as 'png, 'svg, or 'ps. width/height default to 800×600.

ggdisplay plot-spec #!key width heightprocedure

Render to an X11 window.

Plot serialisation

plot->sexp plot-specprocedure

Convert a plot specification to a pure s-expression (no closures). The result can be written to a file with write and read back later.

sexp->plot sexpprocedure

Reconstruct a plot-spec from a serialised s-expression.

Layer constructors

All layer constructors accept #:data (override dataset), #:mapping (override or extend the plot-level aesthetic mapping), plus geometry-specific keyword arguments.

Basic geometries

layer-point #!key data mapping size shape alpha colorprocedure
layer-line #!key data mapping width style colorprocedure
layer-path #!key data mapping width colorprocedure
layer-area #!key data mapping fill alphaprocedure
layer-bar #!key data mapping fill widthprocedure
layer-rect #!key data mapping fill colorprocedure
layer-text #!key data mapping size colorprocedure
layer-segment #!key data mapping color widthprocedure
layer-eventplot #!key data mapping line-length width colorprocedure

Reference lines

layer-hline yintercept #!key color width linetype alphaprocedure
layer-vline xintercept #!key color width linetype alphaprocedure

linetype is 'solid, 'dashed, or 'dotted.

Statistical geometry layers

layer-histogram #!key data mapping bins binwidth breaks method fill color alphaprocedure
bins
number of bins (default 30)
binwidth
bin width in data units (overrides bins)
method
'sturges (default), 'scott, 'fd, 'equal-width
layer-density #!key data mapping bandwidth kernel n adjust fill color alphaprocedure
kernel
'gaussian (default), 'epanechnikov, 'rectangular, 'triangular, 'biweight
n
number of evaluation points (default 512)
layer-boxplot #!key data mapping coef varwidth fill color outlier-color outlier-size widthprocedure
coef
IQR multiplier for whisker length (default 1.5)
layer-violin #!key data mapping scale draw-quantiles bandwidth kernel fill color alphaprocedure
scale
'area (equal area, default) or 'count (proportional to n)
draw-quantiles
list of quantile levels, e.g. '(0.25 0.5 0.75)
layer-errorbar #!key data mapping stat fun-ymin fun-ymax color width cap-widthprocedure
stat
'identity (use ymin/ymax columns) or 'summary (compute from raw values)
layer-pointrange #!key data mapping stat fun-y fun-ymin fun-ymax color point-size line-widthprocedure
layer-linerange #!key data mapping stat fun-ymin fun-ymax color widthprocedure
layer-crossbar #!key data mapping stat fun-y fun-ymin fun-ymax fill color widthprocedure
layer-col #!key data mapping fun position fill color widthprocedure
position
'stack (default), 'dodge, 'fill

Annotation layers

layer-annotate-text text x y #!key size color hjust vjust angleprocedure
layer-annotate-rect xmin ymin xmax ymax #!key fill alpha color line-widthprocedure
layer-annotate-segment x1 y1 x2 y2 #!key color widthprocedure
layer-annotate-arrow x1 y1 x2 y2 #!key color widthprocedure

Coordinates are in data space.

For reference lines with full linetype support, the following are recommended over layer-hline/layer-vline when annotation-layer dispatch is needed:

annotate-vline x #!key color width linetypeprocedure
annotate-hline y #!key color width linetypeprocedure
annotate-abline slope intercept #!key color widthprocedure

Scale specifications

Scale specification functions return tagged lists consumed by ggplot.

Continuous position scales

scale-x-continuous #!key name limits breaks trans expandprocedure
scale-y-continuous #!key name limits breaks trans expandprocedure
name
axis title string
limits
explicit domain (min max)
breaks
explicit tick positions
trans
transformation symbol: 'log, 'log10, 'sqrt, …
expand
fractional padding added to domain on each side
scale-x-log #!key name base breaksprocedure
scale-y-log #!key name base breaksprocedure

Shorthand for a continuous scale with trans: 'log and the given base (default 10).

Discrete position scales

scale-x-discrete #!key name limitsprocedure
scale-y-discrete #!key name limitsprocedure

Color / fill scales

scale-color-manual #!key valuesprocedure
scale-fill-manual #!key valuesprocedure

values is an alist: '(("Control" . "blue") ("Treatment" . "red")).

scale-color-gradient #!key low high limitsprocedure

Two-stop continuous gradient.

Coordinate systems

coord-cartesian #!key xlim ylimprocedure

Default Cartesian coordinates with optional axis limits.

coord-fixed #!key ratio xlim ylimprocedure

Fixed aspect ratio (default 1:1).

coord-flipprocedure

Swap x and y axes.

Faceting

facet-nullprocedure

No faceting (single panel, default).

facet-wrap var #!key ncol nrow scalesprocedure

Wrap panels by var (a quoted symbol). scales is one of "fixed" (default), "free", "free_x", "free_y".

facet-grid row-var col-var #!key scales space shrink labellerprocedure

Two-dimensional panel grid. Pass #f for either variable to omit that dimension.

Themes

theme-gray #!key base-size base-familyprocedure

Gray background with white grid lines (the default ggplot2-style theme).

theme-minimal #!key base-size base-familyprocedure

White background, no border, gray grid lines. base-size defaults to 11.

theme-classic #!key base-size base-familyprocedure

White background, no grid lines, axis lines present.

theme-bw #!key base-sizeprocedure

White background, black border, gray grid lines.

theme-linedraw #!key base-size base-familyprocedure

White background, black grid lines and border.

theme-light #!key base-size base-familyprocedure

Light gray border and grid lines.

theme-dark #!key base-size base-familyprocedure

Dark background with contrasting grid lines; suitable for bright-colored data.

theme-void #!key base-sizeprocedure

No background, no axes, no grid.

Legend position modifiers

theme-legend-position positionprocedure

position: 'right (default), 'left, 'top, 'bottom, 'none, 'inside, 'outside.

theme-legend-inside positionprocedure

position: 'top-right, 'top-left, 'bottom-right, 'bottom-left, 'center.

theme-legend-outside positionprocedure

position: 'right, 'left, 'top, 'bottom.

Labels

labs #!key title subtitle x y captionprocedure
xlab nameprocedure
ylab nameprocedure
ggtitle title #!optional subtitleprocedure

Collision-avoiding text

geom-text-repel ...procedure
geom-label-repel ...procedure

Repel overlapping text labels using a force-directed algorithm. Accepts the same arguments as layer-text.

Plot-spec accessors

plot-spec? objprocedure
plot-spec-data specprocedure
plot-spec-default-aes specprocedure
plot-spec-layers specprocedure
plot-spec-scales specprocedure
plot-spec-coord specprocedure
plot-spec-facet specprocedure
plot-spec-theme specprocedure
plot-spec-labels specprocedure

Module: gg-primitives-vge

Low-level composable drawing layer. A drawer is a record wrapping a procedure that emits instructions into a VGE (Virtual Graphics Engine). Drawers are first-class values: they can be stored, composed with combine, and wrapped with style or transform combinators before being rendered to any backend.

Coordinate convention: right-handed, origin at bottom-left, Y-up. All coordinates are in user space; the backend maps them to device pixels.

Drawer record

make-drawer proc boundsprocedure

Create a drawer from a procedure (vge -> void) and an optional bounding box (or #f).

drawer? objprocedure

True if obj is a drawer record.

drawer-proc drawerprocedure
drawer-bounds drawerprocedure

Accessors.

empty-drawerprocedure

A drawer that does nothing (identity for combine).

Composition

combine drawer ...procedure

Return a new drawer that executes each argument drawer left-to-right with no additional scoping.

combine-group drawer ...procedure

Like combine but wraps the result in a gfx:group scope.

Rendering

render-drawer drawer vgeprocedure

Emit a drawer's instructions into vge (a VGE accumulator created by make-vge from gg-vge). Does not perform I/O; call vge-render! afterwards to send the instructions to a backend.

Scoped state wrappers

Each wrapper produces a gfx:group, so the state change is automatically scoped; no explicit push/pop is needed.

with-pushed-state drawerprocedure

Raw push/pop scope (low-level; prefer the typed wrappers below).

with-translate dx dy drawerprocedure
with-viewport x0 y0 x1 y1 drawerprocedure
with-clip-rect x y w h drawerprocedure
with-rotate angle drawerprocedure

angle in radians.

Style wrappers

with-pen-color color drawerprocedure

color is a color string ("steelblue", "#3f7ab5") or a color:rgba / color:named value from gg-backend.

with-fill-color color drawerprocedure
with-line-width width drawerprocedure

width in user coordinates.

with-dash dashes offset drawerprocedure

dashes is a list of on/off lengths; offset is the phase.

with-font family size slant weight drawerprocedure

family is a font family string (e.g. "sans-serif"); slant is 'normal or 'italic; weight is 'normal or 'bold.

Stroked drawing primitives

line-drawer x1 y1 x2 y2procedure
polyline-drawer ptsprocedure

pts is a list of (x . y) pairs.

rect-drawer x y w hprocedure

Outline rectangle; bottom-left corner at (x, y).

circle-drawer cx cy rprocedure
polygon-drawer ptsprocedure

Filled drawing primitives

filled-rect-drawer x y w hprocedure
filled-circle-drawer cx cy rprocedure
filled-polygon-drawer ptsprocedure

Text

text-drawer x y text #!key halign valignprocedure

Draw text anchored at (x, y).

halign
'left, 'center (default), or 'right
valign
'top, 'center, 'bottom, or 'baseline (default)

Convenience drawers

h-line-drawer x1 x2 yprocedure
v-line-drawer x y1 y2procedure
filled-rect+border-drawer x y w h fill-color edge-colorprocedure
path-drawer cmds #!key filled?procedure

cmds is a list of path commands from gg-backend: path:move-to, path:line-to, path:curve-to, path:arc, path:close.


Module: gg-backend-cairo

Cairo graphics backend. Implements the abstract backend protocol from gg-backend for four output formats.

make-cairo-png-backend filename width heightprocedure

PNG raster output. width and height are in pixels.

make-cairo-svg-backend filename width heightprocedure

SVG vector output.

make-cairo-ps-backend filename width heightprocedure

PostScript output.

make-cairo-pdf-backend filename width heightprocedure

PDF output. width and height are in points (72 pt = 1 inch; A4 portrait = 595 × 842 pt).


Module: gg-scales

Scales map between the data domain and the visual range. All scale objects implement the same protocol (via YASOS), so geometry and guide code is scale-type–agnostic.

Scale protocol

scale? objprocedure
scale-type scaleprocedure

Returns a symbol: 'linear, 'log, 'sqrt, 'power, 'ordinal, 'band, 'color-gradient, 'color-manual, …

scale-train! scale valuesprocedure

Extend the domain to include values (a list). Mutates the scale.

scale-map scale valueprocedure

Map a single domain value to the visual range.

scale-inverse scale valueprocedure

Map from visual range back to domain.

scale-breaks scale #!optional nprocedure

Return a list of n (default 5) nicely-placed tick positions.

scale-labels scale breaksprocedure

Return formatted label strings for the given break positions.

scale-domain scaleprocedure

Current domain as a (min . max) pair, or a list for discrete scales.

scale-range scaleprocedure

Current visual range as a (min . max) pair.

scale-set-domain! scale domainprocedure
scale-set-range! scale rangeprocedure

Mutating setters.

scale-bandwidth scaleprocedure

Width of a single band (for band scales only).

Functional scale combinators

These return a new scale and leave the original unmodified.

scale-with-domain scale domainprocedure
scale-with-range scale rangeprocedure
scale-with-trained scale valuesprocedure
scale-with-transform scale transform-typeprocedure

transform-type is one of: 'log, 'log10, 'log2, 'ln, 'sqrt, 'identity.

scale-with-breaks scale explicit-breaksprocedure

Override automatic break computation with a fixed list.

Continuous scale constructors

make-scale-linear #!key domain rangeprocedure
make-scale-log #!key domain range baseprocedure

base defaults to 10.

make-scale-sqrt #!key domain rangeprocedure
make-scale-power #!key domain range exponentprocedure

exponent defaults to 2.

Discrete scale constructors

make-scale-ordinal #!key domain rangeprocedure

Maps each domain value to the corresponding entry in range, cycling if necessary.

make-scale-band #!key domain range paddingprocedure

Like ordinal but maps to a continuous sub-interval (band) for bar charts. padding (default 0.1) is the fraction of each step reserved for spacing.

Color scale constructors

make-scale-color-gradient #!key domain low highprocedure

Continuous gradient interpolating between low and high color strings. Accepts named colors ("blue") and hex strings ("#3f7ab5").

make-scale-color-diverging #!key domain low mid high midpointprocedure

Two-segment gradient with a midpoint color.

make-scale-color-ordinal #!key domain paletteprocedure

Ordinal scale backed by a list of color strings.

make-scale-color-manual value-mapprocedure

Explicit category -> color alist, e.g. `(("Control" . "blue") ("Treatment" . "red"))

Break utilities

nice-breaks min-val max-val nprocedure
compute-pretty-breaks min max nprocedure
extend-domain domain expansionprocedure

Extend domain by the fractional expansion on each side (e.g. 0.05 adds 5 % padding).

Module: gg-data

Columnar data frames: an association list mapping column names (symbols) to parallel value lists.

(define data
  '((time  . (0 10 20 30 40 50))
    (value . (1.2 1.5 2.3 1.8 1.4 1.9))
    (group . ("A" "A" "A" "B" "B" "B"))))
data-column data column-nameprocedure

Extract a column list. Signals an error if the column is absent.

data-columns dataprocedure

List of column name symbols.

data-n-rows dataprocedure
data-row data indexprocedure

Single row as an association list ((col . value) ...).

data-rows dataprocedure

All rows as a list of association lists. Used internally by geometries.

columns->rows dataprocedure
rows->columns rowsprocedure

Convert between the columnar and row-oriented representations.

Module: gg-aes

Aesthetic mappings link data columns to visual channels.

Creating mappings

aes #!key x y color fill size shape alpha linetype group labelprocedure
make-aes ...procedure

Both are equivalent. Column references are symbols; literal values are strings or numbers:

(aes #:x 'time #:y 'value #:color 'condition)   ; x, y, color mapped to columns
(aes #:x 'time #:y 'value #:color "steelblue")  ; color is a constant
aesthetic-mapping? objprocedure

Accessors

aes-x mappingprocedure
aes-y mappingprocedure
aes-color mappingprocedure
aes-fill mappingprocedure
aes-size mappingprocedure
aes-shape mappingprocedure
aes-alpha mappingprocedure
aes-linetype mappingprocedure
aes-group mappingprocedure
aes-label mappingprocedure
aes-get mapping key #!optional defaultprocedure

Utilities

aes-merge base overrideprocedure

Merge two mappings; override wins on conflicts.

aes-has? mapping keyprocedure
aes-keys mappingprocedure
aes-map-value mapping key data-rowprocedure

Resolve an aesthetic: if the stored value is a symbol, look it up in data-row (an association list); otherwise return the literal value.

constant-value? valueprocedure
mapped-value? valueprocedure

Module: gg-geom

Geometry functions take a columnar data frame and an aesthetic mapping and return (values drawer trained-scales). They are normally used indirectly through the layer constructors in gg-plot, but can be called directly for custom pipelines.

Core geometries

geom-point data aes #!key scales size shape alphaprocedure

Scatter plot. Required aesthetics: x, y. Optional: color, fill, size.

geom-line data aes #!key scales width styleprocedure

Line plot. Groups rows by the color or group aesthetic and draws a separate polyline per group. Required: x, y.

geom-path data aes #!key scales width colorprocedure

Like geom-line but connects points in data order without sorting.

geom-area data aes #!key scales fill alphaprocedure

Filled area. With only x/y aesthetics, fills from 0 to y (simple area). With ymin/ymax aesthetics, fills between the two curves (ribbon).

geom-bar data aes #!key scales fill widthprocedure

Bar chart. Required: x, y.

geom-rect data aes #!key scalesprocedure

Draws rectangles from xmin/xmax/ymin/ymax aesthetics.

geom-text data aes #!key scales size colorprocedure

Text labels positioned at x/y, string from label aesthetic.

geom-segment data aes #!key scales color widthprocedure

Line segments from (x, y) to (xend, yend).

geom-hline data aes #!key scales color width linetypeprocedure
geom-vline data aes #!key scales color width linetypeprocedure

Reference lines.

Event plot

geom-eventplot data aes #!key scales line-length width colorprocedure

Draws one vertical tick per event time. Expects x to hold a list of timestamps per row and y to hold the row index (trial number).

(define spike-data
  '((trial  . (0 1 2 3 4))
    (spikes . ((12 25 38) (15 28 42) (10 23 40) (18 30 45) (13 27 41)))))

(geom-eventplot spike-data (aes #:x 'spikes #:y 'trial)
                #:line-length 0.7 #:width 1 #:color "black")

Statistical geometries

geom-histogram data aes #!key scales bins fill color alphaprocedure
geom-density data aes #!key scales fill color alphaprocedure
geom-boxplot data aes #!key scales fill color widthprocedure
geom-violin data aes #!key scales fill color alphaprocedure
geom-errorbar data aes #!key scales color width cap-widthprocedure
geom-crossbar data aes #!key scales fill color widthprocedure
geom-linerange data aes #!key scales color widthprocedure
geom-pointrange data aes #!key scales color point-size line-widthprocedure

Module: gg-guides

Axis and legend rendering. Returns drawers positioned in axis-local coordinates; gg-plot translates them to panel coordinates.

Axes

make-axis-bottom scale #!key label tick-countprocedure
make-axis-top scale #!key label tick-countprocedure
make-axis-left scale #!key label tick-countprocedure
make-axis-right scale #!key label tick-countprocedure

Convenience wrappers around:

make-axis scale position #!key label tick-count tick-length tick-width label-size label-offset line-colorprocedure
position
'bottom, 'top, 'left, or 'right
tick-count
target number of ticks (default 5)
tick-length
length of tick marks in user units (default 5)
tick-width
stroke width of ticks (default 1)
label-size
font size for tick labels (default 10.0)
label-offset
distance from axis line to label anchor in user units (default 15)
line-color
color string (default "black")
axis-drawer axis-configprocedure

Return a drawer for the axis. The drawer is in axis-local coordinates (the axis line lies at x=0 for vertical axes, y=0 for horizontal ones); the caller must apply with-translate to place it at the panel edge.

Legends

make-legend-continuous scale #!key title position width height label-sizeprocedure
make-legend-discrete scale #!key title position width height label-sizeprocedure
legend-drawer legend-configprocedure

Data format

All geometries expect data as a columnar alist, an association list mapping column names (symbols) to lists of equal length:

;; Columnar alist (required by the library)
'((time      . (0    10   20   30   40   50))
  (response  . (0.89 1.29 2.35 1.68 2.58 2.08))
  (condition . ("A" "A" "A" "B" "B" "B")))

Use columns->rows / rows->columns from gg-data to convert between row-oriented and column-oriented representations.


Examples

Minimal scatter plot

(import gg-plot gg-backend-cairo)

(define data
  '((x . (1 2 3 4 5))
    (y . (2.1 3.8 2.9 5.1 4.3))))

(define p
  (ggplot data (aes #:x 'x #:y 'y)
    (layer-point #:size 6 #:color "steelblue")
    (scale-x-continuous #:name "X")
    (scale-y-continuous #:name "Y")
    (theme-minimal)
    (labs #:title "Simple Scatter")))

(ggsave p "scatter.png" #:width 600 #:height 400)

Time series with confidence ribbon

(import gg-plot gg-backend-cairo)

(define data
  '((time  . (0 10 20 30 40 50 60 70 80 90 100))
    (value . (0.89 1.29 2.35 1.68 1.15 1.81 2.58 2.08 1.57 1.94 2.35))
    (upper . (1.66 1.95 2.72 2.12 1.71 2.21 2.96 2.39 2.00 2.27 2.67))
    (lower . (0.55 0.83 1.56 0.75 0.76 1.16 2.19 1.50 0.91 1.16 2.00))))

(define p
  (ggplot data (aes #:x 'time #:y 'value)
    ;; Shaded confidence band
    (layer-area  #:mapping (aes #:ymin 'lower #:ymax 'upper)
                 #:fill "steelblue" #:alpha 0.3)
    ;; Central line and points
    (layer-line  #:width 2 #:color "black")
    (layer-point #:size 5 #:color "black")
    (scale-x-continuous #:name "Time (seconds)")
    (scale-y-continuous #:name "Response (mV)")
    (theme-minimal #:base-size 12)
    (labs #:title "Time Series with Confidence Band"
          #:subtitle "Example of layered composition")))

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

Multi-series line plot with manual colors

(import gg-plot gg-backend-cairo)

(define data
  '((time  . (0 10 20 30 40 50 60   0 10 20 30 40 50 60))
    (value . (1.2 2.3 1.8 2.5 2.1 1.9 2.4
              0.8 1.5 1.2 1.8 1.6 1.4 1.7))
    (condition . ("Control" "Control" "Control" "Control"
                  "Control" "Control" "Control"
                  "Treatment" "Treatment" "Treatment"
                  "Treatment" "Treatment" "Treatment" "Treatment"))))

(define p
  (ggplot data (aes #:x 'time #:y 'value #:color 'condition)
    (layer-line  #:width 2)
    (layer-point #:size 4)
    (scale-x-continuous #:name "Time (ms)")
    (scale-y-continuous #:name "Response")
    (scale-color-manual #:values '(("Control"   . "blue")
                                   ("Treatment" . "red")))
    (theme-classic #:base-size 11)
    (labs #:title "Treatment vs Control")))

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

Bar chart with categorical x axis

(import gg-plot gg-backend-cairo)

(define data
  '((region      . ("V1" "V2" "V4" "MT" "IT"))
    (firing-rate . (12.5 8.3 15.7 22.1 9.4))))

(define p
  (ggplot data (aes #:x 'region #:y 'firing-rate)
    (layer-bar #:fill "steelblue" #:width 0.7)
    (scale-x-discrete  #:name "Brain Region")
    (scale-y-continuous #:name "Firing Rate (Hz)" #:limits '(0 25))
    (theme-bw)
    (labs #:title "Firing Rates Across Brain Regions")))

(ggsave p "bars.png" #:width 700 #:height 500)

Spike raster (neuroscience event plot)

(import gg-plot gg-backend-cairo)

(define spike-data
  '((trial . (0 1 2 3 4 5 6 7 8 9))
    (spikes . ((12 25 38 55 67)
               (15 28 42 58 71)
               (10 23 40 52 65)
               (18 30 45 60 73)
               (13 27 41 56 68)
               (16 29 43 59 72)
               (11 24 39 54 66)
               (14 26 44 57 70)
               (17 31 46 61 74)
               (9  22 37 53 64)))
    (condition . ("Pre" "Pre" "Pre" "Pre" "Pre"
                  "Post" "Post" "Post" "Post" "Post"))))

(define p
  (ggplot spike-data (aes #:x 'spikes #:y 'trial #:color 'condition)
    (layer-eventplot #:line-length 0.7 #:width 4)
    ;; Stimulus onset marker
    (layer-vline #:xintercept 20 #:color "red" #:linetype 'dashed #:width 1.5)
    (scale-x-continuous #:name "Time (ms)" #:limits '(0 80))
    (scale-y-continuous #:name "Trial #")
    (scale-color-manual #:values '(("Pre" . "black") ("Post" . "royalblue")))
    (theme-classic #:base-size 11)
    (labs #:title "Spike Raster Plot"
          #:subtitle "Pre vs Post stimulus")))

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

Logarithmic axes

(import gg-plot gg-backend-cairo)

(define data
  '((concentration . (0.1 1 10 100 1000))
    (response      . (2.1 8.5 42.3 201.7 987.2))))

(define p
  (ggplot data (aes #:x 'concentration #:y 'response)
    (layer-point #:size 6 #:color "coral")
    (layer-line  #:width 2 #:color "coral")
    (scale-x-log #:name "Concentration (uM)" #:base 10)
    (scale-y-log #:name "Response (% baseline)" #:base 10)
    (theme-minimal #:base-size 12)
    (labs #:title "Dose-Response Curve" #:subtitle "Log-log axes")))

(ggsave p "logscale.png" #:width 700 #:height 600)

Faceted plot (small multiples)

(import gg-plot gg-backend-cairo)

(define data
  '((time  . (0 10 20 30   0 10 20 30   0 10 20 30))
    (power . (8 12 15 11   5  9 14 10  12 18 22 17))
    (band  . ("Alpha" "Alpha" "Alpha" "Alpha"
              "Beta"  "Beta"  "Beta"  "Beta"
              "Gamma" "Gamma" "Gamma" "Gamma"))))

(define p
  (ggplot data (aes #:x 'time #:y 'power)
    (layer-line  #:color "steelblue" #:width 2)
    (layer-point #:size 4 #:color "darkblue")
    (facet-wrap 'band #:ncol 3 #:scales "free_y")
    (scale-x-continuous #:name "Time (s)")
    (scale-y-continuous #:name "Power (dB)")
    (theme-bw #:base-size 10)
    (labs #:title "Power Across Frequency Bands")))

(ggsave p "faceted.png" #:width 1200 #:height 400)

Multiple output formats

(import gg-plot gg-backend-cairo)

(define p (ggplot data (aes #:x 'x #:y 'y)
            (layer-point #:size 6)
            (theme-minimal)
            (labs #:title "Multi-format")))

;; PNG raster
(ggsave p "out.png" #:width 600 #:height 400)

;; High-resolution PNG (larger pixel dimensions)
(ggsave p "out-hires.png" #:width 2400 #:height 1600)

;; SVG vector
(ggsave p "out.svg" #:width 600 #:height 400)

;; PostScript
(ggsave p "out.ps" #:width 600 #:height 400)

;; PDF (A4 portrait, dimensions in points)
(render-plot p (make-cairo-pdf-backend "out.pdf" 595 842))

Plot specification serialisation

(import gg-plot gg-backend-cairo)

(define p (ggplot data (aes #:x 'x #:y 'y)
            (layer-point #:size 6)
            (scale-x-continuous #:name "X")
            (scale-y-continuous #:name "Y")
            (theme-classic)
            (labs #:title "Saved plot")))

;; Serialise to an s-expression and write to disk
(define spec (plot->sexp p))
(with-output-to-file "my-plot.scm"
  (lambda () (write spec) (newline)))

;; Later: load and re-render
(define restored
  (sexp->plot (with-input-from-file "my-plot.scm" read)))

(ggsave restored "restored.png" #:width 700 #:height 500)

Programmatic plot generation

;; Build a plot that layers one line per variable
(define (multi-line-plot data vars)
  (apply ggplot data (aes #:x 'time)
    (append
      (map (lambda (var)
             (layer-line #:mapping (aes #:y var) #:width 2))
           vars)
      (list (scale-x-continuous #:name "Time (s)")
            (scale-y-continuous #:name "Value")
            (theme-minimal)
            (labs #:title (format "Variables: ~a" vars))))))

Architecture notes

Scale training

Scales are mutable: scale-train! extends the domain and scale-map reflects the updated domain. The plot pipeline trains each scale by scanning all layers before any geometry is rendered, which allows automatic axis limits that span the full data range across layers.

Drawer composition model

All rendering is expressed as composable drawer values (drawer?). The pipeline builds one large combined drawer per panel and then executes it in a single pass over the plotter.

Author

Ivan Raikov

Repository

https://github.com/iraikov/chicken-ggplot

Version History

1.0
Initial release

License

LPGL-3

References

Contents »