figures

cli.figures

tvbo figure — render declarative figures from a Figure or Study YAML.

A :class:~tvbo.datamodel.Figure is TVBO’s backend-independent spec of a publication figure: a mosaic of panels whose layers bind experiment result containers to visual channels (see schema/figure.yaml). This verb resolves such a spec and drives :mod:tvbo.adapters.bsplot to emit a self-contained plot.py and run it, mirroring how tvbo run drives the simulation adapters.

The spec may be a standalone Figure (top-level panels:) or a SimulationStudy carrying a figures: list — the latter closes the replication loop (a study is its experiments plus the figures that read them).

Attributes

Name Description
app

Functions

Name Description
caption Compose each figure’s caption from its spec and write a <name>.caption.qmd partial.
compare Compare each rendered figure against its published counterpart, by panel geometry.
figure_origins {figure name: study root} for every figure the spec pulled in with !include.
figure_outputs (name, image, script) for figure under out_dir — where the render writes, named once.
reference_image_for The published image figure reproduces, resolved against root.
register_figure_code Put a root’s code/ on sys.path, so a figure rendering against it can import the modules its code_modules names.
render Render figures in spec via bsplot codegen (all of them, or the --name subset).
render_figures Emit + run each figure’s render script and return the written images.

caption

cli.figures.caption(
    spec=typer.Argument(..., help='Path to a Figure or SimulationStudy YAML.'),
    out=typer.Option(None, '-o', '--out', help="Directory for the .caption.qmd partials (default: the study's figures directory from the layout record)."),
    name=typer.Option(None, '-n', '--name', help='Caption only the figure(s) with this name (comma-separated). Default: all.'),
)

Compose each figure’s caption from its spec and write a <name>.caption.qmd partial.

The render-free sibling of figure render: it emits only the composed captions (figure lead + per-panel structural descriptor + authored Panel.description), so the prose can {{< include >}} a caption that regenerates from the spec without recomputing the figure.

compare

cli.figures.compare(
    spec=typer.Argument(..., help='Path to a Figure YAML or a SimulationStudy YAML with a figures: list.'),
    reference=typer.Option(None, '-r', '--reference', help="Reference image, or a directory of them. Optional: by default each figure's declared `reference_image:` is used, resolved against the study root."),
    figures_dir=typer.Option(None, '-f', '--figures', help="Directory holding the rendered figures (default: the study's figures directory from the layout record)."),
    out=typer.Option(None, '-o', '--out', help="Directory for the side-by-side overlays and the markdown summary (default: figure-compare/ under the study's notes directory)."),
    base_dir=typer.Option(None, '--base-dir', help="Study root. Defaults to the spec file's directory."),
    name=typer.Option(None, '-n', '--name', help='Compare only the figure(s) with this name (comma-separated).'),
)

Compare each rendered figure against its published counterpart, by panel geometry.

Replication asks a figure to land on the original’s layout — same aspect, same panel grid, panels the same relative size in the same places. This decomposes both images into panel boxes and reports the offsets, so “not well aligned” becomes a number per panel rather than an impression. Writes one overlay PNG per figure plus a markdown summary; the summary is what a report reads.

figure_origins

cli.figures.figure_origins(spec_path)

{figure name: study root} for every figure the spec pulled in with !include.

A figure record included from another study names its code_modules, its captured source and the path it draws relative to that study, and including it somewhere else must not change what those mean. So an included figure renders against the study its fragment lives in, and one written inline renders against the spec, which is what each already says. A fragment that belongs to no study — a spec kept beside the manuscript that includes it — is left out, so it renders against the including spec exactly as if it had been written there.

figure_outputs

cli.figures.figure_outputs(figure, out_dir)

(name, image, script) for figure under out_dir — where the render writes, named once.

The renderer and every consumer that has to find a rendered figure afterwards ask this, so a figure’s file name is derived in one place rather than re-spelled wherever it is looked up.

reference_image_for

cli.figures.reference_image_for(figure, root)

The published image figure reproduces, resolved against root.

Prefers the figure’s declared reference_image:; otherwise falls back to a file named after the figure. Returns None when neither exists.

register_figure_code

cli.figures.register_figure_code(base)

Put a root’s code/ on sys.path, so a figure rendering against it can import the modules its code_modules names.

Called for whichever root a figure actually renders against: its own, or — for a record !included from another study — that study’s, which the including spec knows nothing about. Without it a figure resolves against the right root and still cannot find its panels.

render

cli.figures.render(
    spec=typer.Argument(..., help='Path to a Figure YAML (top-level panels:) or a SimulationStudy YAML with a figures: list.'),
    out=typer.Option(None, '-o', '--out', help="Directory for the rendered figures + plot scripts (default: the study's figures directory from the layout record)."),
    base_dir=typer.Option(None, '--base-dir', help="Study root the result containers are resolved against. Defaults to the spec file's directory."),
    name=typer.Option(None, '-n', '--name', help='Render only the figure(s) with this name (comma-separated for several). Default: render every figure in the spec. Iterating one panel? `tvbo figure render <Study>.yaml -n Fig3_<study>` re-renders just that figure.'),
)

Render figures in spec via bsplot codegen (all of them, or the --name subset).

Each figure’s <name>.<format> image lands in <out-dir> and its self-contained, editable plot_<name>.py in <out-dir>/scripts/, so the directory the report reads holds images only. <base-dir> is the study root each layer’s used IRI resolves against; the containers are read from its results directory.

render_figures

cli.figures.render_figures(figures, base_dir, out_dir, origins=None)

Emit + run each figure’s render script and return the written images.

The single home for the per-figure render loop, shared by the figure render command and by tvbo run (which renders a study’s figures after its experiments, so one command closes the replication loop). base_dir is the study root each layer’s used IRI resolves against, whose results directory holds the containers; origins overrides it per figure, for a record !included from another study (see :func:figure_origins).

Every figure is attempted before anything is raised, so one broken declaration reports itself alongside the others rather than hiding the thirteen behind it; the run still fails, naming all of them.

The image lands directly in out_dir — the one place the report and every other consumer reads a figure from — while its self-contained, editable plot_<name>.py goes to out_dir/scripts/. Both are regenerable and gitignored together; separating them just keeps a study with many figures from interleaving twice as many files in the directory people actually browse. The subdirectory is deliberately NOT called code: in a study that name means the authored, tracked, importable code the recipe references by bare module name, which this is not.