Layout Utilities¶
Utilities for tightening layouts without juggling plt.subplots_adjust.
simple_layout optimizes margins with L-BFGS-B so axes fit inside a bounding
box; make_offset nudges text/legends in point units; label_axes adds
standardized panel labels; arrow_axis draws annotated bidirectional arrows;
and set_decimal/get_bounding_box provide quick helpers when formatting axes.
Example¶
import matplotlib.pyplot as plt
import numpy as np
import dartwork_mpl as dm
fig, axes = plt.subplots(1, 3, figsize=(dm.DW, dm.DW * 0.35))
for ax in axes:
ax.plot(np.linspace(0, 1, 40), np.random.rand(40), color='oc.blue6')
# Panel labels
dm.label_axes(axes) # adds a, b, c
# Layout optimization
dm.simple_layout(fig, margins=(0.08, 0.05, 0.1, 0.08))
# Decimal formatting
dm.set_decimal(axes[0], xn=2, yn=1)
# Arrow annotations
dm.arrow_axis(axes[1], 'x', 'Installation cost')
dm.arrow_axis(axes[2], 'y', 'Information richness')
API¶
Layout Functions¶
- dartwork_mpl.cm2in(cm: float) float[source]¶
Convert centimeters to inches.
- Parameters:
cm (float) – Value in centimeters.
- Returns:
Equivalent value in inches.
- Return type:
float
- dartwork_mpl.simple_layout(fig: Figure, gs: GridSpec | SubplotSpec | None = None, margins: tuple[float, float, float, float] = (0.1, 0.1, 0.08, 0.05), bbox: tuple[float, float, float, float] = (0, 1, 0, 1), verbose: bool = False, gtol: float = 0.01, bound_margin: float = 0.2, use_all_axes: bool = True, importance_weights: tuple[float, float, float, float] = (1, 1, 1, 1)) OptimizeResult[source]¶
Apply an optimized layout to a GridSpec for fine-tuned subplot positioning.
Uses the L-BFGS-B optimization algorithm to compute GridSpec parameters that best fit subplots within the specified margins and bounding box. Provides more consistent and predictable margin control than the built-in
tight_layout.- Parameters:
fig (Figure) – The Matplotlib Figure to apply the layout to.
gs (GridSpec | SubplotSpec | None, optional) – GridSpec or SubplotSpec to optimize. If None, defaults to the GridSpec of
fig.axes[0]. If a SubplotSpec is provided, its parent GridSpec will be used.margins (tuple[float, float, float, float], optional) – Margins in inches (left, right, bottom, top). Default is (0.15, 0.05, 0.05, 0.05).
bbox (tuple[float, float, float, float], optional) – Target region in figure-relative coordinates (left, right, bottom, top). Default (0, 1, 0, 1) covers the entire figure.
verbose (bool, optional) – Whether to print diagnostic logs during optimization. Default is False.
gtol (float, optional) – Gradient tolerance for L-BFGS-B optimization. Default is 1e-2.
bound_margin (float, optional) – Buffer margin for generating parameter bounds, controlling the optimization search space. Default is 0.2.
use_all_axes (bool, optional) – If True, uses all Axes in the Figure for bounding-box computation. If False, only Axes belonging to gs are considered. Default is True.
importance_weights (tuple[float, float, float, float], optional) – Weights (left, right, bottom, top) controlling the importance of matching each margin. Default is (1, 1, 1, 1).
- Returns:
The scipy optimization result object.
- Return type:
OptimizeResult
- dartwork_mpl.auto_layout(fig: Figure, *, padding: float | tuple[float, float, float, float] = 0.08, max_iter: int = 5, tolerance: float = 2.0, verbose: bool = False) None[source]¶
Content-aware layout that auto-adjusts margins to eliminate overflow.
Wraps
simple_layoutwith a Validate → Measure → Adjust → Retry loop. Starts with minimal margins, measures actual per-side overflow using text and tick-label bounding boxes, and increases margins only on overflowing sides. Converges in 1–3 iterations for typical charts; axes-relative annotations (which move with the subplot) may need more.- Parameters:
fig (Figure) – The Matplotlib Figure to lay out.
padding (float | tuple[float, float, float, float], optional) – Initial padding in inches for all four sides (left, right, bottom, top). If a single float, it is used for all sides. Default is 0.08.
max_iter (int, optional) – Maximum number of measure-and-adjust iterations. Default is 5.
tolerance (float, optional) – Overflow tolerance in pixels. Overflows below this threshold are ignored. Default is 2.0 px.
verbose (bool, optional) – If True, prints per-iteration diagnostics. Default is False.
Examples
>>> import dartwork_mpl as dm >>> fig, ax = plt.subplots() >>> ax.plot([1, 2, 3]) >>> ax.set_ylabel("Revenue ($M)") >>> dm.auto_layout(fig)
- dartwork_mpl.set_xmargin(ax: Axes, margin: float = 0.05, *, left: float | None = None, right: float | None = None) None[source]¶
Set responsive margins or fixed bounds on the x-axis limits.
Wraps
set_xlimto allow specifying a global margin ratio while optionally pinning one or both edges to fixed values.- Parameters:
ax (Axes) – The matplotlib Axes to modify.
margin (float, optional) – Fractional margin applied to both sides. Default is 0.05.
left (float | None, optional) – Fixed left bound for the x-axis. Overrides the margin on that side.
right (float | None, optional) – Fixed right bound for the x-axis. Overrides the margin on that side.
- dartwork_mpl.set_ymargin(ax: Axes, margin: float = 0.05, *, bottom: float | None = None, top: float | None = None) None[source]¶
Set responsive margins or fixed bounds on the y-axis limits.
Wraps
set_ylimto allow specifying a global margin ratio while optionally pinning one or both edges to fixed values.- Parameters:
ax (Axes) – The matplotlib Axes to modify.
margin (float, optional) – Fractional margin applied to both sides. Default is 0.05.
bottom (float | None, optional) – Fixed bottom bound for the y-axis. Overrides the margin on that side.
top (float | None, optional) – Fixed top bound for the y-axis. Overrides the margin on that side.
Annotation Functions¶
- dartwork_mpl.make_offset(x: float, y: float, fig: Figure) ScaledTranslation[source]¶
Create a translation offset transform for positioning figure elements.
- Parameters:
x (float) – Horizontal offset in points.
y (float) – Vertical offset in points.
fig (matplotlib.figure.Figure) – The Figure whose DPI scale is used.
- Returns:
A translation transform that can be added to other transforms.
- Return type:
matplotlib.transforms.ScaledTranslation
- dartwork_mpl.label_axes(axes: list[Axes] | ndarray, labels: list[str] | None = None, fontsize: float = 10, fontweight: str = 'bold', x: float | str = 'auto', y: float = 1.05, **kwargs) list[source]¶
Add standardized identification labels (a, b, c, …) to subplot panels.
Commonly used in academic papers and reports to annotate multiple panels of a figure, placing labels at the left edge or top corner of each Axes.
- Parameters:
axes (list[Axes] | np.ndarray) – List or array of Axes objects to label.
labels (list[str] | None, optional) – Custom text labels. If None, lowercase letters (a, b, c, …) are assigned automatically.
fontsize (float, optional) – Font size for the labels. Default is 10 points.
fontweight (str, optional) – Font weight for the labels. Default is “bold”.
x (float | str, optional) – Horizontal position in Axes-relative coordinates (may exceed 0.0–1.0). If “auto”, the optimal x position is determined based on whether a y-axis label is present (-0.18 or -0.02).
y (float, optional) – Vertical position in Axes-relative coordinates. Default is 1.05.
**kwargs – Additional text properties passed to
ax.text().
- Returns:
List of created Text objects.
- Return type:
list
- dartwork_mpl.arrow_axis(ax: Axes, direction: str, label: str, *, offset: float = -0.1, low: str = 'Low', high: str = 'High', fontsize: float | None = None, fontsize_label: float | None = None, pad: float = -0.005, weight: str = 'normal', color: str = 'black', arrow_kw: dict | None = None) None[source]¶
Draw a bidirectional Low–High arrow axis along the edge of a plot.
Produces a visual like
Low ◄── label ──► Highnear the spine exterior.- Parameters:
ax (Axes) – Target Axes object for the annotation.
direction ({'x', 'y'}) – “x”: insert a horizontal arrow axis below the x-axis spine. “y”: insert a vertical arrow axis to the left of the y-axis spine.
label (str) – Center label text placed at the midpoint of the axis.
offset (float, optional) – Offset from the spine in Axes-fraction units. Default is -0.10 (sufficiently outside to avoid overlap with tick labels).
low (str, optional) – Text for the low end (bottom/left) of the axis. Default is “Low”.
high (str, optional) – Text for the high end (top/right) of the axis. Default is “High”.
fontsize (float | None, optional) – Font size for the Low/High endpoint labels. Default is fs(-1).
fontsize_label (float | None, optional) – Font size for the center label. Default is fs(0).
pad (float, optional) – Fractional gap between text and arrowheads. Default is -0.005.
weight (str, optional) – Font weight applied to all text elements.
color (str, optional) – Color for both text and arrows. Default is “black”.
arrow_kw (dict | None, optional) – Override the arrowprops passed to the internal
ax.annotatecalls.
Utility Functions¶
- dartwork_mpl.layout.get_bounding_box(boxes: list) tuple[float, float, float, float][source]¶
Compute the minimum bounding box that encloses all given box regions.
- Parameters:
boxes (list) – List of box objects, each having at minimum p0 (bottom-left coordinate), width, and height attributes.
- Returns:
Overall bounding box as (min_x, min_y, bbox_width, bbox_height).
- Return type:
tuple[float, float, float, float]
- dartwork_mpl.set_decimal(ax: Axes, xn: int | None = None, yn: int | None = None) None[source]¶
Fix the number of decimal places displayed on tick labels.
- Parameters:
ax (matplotlib.axes.Axes) – The Axes to modify.
xn (int | None, optional) – Number of decimal places for x-axis tick labels. If None, the x-axis is left unchanged.
yn (int | None, optional) – Number of decimal places for y-axis tick labels. If None, the y-axis is left unchanged.