Multi-panel Figures¶
Plots combine into multi-panel figures in two ways. Both produce the same backend-agnostic grid:
- Operators:
a | bputs panels side by side anda / bstacks them. This is the quickest way, and it nests. Figure: an explicit grid withadd(row=, col=, rowspan=, colspan=), for full control.
Composing with operators¶
| and / accept any plot or figure, including the result of an earlier
composition. The result is a figure that you can .render(), .show() or
.save() like any other.
Side by side and stacked¶
a | b places panels in a row. Chaining | gives one flat row rather than
nested pairs:
a / b stacks panels in a column:
Nesting and automatic spans¶
Use parentheses to nest groups. A single panel next to a group stretches to cover it, so you never need to work out spans yourself:
Columns with different numbers of rows¶
Groups don't need to line up. Here a column of two sits beside a column of three. cplots merges the row boundaries (halves and thirds) into one grid, so each panel keeps exactly its share of the height:
┌──────┬────────┐
│ │ p3 │
│ p1 ├────────┤
│ │ │
├──────┤ pk_fig │ 4 grid rows, height ratios 2:1:1:2
│ │ │
│ p2 ├────────┤
│ │ hz_fig │
└──────┴────────┘
Relative sizes¶
cplots.Row and cplots.Col are the classes behind | and /. Call them
directly to weight a group's children:
A weighted group nested in a larger layout keeps its internal split. In
Row(p1, p2, widths=[3, 1]) | pk_fig, the inner row takes half the width
(split 3:1) and pk_fig takes the other half, which gives column ratios 3:1:4:
.layout(widths=, heights=) works differently: it sets the ratios of the
final grid directly, with one value per grid column or row:
Figure-level settings¶
A composition is a figure, so the figure methods chain on it:
.layout(sharex=, sharey=, hspace=, wspace=)for axis sharing and spacing.size(w, h)and.paper("PRD-2col")for the size.style(...)for a style that applies to every panel (Formatting and Styles)
On matplotlib, figures use the constrained layout engine by default, so axis
labels, titles and colourbars don't overlap. Setting hspace or wspace asks
for exact spacing and turns the engine off; .layout(engine="tight") or
.layout(engine=None) choose another engine or none at all.
A model and its residuals, with a shared x-axis and a tall top panel:
Per-plot formatting survives composition, so each panel keeps its own limits, legend and style:
Mixing with Figure¶
Operators also accept a Figure, which keeps its own grid, ratios and style
inside the larger layout:
The same layout, three ways¶
These three expressions build the same figure: two panels on top and one wide panel below.
(p1 | p2) / pk_fig # operators
cplots.Figure.grid([[p1, p2], [pk_fig]]) # grid of rows
(cplots.Figure(nrows=2, ncols=2) # explicit cells
.add(p1, row=0, col=0)
.add(p2, row=0, col=1)
.add(pk_fig, row=1, col=0, colspan=2))
Operators are usually the shortest. Figure.add gives exact control over each
cell, for layouts that don't break down into rows and columns.
Simple grids¶
Figure.grid() is the fastest way to build a uniform layout:
Rules:
- Each inner list is a row.
- Rows with fewer plots than the maximum width are auto-spanned evenly.
- The number of plots per row must evenly divide the maximum row length.
Explicit spanning¶
Use Figure(...).add(...) for irregular layouts:
add() returns self, so calls can be chained.
Shared axes¶
Sizing and styles¶
The figure's style applies to every panel. A panel's own style
(p1.style(...)) is layered on top of it.
Colourbars¶
colorbar={...} sets colourbar fields (loc, label_loc, pad, scale, ...)
on every colour-mapped panel (e.g. XYZColored); panels without a colour scale
are left alone:
For one colourbar shared by several colour-coded panels, use
XYZColoredGrid(..., shared_colorbar=True).
Backend support
matplotlib and plotly support every layout feature. Altair sizes panels by
colspan and width/height ratios. It cannot share axes, and it raises
NotImplementedError for rowspan > 1. Anything a backend ignores triggers
one cplots.UnsupportedFeatureWarning.
Not a panel
A TrianglePlot cannot be a Figure panel: its engine draws a figure of
its own. 3D PhasePortraits cannot be panels either. Both raise
NotImplementedError; render them on their own.