Reproducible matplotlib wrapper with mm-precision layouts
Project description
FigRecipe (scitex-plt)
Reproducible scientific figures as first-class objects
Full Documentation · pip install figrecipe
Problem and Solution
| # | Problem | Solution |
|---|---|---|
| 1 | Figures drift from data -- plt.savefig(...) produces a PNG whose source data disappears the moment the notebook closes |
Recipe + data + PNG atomic -- each ax.stx_*() call records inputs; stx.io.save(fig) writes .png + .csv + .yaml so figures are replayable from the recipe |
| 2 | Restyling requires re-running analysis -- changing fonts/colors/layout means rebuilding the figure from scratch | Reproduce from recipe -- stx.plt.reproduce("fig.yaml", style="nature") restyles without touching data; hashes stay valid for Clew |
| 3 | mm-precision layout hard -- matplotlib uses inches/pixels; journals demand mm | Native mm layout -- figure_mm() + figure_from_axes_mm() give journal-grade column widths without conversion math |
Installation
Requires Python >= 3.10.
pip install figrecipe
For the GUI editor: pip install figrecipe[editor]
SciTeX users:
pip install scitex[plt]already includes FigRecipe.
Quickstart
import figrecipe as fr
import numpy as np
x = np.linspace(0, 2 * np.pi, 100)
fig, ax = fr.subplots()
ax.plot(x, np.sin(x), id="sine")
fr.save(fig, "figure.png")
# Produces: figure.png, figure.yaml, figure_data/sine.csv
Reload and edit from the saved recipe:
fig, ax = fr.reproduce("figure.yaml")
fr.gui(fig) # Launch visual editor at http://127.0.0.1:5050
Role in SciTeX Ecosystem
FigRecipe is the first app built on the SciTeX platform -- it proves the app pattern that other apps follow. It works standalone (figrecipe gui) AND embedded inside scitex-cloud.
scitex (orchestrator) -- re-exports figrecipe as scitex.plt
|-- scitex-app -- runtime SDK (FigRecipe inherits ScitexAppConfig)
|-- scitex-ui -- React/TS components (FigRecipe consumes these)
+-- figrecipe (this package) -- reference app
|-- figrecipe -- standalone Python package (pip install figrecipe)
+-- figrecipe._django -- Django integration for scitex-cloud embedding
What this package owns: Figure creation, reproduction, and composition engine; YAML recipe format and data provenance; Diagram system (box-and-arrow with mm-based coordinates); GUI editor; Django integration.
What this package does NOT own: App runtime SDK (inherits from scitex-app); UI components (consumes from scitex-ui); Templates (managed by scitex).
FigRecipe -- Reproducible, editable, publication-ready scientific figures. Part of SciTeX.
The SciTeX system follows the Four Freedoms for Research below, inspired by the Free Software Definition:
Four Freedoms for Research
- The freedom to run your research anywhere -- your machine, your terms.
- The freedom to study how every step works -- from raw data to final manuscript.
- The freedom to redistribute your workflows, not just your papers.
- The freedom to modify any module and share improvements with the community.
AGPL-3.0 -- because we believe research infrastructure deserves the same freedoms as the software it runs on.
SciTeX users:
pip install scitex[plt]includes FigRecipe.scitex.pltdelegates tofigrecipe-- they share the same API.
Overview
FigRecipe treats recipe, data, and style as first-class attributes of every figure. This enables data governance and style editing without losing scientific rigor.
Created with Diagrams
Styling
FigRecipe provides millimeter-precise control over every visual element. The SCITEX style preset is applied by default, producing publication-ready figures with standard matplotlib plotting.
Millimeter-based Layout
fig, ax = fr.subplots(axes_width_mm=60, axes_height_mm=40, margin_left_mm=15)
Style Presets
fr.load_style("SCITEX") # Publication defaults
fr.load_style("SCITEX_DARK") # Dark theme
fr.load_style("MATPLOTLIB") # Pure Matplotlib
GUI Editor
For precise adjustments, GUI editor is available.
Migration from Matplotlib
Matplotlib-compatibility
FigRecipe is a drop-in replacement for matplotlib -- just change your import:
# Before
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x, y)
plt.savefig("fig.png")
# After
import figrecipe as fr
fig, ax = fr.subplots()
ax.plot(x, y, id="my_trace")
fr.save(fig, "fig.png") # -> fig.png + fig.yaml + fig_data/
Systematic Migration
scitex-linter detects and auto-fixes matplotlib patterns into mm-based FigRecipe equivalents (check, format, python). It also works as a pre-commit hook, ensuring AI agents follow FigRecipe conventions.
Diagrams
Create publication-quality box-and-arrow diagrams with mm-based coordinates. See Overview for an example output.
Usage
from figrecipe import Diagram
d = Diagram(title="EEG Pipeline", gap_mm=10)
d.add_box("raw", "Raw EEG", subtitle="64 ch", emphasis="muted", shape="cylinder")
d.add_box("filter", "Bandpass", subtitle="0.5-45 Hz", emphasis="primary")
d.add_box("ica", "ICA", subtitle="Artifact removal", emphasis="primary")
d.add_arrow("raw", "filter")
d.add_arrow("filter", "ica")
d.save("pipeline.png") # -> pipeline.png + pipeline.yaml + pipeline_hitmap.png + pipeline_debug.png
Containers & Flex Layout
d = Diagram(title="System Overview", gap_mm=10)
d.add_box("a", "Module A")
d.add_box("b", "Module B")
d.add_container("grp", title="Core", children=["a", "b"], direction="row")
d.add_box("out", "Output", shape="document")
d.add_arrow("grp", "out")
d.save("overview.png")
Auto-Fix & Save Options
auto_fix=True automatically resolves layout violations. Output files from d.save(): out.png (auto-cropped), out.yaml (recipe), out_hitmap.png (GUI click regions), out_debug.png (debug overlay).
Shapes & Anchors
Shapes: rounded (default), box, stadium, cylinder, document, file, codeblock. Use node_class for semantic defaults: "code" -> codeblock, "input" -> cylinder, "claim" -> document.
Anchors: top, bottom, left, right, top-left, top-right, bottom-left, bottom-right, center, or auto (default). Aliases like n/s/e/w are normalized automatically.
Validation Rules
| Rule | Check | Severity |
|---|---|---|
| W | Width exceeds 185 mm (double-column max) | Warning |
| R1 | Container must enclose all children | Error |
| R2 | No two boxes may overlap | Error |
| R3 | Container title must clear children (5 mm zone) | Warning |
| R4 | Box text must fit within padded inner area | Warning |
| R5 | Text-to-text margin >= 2 mm | Error |
| R6 | Text-to-edge margin >= 2 mm | Error |
| R7 | Arrow visible-length ratio >= 90% | Error |
| R8 | Curved-arrow label on same side as arc | Error |
| R9 | All elements within canvas bounds | Error |
Four Interfaces
Python API
import figrecipe as fr
import numpy as np
fig, ax = fr.subplots()
ax.plot(np.sin(np.linspace(0, 10, 100)), id="sine")
fr.save(fig, "figure.png") # Saves + validates pixel-identical reproduction
# Output: figure.png, figure.yaml, figure_data/sine.csv
fr.save(fig, "fig.zip") # self-contained zip bundle
fr.load("fig.png") # reload from any format
fig, ax = fr.reproduce("figure.yaml")
fr.gui(fig) # Launch visual editor
fr.compose(sources=["panel_a.yaml", "panel_b.yaml"], output_path="composed.png", layout="horizontal")
ax.add_stat_annotation(x1=0, x2=1, p_value=0.01, style="stars")
CLI Commands
figrecipe --help-recursive # Show all commands
figrecipe reproduce fig.yaml # Recreate figure from recipe
figrecipe gui figure.png # Launch visual editor
figrecipe validate fig.yaml # Verify pixel-identical reproduction
figrecipe extract fig.yaml # Extract plotted data as CSV
figrecipe compose a.yaml b.yaml # Compose multi-panel figure
figrecipe crop figure.png # Auto-crop whitespace
figrecipe info fig.yaml # Show recipe metadata
MCP Server -- for AI Agents
AI agents can create, compose, and reproduce publication-ready figures autonomously via the Model Context Protocol.
| Tool | Description |
|---|---|
plot |
Create figure from declarative YAML spec |
reproduce |
Recreate figure from recipe |
compose |
Combine panels into multi-panel layout |
crop |
Auto-crop whitespace |
info |
Inspect recipe metadata |
validate |
Verify reproduction fidelity |
diagram_compile_mermaid |
Compile diagram spec to Mermaid |
diagram_render |
Render diagram to PNG/SVG/PDF |
audio_speak |
Text-to-speech relay to user's speakers |
Add .mcp.json to your project root (use SCITEX_ENV_SRC for environment switching):
{"mcpServers": {"scitex": {"command": "scitex", "args": ["mcp", "start"], "env": {"SCITEX_ENV_SRC": "${SCITEX_ENV_SRC}"}}}}
Skills — for AI Agent Discovery
Skills provide workflow-oriented guides that AI agents query to discover capabilities and usage patterns.
figrecipe skills list # List available skill pages
figrecipe skills get SKILL # Show main skill page
scitex-dev skills export --package figrecipe # Export to Claude Code
| Skill | Content |
|---|---|
quick-start |
Core workflow: subplots, save, reproduce |
plot-types |
All supported plot types with examples |
composition |
Multi-panel figure composition |
styles |
Style presets, SCITEX/MATPLOTLIB, custom styles |
bundle |
ZIP bundle format |
diagram |
Box-and-arrow diagrams, Mermaid, Graphviz |
cli-reference |
All CLI commands |
mcp-tools |
MCP tool reference for AI agents |
Lint Rules
Detected by scitex-linter when this package is installed.
| Rule | Severity | Message |
|---|---|---|
STX-FM001 |
warning | figsize= detected -- inch-based figure sizing is imprecise for publications |
STX-FM002 |
warning | tight_layout() detected -- layout is unpredictable across plot types |
STX-FM003 |
warning | bbox_inches="tight" detected -- can crop important elements unpredictably |
STX-FM004 |
info | constrained_layout=True detected -- conflicts with mm-based layout control |
STX-FM005 |
info | subplots_adjust() with hardcoded fractions -- fragile across figure sizes |
STX-FM006 |
info | plt.savefig() detected -- no provenance tracking |
STX-FM007 |
info | rcParams direct modification detected -- hard to maintain across figures |
STX-FM008 |
warning | set_size_inches() detected -- bypasses mm-based layout control |
STX-FM009 |
warning | ax.set_position() detected -- conflicts with mm-based layout control |
STX-P001 |
info | ax.plot() -- consider ax.stx_line() for automatic CSV data export |
STX-P002 |
info | ax.scatter() -- consider ax.stx_scatter() for automatic CSV data export |
STX-P003 |
info | ax.bar() -- consider ax.stx_bar() for automatic sample size annotation |
STX-P004 |
info | plt.show() is non-reproducible in batch/CI environments |
STX-P005 |
info | print() inside @stx.session -- use logger for tracked logging |
47 matplotlib plot types supported
| Category | Plot Types |
|---|---|
| Line & Curve | plot, step, fill, fill_between, fill_betweenx, errorbar, stackplot, stairs |
| Scatter & Points | scatter |
| Bar & Categorical | bar, barh |
| Distribution | hist, hist2d, boxplot, violinplot, ecdf |
| 2D Image & Matrix | imshow, matshow, pcolor, pcolormesh, hexbin, spy |
| Contour & Surface | contour, contourf, tricontour, tricontourf, tripcolor, triplot |
| Spectral & Signal | specgram, psd, csd, cohere, angle_spectrum, magnitude_spectrum, phase_spectrum, acorr, xcorr |
| Vector & Flow | quiver, barbs, streamplot |
| Special | pie, stem, eventplot, loglog, semilogx, semilogy, graph |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file figrecipe-0.28.3.tar.gz.
File metadata
- Download URL: figrecipe-0.28.3.tar.gz
- Upload date:
- Size: 8.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e98413746d6d959586588b48e61bcd245e54d94a953244d78490808781296acf
|
|
| MD5 |
34fdd75bd6ea4052589b794343717e94
|
|
| BLAKE2b-256 |
962d859a445e06391dffd13c3d02c777112a9f4675f32e6066553e167652acb2
|
File details
Details for the file figrecipe-0.28.3-py3-none-any.whl.
File metadata
- Download URL: figrecipe-0.28.3-py3-none-any.whl
- Upload date:
- Size: 6.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0f2118263b17af2a695524ef36b20532b6d9bc2f1074d327424f32b24a8e322
|
|
| MD5 |
ca46fc1747610fb1a518e5c5d66f421c
|
|
| BLAKE2b-256 |
46b3464a2c10779f048730c19691a13a3b5064cfcb82b26b2e31bfa7218e451c
|