Quick Start

Creating Your First Reproducible Figure

FigRecipe wraps matplotlib with automatic recording. Use the standard matplotlib API:

import figrecipe as fr
import numpy as np

# Create figure with recording
fig, ax = fr.subplots()

# Use standard matplotlib methods
x = np.linspace(0, 2 * np.pi, 100)
ax.plot(x, np.sin(x), label="sin(x)", color="blue", id="sine")
ax.plot(x, np.cos(x), label="cos(x)", color="red", id="cosine")

ax.set_xlabel("X (radians)")
ax.set_ylabel("Y")
ax.set_title("Trigonometric Functions")
ax.legend()

# Save creates: plot.png + plot.yaml
fr.save(fig, "trig_plot.png")
Trigonometric plot example

Saving Figures

All three save methods are equivalent for RecordingFigures:

# These produce identical output (same DPI, crop, recipe):
fr.save(fig, "plot.png")       # Explicit API
fig.savefig("plot.png")        # Delegates to fr.save()

# In a @stx.session context:
stx.io.save(fig, "plot.png")   # SciTeX universal I/O

Use whichever style you prefer — they all go through the same pipeline with style-based DPI, auto-crop, and recipe generation.

Warning

Never bypass the wrapper with fig.fig.savefig() — that accesses the raw matplotlib figure and skips DPI, crop, and recipe logic.

Output Files

FigRecipe creates different outputs depending on format:

PNG/YAML format (for development):

plot.png               # The figure image
plot.yaml              # Recipe for reproduction
plot_data/             # Data CSV files

ZIP bundle (for sharing):

plot.zip               # Self-contained bundle with all data

Reproducing a Figure

Recreate any figure from its recipe:

import figrecipe as fr

# From YAML recipe
fig, ax = fr.reproduce("trig_plot.yaml")

# Save reproduced figure (pixel-identical to original)
fr.save(fig, "reproduced.png")

# From ZIP bundle
fig, ax = fr.reproduce_bundle("figure.zip")

# Optionally modify and save again
ax.set_title("Modified Title")
fr.save(fig, "modified.png")

CLI Commands

FigRecipe provides a comprehensive CLI:

# Show help
figrecipe --help

# Reproduce a figure
figrecipe reproduce trig_plot.yaml -o reproduced.png

# Validate reproduction fidelity
figrecipe validate trig_plot.yaml

# Compare two images
figrecipe diff original.png reproduced.png

# Launch GUI editor
figrecipe gui trig_plot.yaml

MCP Server for AI Agents

FigRecipe includes an MCP server for AI integration:

# Start MCP server
figrecipe mcp start

# List available MCP tools
figrecipe mcp list-tools

# Install to Claude Code
figrecipe mcp install --claude-code

Statistical Annotations

Add significance brackets:

import figrecipe as fr

fig, ax = fr.subplots()
ax.bar(["Control", "Treatment"], [10, 15], yerr=[1, 1.5])

# Add significance annotation
ax.add_stat_annotation(
    x1=0, x2=1,
    p_value=0.01,
    style="stars"  # Shows **
)

fr.save(fig, "stats_plot.png")

Multi-Panel Composition

Compose multiple figures:

import figrecipe as fr

# Create individual panels
fig1, ax1 = fr.subplots()
ax1.plot([1, 2, 3], [1, 4, 9])
fr.save(fig1, "panel_a.png")

fig2, ax2 = fr.subplots()
ax2.bar(["A", "B"], [10, 15])
fr.save(fig2, "panel_b.png")

# Compose into multi-panel figure
fr.compose(
    sources=["panel_a.yaml", "panel_b.yaml"],
    output_path="composed.png",
    layout="horizontal",
    panel_labels=True
)

Box-and-Arrow Schematics

Create publication-quality schematic diagrams with mm-based coordinates:

import figrecipe as fr

s = fr.Schematic(title="EEG Analysis Pipeline", width_mm=170, height_mm=100)
s.add_box("raw", "Raw EEG", subtitle="64 channels", emphasis="muted")
s.add_box("filter", "Bandpass Filter", subtitle="0.5-45 Hz", emphasis="primary")
s.add_box("ica", "ICA", subtitle="Artifact removal", emphasis="primary")
s.add_arrow("raw", "filter")
s.add_arrow("filter", "ica")
s.auto_layout(layout="lr", gap_mm=15)

fig, ax = fr.subplots()
ax.schematic(s, id="pipeline")
fr.save(fig, "pipeline.png")
Left-to-right schematic pipeline

Top-to-bottom layouts work the same way:

s = fr.Schematic(title="Neural Network", width_mm=150, height_mm=250)
s.add_box("input", "Input Layer", subtitle="784 neurons", emphasis="muted")
s.add_box("conv", "Conv2D", subtitle="32 filters", emphasis="primary")
s.add_box("out", "Output", subtitle="10 classes", emphasis="warning")
s.add_arrow("input", "conv")
s.add_arrow("conv", "out")
s.auto_layout(layout="tb", gap_mm=10)
Top-to-bottom schematic architecture

Schematic Validation Rules

All rules are enforced automatically on render. When validation fails, figures are saved with a _FAILED suffix for inspection.

Rule

Check

Severity

W

Width exceeds 185 mm (double-column max)

UserWarning

R1

Container must enclose all children

ValueError

R2

No two boxes may overlap

ValueError

R3

Container title must clear children (5 mm zone)

UserWarning

R4

Box text must fit within padded inner area

UserWarning

R5

Text-to-text margin >= 2 mm

ValueError

R6

Text-to-edge margin >= 2 mm

ValueError

R7

Arrow visible-length ratio >= 90%

ValueError

R8

Curved-arrow label on same side as arc

ValueError