Margins
Pin the plot's inner offsets so charts align across grids and documents — and set the gutter between facet panels.
AI assisted, human approved — novem uses AI to review and keep our documentation up to date.
Note: the margins file is part of the early-access flat config tree. You can explore it interactively in the plot playground.
Margins live in one file directly under your plot's config:
By default every side is auto: novem measures your axis labels,
ticks and titles and computes the margin that fits them. An unsigned
value replaces that calculation exactly; a value prefixed with +
or - adjusts it. Exact margins are useful when charts must align
across a grid or document, and they double as the wrap budget for
wrapped category labels.
The keys are the m* family — the same prefix the axis grammar uses
for its offsets: m* moves things, p* pads scales, e: picks
edges.
ml:15px mr:45, mt:22
ml:60 -- later directives win
ml:5% mb:auto -- % of the svg dimension
ma:+5 -- add 5px to every auto margin
mb:-5 -- subtract 5px from auto bottom
ml:mr:mt:mb:are the left, right, top and bottom margins of the plot area.mx:my:ma:are side bundles, the same x/y reading the table's border and padding files use:mx:sets left+right,my:top+bottom,ma:all four. They are pure expansions — a later single-side directive overrides its half (mx:20 ml:60leaves right at 20).- An unsigned pixel (
pxsuffix optional) or%value is exact. Prefix it with+or-to adjust the measured value instead:ma:+5adds 5px to all sides, whilemb:-5subtracts 5px from the calculated bottom. Signed percentages adjust by that percentage of the corresponding svg dimension. - Whitespace and commas both separate directives; several fit on one
line; the last directive for a side wins; the value may be
attached (
ml:15) or the next token (ml: 15). autorestores the measured autocompute — a laterautoclears an earlier explicit value.--starts a comment, the same marker as every novem grammar.
When a plot is split into panels with
facets, px: and
py: set the gutters between them. Gutters are inner spacing,
so they take the padding letter, and they read the same way as every
other x/y in the platform: px: is the gap you cross moving
horizontally (between each column of panels), py: the gap
between each row:
px:12 py:8
pa: bundles both gutters, like ma: does for the sides. The
gutter is by definition the leftover space after each facet
carves out its label, axis and chart area. The side directives
describe the outer frame of the whole surface; between panels
there is no margin, only the gutter — a panel's exterior sides
inherit the frame, its interior sides get the gutter, so a stacked
price/volume layout comes out right with no configuration at all.
Negative gutters pull panels together (overlap allowed); auto
restores the theme default. Margin and gutter changes animate like
any other layout change.
A line leading with the shared slicer pair selects panels by their physical grid position — rows × columns, one slicer meaning columns, negatives counting from the end — and overrides those panels' margin boxes:
0 : mt:40 -- the first grid ROW
: -1 mr:0 -- the last grid COLUMN
-1 mb:20 -- one slicer = columns
Later lines win per side. Sides you don't override follow the
exterior/interior rule; auto on a scoped line removes that
override again.
Invalid directives are dropped, never fatal: the rest of the file still applies, and every dropped directive lands in the plot's diagnostics with its line number. The playground shows them inline.