Skip to content
mathtext

mathtext

Mojo module 🡭

mathtext

Mathematical labels: a small expression language for titles, axis captions, legend entries, tick labels and annotations (#371).

A label such as "$\sigma^2$" or "Rate $\frac{\Delta y}{\Delta x}$" is parsed here, laid out into positioned text runs, and handed to the same deferred-_TextRequest path every plain label takes. A label with no $ in it never enters this module: _needs_math() is a byte scan, and the plain path is byte-for-byte what it was before this existed.

Why the layout lives here and not in canvas

An expression is a tree of runs at different sizes and offsets, and laying it out needs exactly two things of a backend: measure a string, and draw a string at an anchor. measure_text and draw_text are on the DrawTarget trait, so one layout serves every backend, and the raster, SVG and PDF outputs put each run at the same anchor by construction rather than by three implementations agreeing. What a backend would have to add for this to move upstream – a math axis height, a superscript shift – are typographic conventions rather than font facts, and the numbers below are those conventions. Canvas already does the two things that are font facts: it shapes each run with kerning, and it pulls a glyph the chosen face lacks from another installed one, which is what makes ∑ and ∂ appear at all.

The subset

Math is delimited by $...$. Inside it:

  • Latin letters and lowercase Greek are italic, as variables; digits, operators and capital Greek are upright. \mathrm{...} forces upright text.
  • ^ and _ attach a superscript or subscript to the atom before them: x^2, x_i, x_i^2, e^{-t}.
  • \frac{num}{den} stacks a fraction with a rule at the math axis; \sqrt{x} draws the sign with a rule over its argument.
  • {...} groups. \, is a thin space. \$ is a literal dollar sign, inside or outside math.
  • Named symbols: the Greek alphabet (\alpha…\omega, \Gamma…\Omega) and the operators listed in _symbol().

A single $ with no partner is a literal (so "Cost $5" stays plain); three or more that cannot pair raise. An unknown \command, an unbalanced brace, or a ^/_ with nothing to attach to raise at render time naming the label and the position, rather than drawing something that looks almost right.

What is not here

No large operators with limits (\sum_i is a subscript, not a limit below), no matrices, no line breaks inside math, and a radical sign that does not grow with a tall argument. Kerning applies within a run, not across the boundary between a base and its script. Each run is anchored on a whole pixel, like every other label; on SVG the viewer’s font, not this layout, advances the pen between runs.