FigRecipe API Reference
figrecipe - Record and reproduce matplotlib figures.
A lightweight library for capturing matplotlib plotting calls and reproducing figures from saved recipes.
Usage
>>> import figrecipe as fr
>>> fig, ax = fr.subplots()
>>> ax.plot(x, y, id='my_data')
>>> fr.save(fig, 'recipe.yaml')
Examples
Recording a figure:
>>> import figrecipe as fr
>>> import numpy as np
>>>
>>> x = np.linspace(0, 10, 100)
>>> y = np.sin(x)
>>>
>>> fig, ax = fr.subplots()
>>> ax.plot(x, y, color='red', linewidth=2, id='sine_wave')
>>> ax.set_xlabel('Time')
>>> ax.set_ylabel('Amplitude')
>>> fr.save(fig, 'my_figure.yaml')
Reproducing a figure:
>>> fig, ax = fr.reproduce('my_figure.yaml')
>>> plt.show()
fr.utils: Unit conversions, font checks, low-level recipe access
fr.styles: Axis helpers, spine management, plot styling functions
fr.viz: Diagram and graph visualization utilities
>>> from figrecipe import utils
>>> utils.mm_to_inch(25.4) # Unit conversions
>>> from figrecipe import styles
>>> styles.hide_spines(ax) # Spine management
- figrecipe.subplots(nrows=1, ncols=1, axes_width_mm=None, axes_height_mm=None, margin_left_mm=None, margin_right_mm=None, margin_bottom_mm=None, margin_top_mm=None, space_w_mm=None, space_h_mm=None, style=None, apply_style_mm=True, panel_labels=None, **kwargs)[source]
Create a figure with recording-enabled axes.
This is a drop-in replacement for plt.subplots() that wraps the returned figure and axes with recording capabilities.
Supports mm-based layout control for publication-quality figures.
- Parameters:
nrows (int) – Number of rows and columns of subplots.
ncols (int) – Number of rows and columns of subplots.
axes_width_mm (float, optional) – Axes dimensions in mm.
axes_height_mm (float, optional) – Axes dimensions in mm.
margin_left_mm (float, optional) – Left/right margins in mm.
margin_right_mm (float, optional) – Left/right margins in mm.
margin_bottom_mm (float, optional) – Bottom/top margins in mm.
margin_top_mm (float, optional) – Bottom/top margins in mm.
space_w_mm (float, optional) – Horizontal/vertical spacing between axes in mm.
space_h_mm (float, optional) – Horizontal/vertical spacing between axes in mm.
style (dict, optional) – Style configuration dictionary.
apply_style_mm (bool) – If True (default), apply loaded style to axes.
panel_labels (bool or None) – If True, add panel labels (A, B, C, …).
**kwargs – Additional arguments passed to plt.subplots().
- Return type:
Tuple[RecordingFigure,Union[RecordingAxes,ndarray[tuple[int,...],dtype[TypeVar(_ScalarType_co, bound=generic, covariant=True)]]]]- Returns:
fig (RecordingFigure) – Wrapped figure object.
axes (RecordingAxes or ndarray) – Wrapped axes.
- figrecipe.save(fig, path, save_recipe=True, include_data=True, data_format='csv', csv_format='separate', validate=True, validate_mse_threshold=100.0, validate_error_level='error', verbose=True, dpi=None, image_format=None, facecolor=None, save_hitmap=True)[source]
Save a figure as image and recipe. Unified API with fig.savefig().
- Parameters:
fig (RecordingFigure or Figure) – The figure to save.
path (str or Path) – Output path (.png, .pdf, .svg, .yaml, etc.)
save_recipe (bool) – If True (default), save YAML recipe alongside the image.
include_data (bool) – If True (default), save large arrays to separate files.
data_format (str) – Format for data files: ‘csv’, ‘npz’, or ‘inline’.
csv_format (str) – CSV structure: ‘separate’ (default) or ‘single’ (scitex-compatible).
validate (bool) – If True (default), validate reproducibility after saving.
validate_mse_threshold (float) – Maximum acceptable MSE for validation (default: 100).
validate_error_level (str) – How to handle failures: ‘error’, ‘warning’, or ‘debug’.
verbose (bool) – If True (default), print save status.
dpi (int, optional) – DPI for image output.
image_format (str, optional) – Image format when path is YAML.
facecolor (str, optional) – Background color. When opaque, patches are made visible.
save_hitmap (bool) – If True (default), save hitmap image for GUI editor element selection.
- Returns:
If save_recipe=True: (image_path, yaml_path, ValidationResult or None) If save_recipe=False: (image_path, None, None)
- Return type:
- figrecipe.reproduce(path, calls=None, skip_decorations=False, apply_style=True)[source]
Reproduce a figure from a recipe file or bundle.
- Parameters:
path (str or Path) – Path to recipe. Supports multiple formats: - .yaml/.yml file: Direct recipe file - .png/.jpg/etc: Image with associated .yaml - Directory: Bundle containing recipe.yaml - .zip: ZIP bundle (both old recipe.yaml format and new spec.json format)
calls (list of str, optional) – If provided, only reproduce these specific call IDs.
skip_decorations (bool) – If True, skip decoration calls.
apply_style (bool) – If True (default), apply saved style.
- Return type:
- Returns:
fig (matplotlib.figure.Figure) – Reproduced figure.
axes (Axes or list of Axes) – Reproduced axes.
- figrecipe.load(path, calls=None, skip_decorations=False, apply_style=True)
Reproduce a figure from a recipe file or bundle.
- Parameters:
path (str or Path) – Path to recipe. Supports multiple formats: - .yaml/.yml file: Direct recipe file - .png/.jpg/etc: Image with associated .yaml - Directory: Bundle containing recipe.yaml - .zip: ZIP bundle (both old recipe.yaml format and new spec.json format)
calls (list of str, optional) – If provided, only reproduce these specific call IDs.
skip_decorations (bool) – If True, skip decoration calls.
apply_style (bool) – If True (default), apply saved style.
- Return type:
- Returns:
fig (matplotlib.figure.Figure) – Reproduced figure.
axes (Axes or list of Axes) – Reproduced axes.
- figrecipe.compose(sources, layout=None, canvas_size_mm=None, gap_mm=5.0, dpi=300, panel_labels=False, label_style='uppercase', **kwargs)[source]
Compose a new figure from multiple sources (recipes or raw images).
Supports two modes automatically detected from sources format:
Grid-based: sources={(row, col): path} Uses layout=(nrows, ncols) for subplot grid.
Mm-based: sources={path: {“xy_mm”: (x, y), “size_mm”: (w, h)}} Uses canvas_size_mm for precise positioning.
- Parameters:
sources (dict) – Either: - Grid-based: {(row, col): source_path} mapping positions to sources - Mm-based: {source_path: {“xy_mm”: (x, y), “size_mm”: (w, h)}}
layout (tuple, optional) – (nrows, ncols) for grid-based composition. Auto-detected if not provided.
canvas_size_mm (tuple, optional) – (width_mm, height_mm) for mm-based composition. Required for mm-based mode.
gap_mm (float) – Gap between panels in mm (for auto-layout modes like ‘horizontal’).
dpi (int) – DPI for the output figure.
panel_labels (bool) – If True, add panel labels (A, B, C…) to each panel.
label_style (str) – ‘uppercase’, ‘lowercase’, or ‘numeric’.
**kwargs – Additional arguments passed to figure creation.
- Return type:
Tuple[RecordingFigure,Union[RecordingAxes,ndarray[tuple[int,...],dtype[TypeVar(_ScalarType_co, bound=generic, covariant=True)]],List[RecordingAxes]]]- Returns:
fig (RecordingFigure) – Composed figure (editable, recordable).
axes (RecordingAxes, ndarray, or list) – Axes of the composed figure.
Examples
Grid-based composition:
>>> fig, axes = fr.compose( ... layout=(1, 2), ... sources={ ... (0, 0): "panel_a.yaml", ... (0, 1): "panel_b.yaml", ... } ... )
Mm-based free-form composition:
>>> fig, axes = fr.compose( ... canvas_size_mm=(180, 120), ... sources={ ... "panel_a.yaml": {"xy_mm": (0, 0), "size_mm": (85, 55)}, ... "panel_b.yaml": {"xy_mm": (90, 0), "size_mm": (85, 55)}, ... "panel_c.yaml": {"xy_mm": (0, 60), "size_mm": (175, 55)}, ... } ... )
- figrecipe.align_panels(fig, panels, mode, reference=None)[source]
Align multiple panels to a reference panel.
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple) – List of (row, col) positions to align.
mode (str or AlignmentMode) – Alignment mode: ‘left’, ‘right’, ‘top’, ‘bottom’, ‘center_h’, ‘center_v’, ‘axis_x’, ‘axis_y’.
reference (tuple, optional) – Reference panel position. If None, uses first panel.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(2, 2) >>> # Align left column panels to left edge >>> fr.align_panels(fig, [(0, 0), (1, 0)], mode="left")
- figrecipe.distribute_panels(fig, panels, direction='horizontal', spacing_mm=None)[source]
Distribute panels evenly with optional fixed spacing.
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple) – List of (row, col) positions to distribute.
direction (str) – ‘horizontal’ or ‘vertical’.
spacing_mm (float, optional) – Fixed spacing in mm. If None, distribute evenly within current bounds.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(1, 3) >>> # Distribute evenly >>> fr.distribute_panels(fig, [(0, 0), (0, 1), (0, 2)]) >>> # With fixed 5mm spacing >>> fr.distribute_panels(fig, [(0, 0), (0, 1), (0, 2)], spacing_mm=5)
- figrecipe.align_smart(fig, panels=None)[source]
Automatically align panels in a compact grid layout.
Works like human behavior: 1. Detect grid structure (nrows, ncols) 2. Place panels from top-left to bottom-right 3. Calculate minimum rectangle to cover all content in each row/column 4. Unify row heights and column widths 5. Use space effectively with theme margins and spacing
Uses margin and spacing values from the loaded SCITEX theme: - margins.left_mm, margins.right_mm, margins.top_mm, margins.bottom_mm - spacing.horizontal_mm, spacing.vertical_mm
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple, optional) – Specific panels to align. If None, aligns all panels.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(2, 2) >>> # ... add plots ... >>> fr.align_smart(fig) # Align all panels using theme settings
- figrecipe.gui(source=None, style=None, port=5050, host='127.0.0.1', open_browser=True, hot_reload=False, working_dir=None, desktop=False)[source]
Launch interactive GUI editor for figure styling.
- Parameters:
source (RecordingFigure, str, Path, or None) – Either a live RecordingFigure object, path to a .yaml recipe file, or None to create a new blank figure.
style (str or dict, optional) – Style preset name or style dict.
port (int, optional) – Flask server port (default: 5050).
host (str, optional) – Host to bind Flask server (default: “127.0.0.1”, use “0.0.0.0” for Docker).
open_browser (bool, optional) – Whether to open browser automatically (default: True).
hot_reload (bool, optional) – Enable hot reload (default: False).
working_dir (str or Path, optional) – Working directory for file browser (default: directory containing source).
desktop (bool, optional) – Launch as native desktop window using pywebview (default: False). Requires: pip install figrecipe[desktop]
- Returns:
Final style overrides after editing session.
- Return type:
- figrecipe.crop(input_path, output_path=None, margin_mm=1.0, margin_px=None, overwrite=False, verbose=False)[source]
Crop a figure image to its content area with a specified margin.
- Parameters:
input_path (str or Path) – Path to the input image.
output_path (str or Path, optional) – Path to save the cropped image.
margin_mm (float, optional) – Margin in millimeters (default: 1.0mm).
margin_px (int, optional) – Margin in pixels (overrides margin_mm if provided).
overwrite (bool, optional) – Whether to overwrite the input file (default: False)
verbose (bool, optional) – Whether to print detailed information (default: False)
- Returns:
Path to the saved cropped image.
- Return type:
Path
- figrecipe.validate(path, mse_threshold=100.0)
Validate that a saved recipe can reproduce its original figure.
- figrecipe.extract_data(path)[source]
Extract data arrays from a saved recipe.
- Returns:
Nested dictionary: {call_id: {‘x’: array, ‘y’: array, …}}
- Return type:
- figrecipe.save_bundle(fig, path, dpi=None, image_formats=None, save_hitmap=True, verbose=True)[source]
Save figure as a layered bundle (ZIP format).
- Bundle structure inside ZIP:
spec.json # WHAT (semantic specification) style.json # HOW (appearance settings) data.csv # DATA (immutable source data) exports/
figure.png figure_hitmap.png
- Parameters:
fig (RecordingFigure) – The figure to save.
path (str or Path) – Output path (.zip will be added if not present).
dpi (int, optional) – DPI for exports (default from style or 300).
image_formats (list, optional) – Image formats to export (default: [‘png’]).
save_hitmap (bool) – Whether to save hitmap for GUI editing (default: True).
verbose (bool) – Whether to print status (default: True).
- Returns:
Path to saved ZIP bundle.
- Return type:
Path
- figrecipe.load_style(style='SCITEX', dark=False, background=None)[source]
Load style configuration and apply it globally.
After calling this function, subsequent subplots() calls will automatically use the loaded style (fonts, colors, theme, etc.).
- Parameters:
style (str, Path, bool, or None) – One of: - “SCITEX” / “FIGRECIPE”: Scientific publication style (default) - “MATPLOTLIB”: Vanilla matplotlib defaults - Path to custom YAML file: “/path/to/my_style.yaml” - None or False: Unload style (reset to matplotlib defaults)
dark (bool, optional) – If True, apply dark theme transformation (default: False). Equivalent to appending “_DARK” to preset name.
background (str, optional) – Override default background color. E.g., ‘white’ for opaque figures. Sets theme.light.figure_bg and theme.light.axes_bg. Use ‘transparent’ for transparent background.
- Returns:
Style configuration with dot-notation access. Returns None if style is unloaded.
- Return type:
DotDict or None
Examples
>>> import figrecipe as fr
>>> # Load scientific style (default) >>> fr.load_style() >>> fr.load_style("SCITEX") # explicit
>>> # Load with white background (override transparent default) >>> fr.load_style("SCITEX", background='white')
>>> # Load dark theme >>> fr.load_style("SCITEX_DARK") >>> fr.load_style("SCITEX", dark=True) # equivalent
>>> # Reset to vanilla matplotlib >>> fr.load_style(None) # unload >>> fr.load_style(False) # unload >>> fr.load_style("MATPLOTLIB") # explicit vanilla
>>> # Access style values >>> style = fr.load_style("SCITEX") >>> style.axes.width_mm 40
- figrecipe.unload_style()[source]
Unload the current style and reset to matplotlib defaults.
After calling this, subsequent subplots() calls will use vanilla matplotlib behavior without FigRecipe styling.
Examples
>>> import figrecipe as fr >>> fr.load_style("SCITEX") # Apply scientific style >>> fig, ax = fr.subplots() # Styled >>> fr.unload_style() # Reset to matplotlib defaults >>> fig, ax = fr.subplots() # Vanilla matplotlib
- figrecipe.list_presets()[source]
List available style presets.
Examples
>>> import figrecipe as ps >>> ps.list_presets() ['MINIMAL', 'PRESENTATION', 'SCIENTIFIC']
- figrecipe.get_graph_preset(name)
Get a preset by name.
- Parameters:
name (str) – Preset name. Built-in presets: ‘default’, ‘minimal’, ‘citation’, ‘dependency’, ‘social’, ‘biological’, ‘knowledge’.
- Returns:
Preset configuration dictionary.
- Return type:
- Raises:
ValueError – If preset name is not found.
- figrecipe.list_graph_presets()
List all available presets with descriptions.
- Returns:
Dictionary mapping preset names to brief descriptions.
- Return type:
- figrecipe.register_graph_preset(name, config, override=False)
Register a custom graph preset.
- Parameters:
- Raises:
ValueError – If preset already exists and override is False.
- Return type:
Examples
>>> from figrecipe._graph_presets import register_preset >>> register_preset('my_style', { ... 'layout': 'circular', ... 'node_color': '#e74c3c', ... 'node_size': 'degree', ... 'labels': True, ... })
- class figrecipe.Diagram(type='workflow', title='', column='single')[source]
Bases:
objectPaper-optimized diagram with semantic specification.
This class provides the main interface for creating diagrams that compile to Mermaid or Graphviz with paper-appropriate layout constraints.
Examples
>>> # From YAML spec >>> d = Diagram.from_yaml("workflow.diagram.yaml") >>> d.to_mermaid("workflow.mmd")
>>> # From existing Mermaid (parse and enhance) >>> d = Diagram.from_mermaid("existing.mmd", diagram_type="workflow") >>> d.spec.paper.column = "double" >>> d.to_mermaid("enhanced.mmd")
>>> # Programmatic creation >>> d = Diagram(type="pipeline") >>> d.add_node("input", "Raw Data") >>> d.add_node("process", "Transform", emphasis="primary") >>> d.add_node("output", "Results") >>> d.add_edge("input", "process") >>> d.add_edge("process", "output") >>> print(d.to_mermaid())
- classmethod from_mermaid(path, diagram_type='workflow')[source]
Parse existing Mermaid file and create enhanced Diagram.
This allows upgrading existing Mermaid files with FigRecipe paper constraints while preserving the original structure.
- render(path, format='png', backend='auto', scale=2.0)[source]
Render diagram to image file (PNG, SVG, PDF).
- Parameters:
- Returns:
Path to rendered file.
- Return type:
Path
- Raises:
RuntimeError – If no rendering backend is available.
- split(max_nodes=12, strategy='by_groups', keep_hubs=True)[source]
Split diagram into multiple figures if too large.
- Parameters:
- Returns:
List of split diagrams (or single diagram if no split needed).
- Return type:
List[Diagram]
Examples
>>> d = Diagram.from_yaml("large_workflow.yaml") >>> parts = d.split(max_nodes=8) >>> for i, part in enumerate(parts): ... part.to_mermaid(f"workflow_part_{i+1}.mmd")
- class figrecipe.Schematic(title=None, width_mm=170.0, height_mm=120.0)[source]
Bases:
objectBuilder for rich schematic diagrams.
- add_arrow(source, target, source_anchor='auto', target_anchor='auto', label=None, style='solid', color=None, curve=0.0, linewidth_mm=0.5, label_offset_mm=None)[source]
Add an arrow connecting two boxes.
- Return type:
- add_box(id, title, subtitle=None, content=None, emphasis='normal', shape='rounded', position_mm=None, size_mm=None, fill_color=None, border_color=None, title_color=None, padding_mm=5.0, margin_mm=0.0)[source]
Add a rich text box.
- Return type:
- add_container(id, title=None, children=None, emphasis='muted', position_mm=None, size_mm=None, fill_color=None, border_color=None)[source]
Add a container that groups other boxes.
- Return type:
- auto_layout(layout='lr', margin_mm=15.0, box_size_mm=None, gap_mm=10.0, avoid_overlap=True, justify='space-between', align_items='center')[source]
Automatically position boxes. See _schematic_layout for details.
- Return type:
- classmethod from_dict(data)[source]
Create Schematic from dictionary (recipe reproduction).
- Return type:
- render_to_file(path, dpi=200)[source]
Render and save. On validation failure, saves as *_FAILED.png.
- Return type:
- figrecipe._get_sns()
Get or create the seaborn recorder instance.
- Return type:
SeabornRecorder
- figrecipe._get_version(distribution_name)
Get the version string for the named package.
- Parameters:
distribution_name – The name of the distribution package to query.
- Returns:
The version string for the package as defined in the package’s “Version” metadata key.
- figrecipe._rebrand_text(text)
Apply branding to a text string (e.g., docstring).
- Parameters:
text (str or None) – Text to rebrand.
- Returns:
Rebranded text, or None if input was None.
- Return type:
str or None
Examples
>>> os.environ["FIGRECIPE_BRAND"] = "mypackage" >>> os.environ["FIGRECIPE_ALIAS"] = "mp" >>> rebrand_text("import figrecipe as fr") 'import mypackage as mp'
Core Functions
- figrecipe.subplots(nrows=1, ncols=1, axes_width_mm=None, axes_height_mm=None, margin_left_mm=None, margin_right_mm=None, margin_bottom_mm=None, margin_top_mm=None, space_w_mm=None, space_h_mm=None, style=None, apply_style_mm=True, panel_labels=None, **kwargs)[source]
Create a figure with recording-enabled axes.
This is a drop-in replacement for plt.subplots() that wraps the returned figure and axes with recording capabilities.
Supports mm-based layout control for publication-quality figures.
- Parameters:
nrows (int) – Number of rows and columns of subplots.
ncols (int) – Number of rows and columns of subplots.
axes_width_mm (float, optional) – Axes dimensions in mm.
axes_height_mm (float, optional) – Axes dimensions in mm.
margin_left_mm (float, optional) – Left/right margins in mm.
margin_right_mm (float, optional) – Left/right margins in mm.
margin_bottom_mm (float, optional) – Bottom/top margins in mm.
margin_top_mm (float, optional) – Bottom/top margins in mm.
space_w_mm (float, optional) – Horizontal/vertical spacing between axes in mm.
space_h_mm (float, optional) – Horizontal/vertical spacing between axes in mm.
style (dict, optional) – Style configuration dictionary.
apply_style_mm (bool) – If True (default), apply loaded style to axes.
panel_labels (bool or None) – If True, add panel labels (A, B, C, …).
**kwargs – Additional arguments passed to plt.subplots().
- Return type:
Tuple[RecordingFigure,Union[RecordingAxes,ndarray[tuple[int,...],dtype[TypeVar(_ScalarType_co, bound=generic, covariant=True)]]]]- Returns:
fig (RecordingFigure) – Wrapped figure object.
axes (RecordingAxes or ndarray) – Wrapped axes.
- figrecipe.save(fig, path, save_recipe=True, include_data=True, data_format='csv', csv_format='separate', validate=True, validate_mse_threshold=100.0, validate_error_level='error', verbose=True, dpi=None, image_format=None, facecolor=None, save_hitmap=True)[source]
Save a figure as image and recipe. Unified API with fig.savefig().
- Parameters:
fig (RecordingFigure or Figure) – The figure to save.
path (str or Path) – Output path (.png, .pdf, .svg, .yaml, etc.)
save_recipe (bool) – If True (default), save YAML recipe alongside the image.
include_data (bool) – If True (default), save large arrays to separate files.
data_format (str) – Format for data files: ‘csv’, ‘npz’, or ‘inline’.
csv_format (str) – CSV structure: ‘separate’ (default) or ‘single’ (scitex-compatible).
validate (bool) – If True (default), validate reproducibility after saving.
validate_mse_threshold (float) – Maximum acceptable MSE for validation (default: 100).
validate_error_level (str) – How to handle failures: ‘error’, ‘warning’, or ‘debug’.
verbose (bool) – If True (default), print save status.
dpi (int, optional) – DPI for image output.
image_format (str, optional) – Image format when path is YAML.
facecolor (str, optional) – Background color. When opaque, patches are made visible.
save_hitmap (bool) – If True (default), save hitmap image for GUI editor element selection.
- Returns:
If save_recipe=True: (image_path, yaml_path, ValidationResult or None) If save_recipe=False: (image_path, None, None)
- Return type:
- figrecipe.reproduce(path, calls=None, skip_decorations=False, apply_style=True)[source]
Reproduce a figure from a recipe file or bundle.
- Parameters:
path (str or Path) – Path to recipe. Supports multiple formats: - .yaml/.yml file: Direct recipe file - .png/.jpg/etc: Image with associated .yaml - Directory: Bundle containing recipe.yaml - .zip: ZIP bundle (both old recipe.yaml format and new spec.json format)
calls (list of str, optional) – If provided, only reproduce these specific call IDs.
skip_decorations (bool) – If True, skip decoration calls.
apply_style (bool) – If True (default), apply saved style.
- Return type:
- Returns:
fig (matplotlib.figure.Figure) – Reproduced figure.
axes (Axes or list of Axes) – Reproduced axes.
- figrecipe.compose(sources, layout=None, canvas_size_mm=None, gap_mm=5.0, dpi=300, panel_labels=False, label_style='uppercase', **kwargs)[source]
Compose a new figure from multiple sources (recipes or raw images).
Supports two modes automatically detected from sources format:
Grid-based: sources={(row, col): path} Uses layout=(nrows, ncols) for subplot grid.
Mm-based: sources={path: {“xy_mm”: (x, y), “size_mm”: (w, h)}} Uses canvas_size_mm for precise positioning.
- Parameters:
sources (dict) – Either: - Grid-based: {(row, col): source_path} mapping positions to sources - Mm-based: {source_path: {“xy_mm”: (x, y), “size_mm”: (w, h)}}
layout (tuple, optional) – (nrows, ncols) for grid-based composition. Auto-detected if not provided.
canvas_size_mm (tuple, optional) – (width_mm, height_mm) for mm-based composition. Required for mm-based mode.
gap_mm (float) – Gap between panels in mm (for auto-layout modes like ‘horizontal’).
dpi (int) – DPI for the output figure.
panel_labels (bool) – If True, add panel labels (A, B, C…) to each panel.
label_style (str) – ‘uppercase’, ‘lowercase’, or ‘numeric’.
**kwargs – Additional arguments passed to figure creation.
- Return type:
Tuple[RecordingFigure,Union[RecordingAxes,ndarray[tuple[int,...],dtype[TypeVar(_ScalarType_co, bound=generic, covariant=True)]],List[RecordingAxes]]]- Returns:
fig (RecordingFigure) – Composed figure (editable, recordable).
axes (RecordingAxes, ndarray, or list) – Axes of the composed figure.
Examples
Grid-based composition:
>>> fig, axes = fr.compose( ... layout=(1, 2), ... sources={ ... (0, 0): "panel_a.yaml", ... (0, 1): "panel_b.yaml", ... } ... )
Mm-based free-form composition:
>>> fig, axes = fr.compose( ... canvas_size_mm=(180, 120), ... sources={ ... "panel_a.yaml": {"xy_mm": (0, 0), "size_mm": (85, 55)}, ... "panel_b.yaml": {"xy_mm": (90, 0), "size_mm": (85, 55)}, ... "panel_c.yaml": {"xy_mm": (0, 60), "size_mm": (175, 55)}, ... } ... )
- figrecipe.validate(path, mse_threshold=100.0)
Validate that a saved recipe can reproduce its original figure.
- figrecipe.crop(input_path, output_path=None, margin_mm=1.0, margin_px=None, overwrite=False, verbose=False)[source]
Crop a figure image to its content area with a specified margin.
- Parameters:
input_path (str or Path) – Path to the input image.
output_path (str or Path, optional) – Path to save the cropped image.
margin_mm (float, optional) – Margin in millimeters (default: 1.0mm).
margin_px (int, optional) – Margin in pixels (overrides margin_mm if provided).
overwrite (bool, optional) – Whether to overwrite the input file (default: False)
verbose (bool, optional) – Whether to print detailed information (default: False)
- Returns:
Path to the saved cropped image.
- Return type:
Path
Recording Classes
These classes are available via from figrecipe import utils or from figrecipe._wrappers import RecordingFigure, RecordingAxes.
- class figrecipe._wrappers.RecordingFigure(fig, recorder, axes)[source]
Bases:
objectWrapper around matplotlib Figure that manages recording.
- Parameters:
fig (matplotlib.figure.Figure) – The underlying matplotlib figure.
recorder (Recorder) – The recorder instance.
axes (list of RecordingAxes) – Wrapped axes objects.
Examples
>>> import figrecipe as ps >>> fig, ax = ps.subplots() >>> ax.plot([1, 2, 3], [4, 5, 6]) >>> ps.save(fig, "my_figure.yaml")
- property axes: List[List[RecordingAxes]]
Get axes as 2D array.
- property flat: List[RecordingAxes]
Get flattened list of all axes.
- property record: FigureRecord
Get the figure record.
- _get_theme_text_color(default='black')[source]
Get text color from loaded style’s theme settings.
- Return type:
- suptitle(t, **kwargs)[source]
Set super title for the figure and record it.
- Parameters:
t (str) – The super title text.
**kwargs – Additional arguments passed to matplotlib’s suptitle().
- Returns:
The matplotlib Text object.
- Return type:
Text
- supxlabel(t, **kwargs)[source]
Set super x-label for the figure and record it.
- Parameters:
t (str) – The super x-label text.
**kwargs – Additional arguments passed to matplotlib’s supxlabel().
- Returns:
The matplotlib Text object.
- Return type:
Text
- supylabel(t, **kwargs)[source]
Set super y-label for the figure and record it.
- Parameters:
t (str) – The super y-label text.
**kwargs – Additional arguments passed to matplotlib’s supylabel().
- Returns:
The matplotlib Text object.
- Return type:
Text
- colorbar(mappable, ax=None, **kwargs)[source]
Add a colorbar and record it for reproduction.
- Return type:
- add_panel_labels(labels=None, loc='upper left', offset=(-0.1, 1.05), fontsize=None, fontweight='bold', **kwargs)[source]
Add panel labels (A, B, C, D, etc.) to multi-panel figures.
- Parameters:
labels (list of str, optional) – Custom labels. If None, uses uppercase letters (A, B, C, …).
loc (str) – Location hint: ‘upper left’ (default), ‘upper right’, ‘lower left’, ‘lower right’.
offset (tuple of float) – (x, y) offset in axes coordinates from the corner. Default is (-0.1, 1.05) for upper left positioning.
fontsize (float, optional) – Font size in points. If None, uses style’s title_pt or 10.
fontweight (str) – Font weight (default: ‘bold’).
**kwargs – Additional arguments passed to ax.text().
- Returns:
The matplotlib Text objects created.
- Return type:
list of Text
Examples
>>> fig, axes = fr.subplots(2, 2) >>> fig.add_panel_labels() # Adds A, B, C, D >>> fig.add_panel_labels(['i', 'ii', 'iii', 'iv']) # Custom labels >>> fig.add_panel_labels(loc='upper right', offset=(1.05, 1.05))
- set_title_metadata(title)[source]
Set figure title metadata (not rendered, stored in recipe).
This is for storing a publication/reference title for the figure, separate from suptitle which is rendered on the figure.
- Parameters:
title (str) – The figure title for publication/reference.
- Returns:
Self for method chaining.
- Return type:
Examples
>>> fig, ax = fr.subplots() >>> fig.set_title_metadata("Effect of temperature on reaction rate") >>> fig.set_caption("Figure 1. Reaction rates measured at various temperatures.")
- set_caption(caption)[source]
Set figure caption metadata (not rendered, stored in recipe).
This is for storing a publication caption for the figure, typically used in scientific papers (e.g., “Fig. 1. Description…”).
- Parameters:
caption (str) – The figure caption text.
- Returns:
Self for method chaining.
- Return type:
Examples
>>> fig, ax = fr.subplots() >>> fig.set_caption("Figure 1. Temperature dependence of reaction rates.")
- set_stats(stats)[source]
Set figure-level statistics metadata (not rendered, stored in recipe).
- Parameters:
stats (dict) – Statistics dictionary (comparisons, summary, correction_method, alpha).
- Return type:
- generate_caption(style='publication', template=None)[source]
Generate caption from stored stats. Styles: publication, brief, detailed.
- Return type:
- savefig(fname, save_recipe=True, include_data=True, data_format='csv', csv_format='separate', validate=True, validate_mse_threshold=100.0, validate_error_level='error', verbose=True, dpi=None, image_format=None, facecolor=None, save_hitmap=False, **kwargs)[source]
Save figure — equivalent to fr.save(). Same DPI, crop, recipe.
Returns (image_path, yaml_path, result). **kwargs passed to matplotlib savefig for file-like objects.
- class figrecipe._wrappers.RecordingAxes(ax, recorder, position=(0, 0))[source]
Bases:
RecordingAxesMethods,AxesStyleMixin,SchematicMixinWrapper around matplotlib Axes that records all calls.
This wrapper intercepts calls to plotting methods and records them for later reproduction.
- Parameters:
ax (matplotlib.axes.Axes) – The underlying matplotlib axes.
recorder (Recorder) – The recorder instance to log calls to.
position (tuple) – (row, col) position in the figure grid.
Examples
>>> import figrecipe as ps >>> fig, ax = ps.subplots() >>> ax.plot([1, 2, 3], [4, 5, 6], color='red', id='my_line') >>> # The call is recorded automatically
- __dir__()[source]
Return list of attributes for tab completion.
Exposes all matplotlib plotting and decoration methods alongside figrecipe’s custom methods and properties.
- _create_recording_wrapper(method_name, method)[source]
Create a wrapper function that records the call.
- _create_legend_wrapper()[source]
Create wrapper for legend() that applies frame styling and records the call.
- set_caption(caption)[source]
Set panel caption metadata (not rendered, stored in recipe).
- Return type:
- set_stats(stats)[source]
Set panel-level statistics metadata (not rendered, stored in recipe).
- Return type:
- _record_seaborn_call(func_name, args, kwargs, data_arrays, call_id=None)[source]
Record a seaborn plotting call.
- Return type:
- property figure
- property xaxis
- property yaxis
Style Management
- figrecipe.load_style(style='SCITEX', dark=False, background=None)[source]
Load style configuration and apply it globally.
After calling this function, subsequent subplots() calls will automatically use the loaded style (fonts, colors, theme, etc.).
- Parameters:
style (str, Path, bool, or None) – One of: - “SCITEX” / “FIGRECIPE”: Scientific publication style (default) - “MATPLOTLIB”: Vanilla matplotlib defaults - Path to custom YAML file: “/path/to/my_style.yaml” - None or False: Unload style (reset to matplotlib defaults)
dark (bool, optional) – If True, apply dark theme transformation (default: False). Equivalent to appending “_DARK” to preset name.
background (str, optional) – Override default background color. E.g., ‘white’ for opaque figures. Sets theme.light.figure_bg and theme.light.axes_bg. Use ‘transparent’ for transparent background.
- Returns:
Style configuration with dot-notation access. Returns None if style is unloaded.
- Return type:
DotDict or None
Examples
>>> import figrecipe as fr
>>> # Load scientific style (default) >>> fr.load_style() >>> fr.load_style("SCITEX") # explicit
>>> # Load with white background (override transparent default) >>> fr.load_style("SCITEX", background='white')
>>> # Load dark theme >>> fr.load_style("SCITEX_DARK") >>> fr.load_style("SCITEX", dark=True) # equivalent
>>> # Reset to vanilla matplotlib >>> fr.load_style(None) # unload >>> fr.load_style(False) # unload >>> fr.load_style("MATPLOTLIB") # explicit vanilla
>>> # Access style values >>> style = fr.load_style("SCITEX") >>> style.axes.width_mm 40
- figrecipe.unload_style()[source]
Unload the current style and reset to matplotlib defaults.
After calling this, subsequent subplots() calls will use vanilla matplotlib behavior without FigRecipe styling.
Examples
>>> import figrecipe as fr >>> fr.load_style("SCITEX") # Apply scientific style >>> fig, ax = fr.subplots() # Styled >>> fr.unload_style() # Reset to matplotlib defaults >>> fig, ax = fr.subplots() # Vanilla matplotlib
Alignment Functions
- figrecipe.align_panels(fig, panels, mode, reference=None)[source]
Align multiple panels to a reference panel.
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple) – List of (row, col) positions to align.
mode (str or AlignmentMode) – Alignment mode: ‘left’, ‘right’, ‘top’, ‘bottom’, ‘center_h’, ‘center_v’, ‘axis_x’, ‘axis_y’.
reference (tuple, optional) – Reference panel position. If None, uses first panel.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(2, 2) >>> # Align left column panels to left edge >>> fr.align_panels(fig, [(0, 0), (1, 0)], mode="left")
- figrecipe.align_smart(fig, panels=None)[source]
Automatically align panels in a compact grid layout.
Works like human behavior: 1. Detect grid structure (nrows, ncols) 2. Place panels from top-left to bottom-right 3. Calculate minimum rectangle to cover all content in each row/column 4. Unify row heights and column widths 5. Use space effectively with theme margins and spacing
Uses margin and spacing values from the loaded SCITEX theme: - margins.left_mm, margins.right_mm, margins.top_mm, margins.bottom_mm - spacing.horizontal_mm, spacing.vertical_mm
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple, optional) – Specific panels to align. If None, aligns all panels.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(2, 2) >>> # ... add plots ... >>> fr.align_smart(fig) # Align all panels using theme settings
- figrecipe.distribute_panels(fig, panels, direction='horizontal', spacing_mm=None)[source]
Distribute panels evenly with optional fixed spacing.
- Parameters:
fig (RecordingFigure) – The figure containing the panels.
panels (list of tuple) – List of (row, col) positions to distribute.
direction (str) – ‘horizontal’ or ‘vertical’.
spacing_mm (float, optional) – Fixed spacing in mm. If None, distribute evenly within current bounds.
- Return type:
Examples
>>> import figrecipe as fr >>> fig, axes = fr.subplots(1, 3) >>> # Distribute evenly >>> fr.distribute_panels(fig, [(0, 0), (0, 1), (0, 2)]) >>> # With fixed 5mm spacing >>> fr.distribute_panels(fig, [(0, 0), (0, 1), (0, 2)], spacing_mm=5)
GUI Editor
- figrecipe.gui(source=None, style=None, port=5050, host='127.0.0.1', open_browser=True, hot_reload=False, working_dir=None, desktop=False)[source]
Launch interactive GUI editor for figure styling.
- Parameters:
source (RecordingFigure, str, Path, or None) – Either a live RecordingFigure object, path to a .yaml recipe file, or None to create a new blank figure.
style (str or dict, optional) – Style preset name or style dict.
port (int, optional) – Flask server port (default: 5050).
host (str, optional) – Host to bind Flask server (default: “127.0.0.1”, use “0.0.0.0” for Docker).
open_browser (bool, optional) – Whether to open browser automatically (default: True).
hot_reload (bool, optional) – Enable hot reload (default: False).
working_dir (str or Path, optional) – Working directory for file browser (default: directory containing source).
desktop (bool, optional) – Launch as native desktop window using pywebview (default: False). Requires: pip install figrecipe[desktop]
- Returns:
Final style overrides after editing session.
- Return type:
Diagram Class
- class figrecipe.Diagram(type='workflow', title='', column='single')[source]
Paper-optimized diagram with semantic specification.
This class provides the main interface for creating diagrams that compile to Mermaid or Graphviz with paper-appropriate layout constraints.
Examples
>>> # From YAML spec >>> d = Diagram.from_yaml("workflow.diagram.yaml") >>> d.to_mermaid("workflow.mmd")
>>> # From existing Mermaid (parse and enhance) >>> d = Diagram.from_mermaid("existing.mmd", diagram_type="workflow") >>> d.spec.paper.column = "double" >>> d.to_mermaid("enhanced.mmd")
>>> # Programmatic creation >>> d = Diagram(type="pipeline") >>> d.add_node("input", "Raw Data") >>> d.add_node("process", "Transform", emphasis="primary") >>> d.add_node("output", "Results") >>> d.add_edge("input", "process") >>> d.add_edge("process", "output") >>> print(d.to_mermaid())
- classmethod from_mermaid(path, diagram_type='workflow')[source]
Parse existing Mermaid file and create enhanced Diagram.
This allows upgrading existing Mermaid files with FigRecipe paper constraints while preserving the original structure.
- render(path, format='png', backend='auto', scale=2.0)[source]
Render diagram to image file (PNG, SVG, PDF).
- Parameters:
- Returns:
Path to rendered file.
- Return type:
Path
- Raises:
RuntimeError – If no rendering backend is available.
- split(max_nodes=12, strategy='by_groups', keep_hubs=True)[source]
Split diagram into multiple figures if too large.
- Parameters:
- Returns:
List of split diagrams (or single diagram if no split needed).
- Return type:
List[Diagram]
Examples
>>> d = Diagram.from_yaml("large_workflow.yaml") >>> parts = d.split(max_nodes=8) >>> for i, part in enumerate(parts): ... part.to_mermaid(f"workflow_part_{i+1}.mmd")