Skip to main content

figquilt is a small, language-agnostic CLI tool that composes multiple figures (PDF/SVG/PNG) into a single publication-ready figure, based on a simple layout file (YAML/JSON). The key function is creating a PDF by composing multiple PDFs and adding subfigure labels and minimal annotations.

Project description

figquilt

Figure quilter: A declarative CLI tool for compositing multiple figures (PDF, SVG, PNG) into publication-ready layouts.

figquilt takes a simple layout file (YAML) describing panels and their structure, composed of various inputs (plots from R/Python, diagrams, photos), and stitches them into a single output file (PDF, SVG) with automatic labeling and precise dimension control.

Philosophy

  • Declarative over imperative: Describe what your figure should look like, not how to construct it. Layouts are data, not scripts.
  • Structural composition first: Prefer high-level layout (rows, columns, ratios) over manual coordinate placement. Let the tool handle positioning.
  • Fine control when needed: Override with explicit coordinates and dimensions when precision matters.
  • Automation-friendly: Designed to fit into reproducible workflows (Snakemake, Make, CI pipelines). No GUI, no manual steps.

Features

  • Precise Layout: Define exact physical dimensions (mm) for the page and panels.
  • Mixed Media: Combine PDF, SVG, and PNG inputs in one figure.
  • Automated Labeling: Automatically add subfigure labels (A, B, C...) with consistent styling.
  • Reproducible: Layouts are defined in version-controllable text files (YAML).
  • Language Agnostic: It is a CLI tool, so it works with outputs from any tool (R, Python, Julia, Inkscape, etc.).

Installation

uv tool install figquilt

Or add it as a project dependency:

uv add figquilt

Development Installation

git clone https://github.com/yy/figquilt.git
cd figquilt
uv sync

Usage

Define a layout in a YAML file (e.g., figure1.yaml):

page:
  width: 180  # mm
  height: 120 # mm
  
panels:
  - id: A
    file: "plots/scatter.pdf"
    width: 80
    x: 0
    y: 0
  - id: B
    file: "diagrams/schematic.svg"
    width: 80
    x: 90
    y: 0

Run figquilt to generate the figure:

figquilt figure1.yaml figure1.pdf

Watch Mode

Use --watch to automatically rebuild when the layout file or any panel source files change:

figquilt --watch figure1.yaml figure1.pdf

This is useful during layout iteration - edit your YAML or regenerate a panel, and the output updates automatically.

Fit Modes

When specifying both width and height for a panel, use fit to control how the source image scales:

  • contain (default): Scale to fit within the cell, preserving aspect ratio. May leave empty space (letterbox/pillarbox).
  • cover: Scale to cover the entire cell, preserving aspect ratio. May crop overflow.
panels:
  - id: A
    file: "photo.png"
    x: 0
    y: 0
    width: 80
    height: 60
    fit: cover  # Fill the cell, cropping if needed

If height is omitted, the panel automatically sizes to preserve the source aspect ratio.

Page Margins

Add consistent margins around your content with the margin property on the page:

page:
  width: 180
  height: 120
  margin: 10  # 10mm margin on all sides

panels:
  - id: A
    file: "plots/scatter.pdf"
    width: 70
    x: 0   # Positioned relative to margin, not page edge
    y: 0

Panel coordinates are relative to the margin edge. A panel at x: 0, y: 0 with a 10mm margin will appear at position (10mm, 10mm) on the page.

Grid Layout

Instead of manually specifying x/y coordinates for each panel, use the grid layout system to define structure with rows and columns:

page:
  width: 180
  height: 100
  units: mm

layout:
  type: row
  ratios: [3, 2]  # Left panel is 60%, right is 40%
  gap: 5
  children:
    - id: A
      file: "plot1.pdf"
    - id: B
      file: "plot2.pdf"

Container Types

  • row: Arranges children horizontally (left to right)
  • col: Arranges children vertically (top to bottom)

Container Properties

Property Default Description
ratios Equal Relative sizing of children (e.g., [3, 2] = 60%/40%)
gap 0 Space between children (in page units)
margin 0 Inner padding of the container

Nested Layouts

Containers can be nested for complex layouts:

layout:
  type: col
  ratios: [1, 2]  # Top row 1/3 height, bottom row 2/3
  children:
    - id: A
      file: "header.pdf"
    - type: row
      ratios: [1, 1]
      gap: 5
      children:
        - id: B
          file: "left.pdf"
        - id: C
          file: "right.pdf"

This creates:

  • Panel A spanning the full width in the top third
  • Panels B and C side-by-side in the bottom two-thirds

Editor Autocomplete (JSON Schema)

For autocomplete and validation in your editor, reference the JSON schema in your layout file:

# yaml-language-server: $schema=https://raw.githubusercontent.com/yy/figquilt/main/schema/layout.schema.json
page:
  width: 180
  height: 120

panels:
  - id: A
    file: "plots/scatter.pdf"
    # ... your editor will now provide autocomplete for all fields

This works with YAML Language Server in VS Code (via the YAML extension) and other editors.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

figquilt-0.1.10.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

figquilt-0.1.10-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file figquilt-0.1.10.tar.gz.

File metadata

  • Download URL: figquilt-0.1.10.tar.gz
  • Upload date:
  • Size: 15.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for figquilt-0.1.10.tar.gz
Algorithm Hash digest
SHA256 8d0a532959e64cda02c2d5a15181607c8047e67055eca86afe8f8a8ffd2868e6
MD5 dbb6db9997783317fd6a330305984c21
BLAKE2b-256 7c97f9c195d8634eca1c16d5e604f7df971103c9322a624d0591206c6a3a6d40

See more details on using hashes here.

File details

Details for the file figquilt-0.1.10-py3-none-any.whl.

File metadata

  • Download URL: figquilt-0.1.10-py3-none-any.whl
  • Upload date:
  • Size: 19.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for figquilt-0.1.10-py3-none-any.whl
Algorithm Hash digest
SHA256 8b3a0571bd8f905195440b377e28161b3c6e8d54e7f2975229ce2f6dae399b04
MD5 421a3d6f470af10d7b91aa605a10f542
BLAKE2b-256 27b24f5c563d09dc1ed60a00f75a43874aa3f5d0ef48b119479bf87650c341da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page