Metadata-Version: 2.4
Name: panel-compiler
Version: 0.1.3
Summary: Compose SVG figures and LaTeX equations into a panel template
Author-email: Matthias Függer <mfuegger@gmail.com>
License: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: pyyaml
Description-Content-Type: text/markdown

# pc — Panel Compiler

Compose scientific figures from SVG plots, PDF figures, and LaTeX equations into a single SVG or PDF panel.
This is intended for the case that these subfigures are
generated by scripts and you automatically want to keep your panels up to date.

Define a panel template in Inkscape with named group (`<g>`) or rectangle (`<rect>`) placeholders (set via the layer/group label field), then write a small YAML config that maps each label to an SVG file, PDF, or a LaTeX string. `pc` scales each figure to fit its placeholder and writes the compiled panel.
It is often convenient to let `pc` overwrite the old panel (labels are preserved for repeated execution).

## Example

An example is given in `example`.
Assume you would like to create a panel with 3 subfigures.
Two are figures created via `python` code, and one contains a LaTeX formula.

We start from the panel template `example/panel.svg` that was created in Inkscape.
Here, the template is simple and contains only three `rect` placeholders, each of which has set its `label` (via Inkscape) set to one of: `formula`, `logistic`, and `logistic_log`.

This is the panel:

![panel template](example/panel.svg)

The `python` script that generates the subfigures is `example/subfigures.py` with the following
subfigures being generated:

| `logistic.svg` | `logistic_log.svg` |
|:--------------:|:------------------:|
| ![logistic](example/logistic.svg) | ![logistic_log](example/logistic_log.svg) |

Next we prepared a configuration `example/pc.yaml` that tells the panel-compiler how to
compile the panel:
```yaml
panel: panel.svg
output:
  - out.svg
  - panel.pdf

formula:
  tex: $\frac{dN}{dt} = rN\!\left(1 - \frac{N}{K}\right)$
  size: 10pt

logistic:
  file: logistic.svg
  fit: contain

logistic_log:
  file: logistic_log.svg
  fit: contain
```

The panel is finally compiled via:

```bash
cd example
python subfigures.py
pc pc.yaml
```

Resulting in the generation of `example/out.svg`:

![compiled panel](example/out.svg)


## Installation

From PyPI:

```bash
uv tool install panel-compiler
```

or with pip:

```bash
pip install panel-compiler
```

From the repository:

```bash
uv tool install git+https://github.com/mfuegger/pc.git
```

or with pip:

```bash
pip install git+https://github.com/mfuegger/pc.git
```

For LaTeX rendering, `pdflatex` must be on your `PATH`. For PDF figures and PDF output, `pdf2svg` and `inkscape` must be on your `PATH`. On macOS: `brew install pdf2svg`.

## Usage

```
pc [config.yaml]
```

| Argument | Default | Description |
|---|---|---|
| `config.yaml` | `pc.yaml` | YAML config (see below) |

The output path is taken from the `output` key in the config. If omitted, it defaults to the config filename with `.svg` extension (e.g. `pc.yaml` → `pc.svg`).

## Config format

### Single panel

```yaml
panel: panel.svg    # required — path to the panel SVG, relative to this config file
output: out.svg     # optional — defaults to <config-stem>.svg if omitted
```

`output` can also be a list to produce multiple formats in one run:

```yaml
output:
  - out.svg
  - out.pdf
```

Each remaining key is a **label** that must match an element in the panel SVG. `pc` looks it up by `inkscape:label` first, then `label`, then `id`. The element can be a `<g>` group or a `<rect>` placeholder — a `<rect>` is automatically replaced by a `<g>` positioned at the rect's `x`/`y`.

### Figure entry (SVG or PDF)

```yaml
plot:
  file: results.svg   # path relative to this config file; .svg or .pdf  (alias: svg:)
  fit: contain        # contain | height | width  (default: contain)
  width: 200          # optional — override the target width  (SVG user units)
  height: 100         # optional — override the target height (SVG user units)
```

Fit strategies:
- `contain` — scale uniformly to fit within the placeholder box (default)
- `height` — scale to match the placeholder height exactly
- `width`  — scale to match the placeholder width exactly

Target dimensions come from `width`/`height` attributes on the group element in the panel SVG. The config `width`/`height` are used as a fallback when the group has no such attributes.

PDF files are converted via `pdf2svg` before embedding.

### LaTeX entry

```yaml
label:
  tex: $y = \sin(x)$   # any LaTeX — math mode, text, amsmath, …
  size: 12pt           # font size (default: 10pt); scales the rendered output
```

Rendered via `pdflatex` + `inkscape`. No fit scaling — the output is sized by `size` alone.

### Shorthand

A plain string value is treated as an SVG file path with `fit: contain`:

```yaml
other: path/to/fig.svg
```

### Multiple panels

Use a YAML list; each entry must have its own `output`:

```yaml
- panel: panel1.svg
  output: out1.svg
  plot:
    file: results.svg

- panel: panel2.svg
  output:
    - out2.svg
    - out2.pdf
  label:
    tex: $E = mc^2$
    size: 12pt
```

## License

Apache 2.0 — see [LICENSE](LICENSE).
